@@ -1538,6 +1538,241 @@ SET ROLE root
15381538statement ok
15391539DROP TABLE force_check CASCADE;
15401540
1541+ # Test to make sure that the scan to enforce uniqueness is done without RLS policies.
1542+ subtest uniq
1543+
1544+ statement ok
1545+ CREATE TABLE uniq (rls_col TEXT, uniq_col INT8 UNIQUE);
1546+
1547+ statement ok
1548+ CREATE USER uniq_user;
1549+
1550+ statement ok
1551+ GRANT ALL ON uniq TO uniq_user;
1552+
1553+ statement ok
1554+ ALTER TABLE uniq OWNER TO uniq_user;
1555+
1556+ statement ok
1557+ SET ROLE uniq_user;
1558+
1559+ statement ok
1560+ ALTER TABLE uniq NO FORCE ROW LEVEL SECURITY, ENABLE ROW LEVEL SECURITY;
1561+
1562+ statement ok
1563+ CREATE POLICY access ON uniq USING (rls_col = 'cat');
1564+
1565+ statement ok
1566+ INSERT INTO uniq VALUES ('cat', 1), ('cat', 2), ('dog', 3), ('cat', 4), ('hamster', 5);
1567+
1568+ statement ok
1569+ ALTER TABLE uniq FORCE ROW LEVEL SECURITY;
1570+
1571+ statement error pq: duplicate key value violates unique constraint "uniq_uniq_col_key"\nDETAIL: Key \(uniq_col\)=\(3\) already exists.
1572+ INSERT INTO uniq VALUES ('cat', 3);
1573+
1574+ statement ok
1575+ INSERT INTO uniq VALUES ('cat', 6);
1576+
1577+ statement error pq: new row violates row-level security policy for table "uniq"
1578+ INSERT INTO uniq VALUES ('dog', 6);
1579+
1580+ statement error pq: duplicate key value violates unique constraint "uniq_uniq_col_key"\nDETAIL: Key \(uniq_col\)=\(5\) already exists.
1581+ UPDATE uniq SET uniq_col = 5 WHERE uniq_col = 1;
1582+
1583+ statement ok
1584+ UPDATE uniq SET uniq_col = 7 WHERE uniq_col = 1;
1585+
1586+ # Ensure that any attempts to update an invisible row will be a no-op
1587+ query TI
1588+ UPDATE uniq SET uniq_col = 8 WHERE uniq_col = 5 RETURNING rls_col, uniq_col;
1589+ ----
1590+
1591+ statement ok
1592+ ALTER TABLE uniq NO FORCE ROW LEVEL SECURITY;
1593+
1594+ query TI
1595+ select rls_col, uniq_col FROM uniq ORDER BY uniq_col;
1596+ ----
1597+ cat 2
1598+ dog 3
1599+ cat 4
1600+ hamster 5
1601+ cat 6
1602+ cat 7
1603+
1604+ statement ok
1605+ SET ROLE root;
1606+
1607+ statement ok
1608+ DROP TABLE uniq;
1609+
1610+ statement ok
1611+ DROP USER uniq_user;
1612+
1613+ # Test to make sure that the scan to enforce foreign keys is exempt from RLS policies.
1614+ subtest fk
1615+
1616+ statement ok
1617+ CREATE TABLE parent (key INT8 NOT NULL PRIMARY KEY);
1618+
1619+ statement ok
1620+ CREATE TABLE child (
1621+ rls_col TEXT,
1622+ key INT8 NOT NULL,
1623+ CONSTRAINT fk FOREIGN KEY (key) REFERENCES parent(key) ON DELETE CASCADE
1624+ );
1625+
1626+ statement ok
1627+ CREATE USER fk_user;
1628+
1629+ statement ok
1630+ GRANT ALL ON parent TO fk_user;
1631+
1632+ statement ok
1633+ GRANT ALL ON child TO fk_user;
1634+
1635+ statement ok
1636+ ALTER TABLE parent OWNER TO fk_user;
1637+
1638+ statement ok
1639+ ALTER TABLE child OWNER TO fk_user;
1640+
1641+ statement ok
1642+ SET ROLE fk_user;
1643+
1644+ statement ok
1645+ INSERT INTO parent SELECT * FROM generate_series(1,6);
1646+
1647+ statement ok
1648+ INSERT INTO child VALUES ('bedroom', 1), ('office', 2)
1649+
1650+ # Set RLS at the parent and ensure FK still enforced.
1651+ statement ok
1652+ ALTER TABLE parent ENABLE ROW LEVEL SECURITY, FORCE ROW LEVEL SECURITY;
1653+
1654+ statement error pq: insert on table "child" violates foreign key constraint "fk"
1655+ INSERT INTO child VALUES ('hall', 7);
1656+
1657+ statement ok
1658+ INSERT INTO child VALUES ('hall', 3);
1659+
1660+ # mimic the FK lookup to show that the given RLS policies will hide the value
1661+ query I
1662+ SELECT 1 FROM parent WHERE key = 3;
1663+ ----
1664+
1665+ query I
1666+ SELECT key FROM child ORDER BY key;
1667+ ----
1668+ 1
1669+ 2
1670+ 3
1671+
1672+ # Set RLS at the child and ensure FK still enforced
1673+ statement ok
1674+ ALTER TABLE child ENABLE ROW LEVEL SECURITY, FORCE ROW LEVEL SECURITY;
1675+
1676+ statement ok
1677+ CREATE POLICY ins1 ON child FOR INSERT WITH CHECK (rls_col = 'bedroom');
1678+
1679+ statement error pq: insert on table "child" violates foreign key constraint "fk"
1680+ INSERT INTO child VALUES ('bedroom', 7);
1681+
1682+ statement error pq: new row violates row-level security policy for table "child"
1683+ INSERT INTO child VALUES ('deck', 7);
1684+
1685+ statement ok
1686+ INSERT INTO child VALUES ('bedroom', 4);
1687+
1688+ # Disable RLS at the parent so that we can do a delete and have it cascade down
1689+ statement ok
1690+ ALTER TABLE parent NO FORCE ROW LEVEL SECURITY;
1691+
1692+ statement ok
1693+ DELETE FROM parent WHERE key = 1;
1694+
1695+ statement ok
1696+ CREATE POLICY sel1 ON child FOR SELECT USING (true);
1697+
1698+ query I
1699+ SELECT key FROM child ORDER BY key;
1700+ ----
1701+ 2
1702+ 3
1703+ 4
1704+
1705+ statement ok
1706+ SET ROLE root
1707+
1708+ statement ok
1709+ DROP TABLE child;
1710+
1711+ statement ok
1712+ DROP TABLE parent;
1713+
1714+ statement ok
1715+ DROP USER fk_user;
1716+
1717+ # Ensure CHECK constraints can work alongside RLS policies
1718+ subtest check_constraint
1719+
1720+ statement ok
1721+ CREATE TABLE rgb_only (col text, check (col = 'red' or col = 'green' or col = 'blue'));
1722+
1723+ statement ok
1724+ CREATE USER rgb_only_user;
1725+
1726+ statement ok
1727+ ALTER TABLE rgb_only OWNER TO rgb_only_user;
1728+
1729+ statement ok
1730+ SET ROLE rgb_only_user;
1731+
1732+ statement ok
1733+ ALTER TABLE rgb_only ENABLE ROW LEVEL SECURITY, FORCE ROW LEVEL SECURITY;
1734+
1735+ statement ok
1736+ CREATE POLICY p_sel ON rgb_only FOR SELECT USING (true);
1737+
1738+ statement ok
1739+ CREATE POLICY p_subset ON rgb_only FOR INSERT WITH CHECK (col = 'red' or col = 'brown');
1740+
1741+ statement ok
1742+ INSERT INTO rgb_only VALUES ('red')
1743+
1744+ # Allowed by policy, reject by CHECK constraint
1745+ statement error pq: failed to satisfy CHECK constraint \(\(\(col = 'red':::STRING\) OR \(col = 'green':::STRING\)\) OR \(col = 'blue':::STRING\)\)
1746+ INSERT INTO rgb_only VALUES ('brown')
1747+
1748+ # Disallowed by policy, accepted by CHECK constraint
1749+ statement error pq: new row violates row-level security policy for table "rgb_only"
1750+ INSERT INTO rgb_only VALUES ('green')
1751+
1752+ statement ok
1753+ DROP POLICY p_subset ON rgb_only;
1754+
1755+ statement ok
1756+ CREATE POLICY p_disjoint ON rgb_only FOR INSERT WITH CHECK (col = 'black');
1757+
1758+ # Disallowed by both.
1759+ statement error pq: new row violates row-level security policy for table "rgb_only"
1760+ INSERT INTO rgb_only VALUES ('blue')
1761+
1762+ query T
1763+ SELECT col FROM rgb_only ORDER BY col;
1764+ ----
1765+ red
1766+
1767+ statement ok
1768+ SET ROLE root;
1769+
1770+ statement ok
1771+ DROP TABLE rgb_only;
1772+
1773+ statement ok
1774+ DROP USER rgb_only_user;
1775+
15411776subtest truncate
15421777
15431778statement ok
0 commit comments