@@ -1457,6 +1457,241 @@ SET ROLE root
1457
1457
statement ok
1458
1458
DROP TABLE force_check CASCADE;
1459
1459
1460
+ # Test to make sure that the scan to enforce uniqueness is done without RLS policies.
1461
+ subtest uniq
1462
+
1463
+ statement ok
1464
+ CREATE TABLE uniq (rls_col TEXT, uniq_col INT8 UNIQUE);
1465
+
1466
+ statement ok
1467
+ CREATE USER uniq_user;
1468
+
1469
+ statement ok
1470
+ GRANT ALL ON uniq TO uniq_user;
1471
+
1472
+ statement ok
1473
+ ALTER TABLE uniq OWNER TO uniq_user;
1474
+
1475
+ statement ok
1476
+ SET ROLE uniq_user;
1477
+
1478
+ statement ok
1479
+ ALTER TABLE uniq NO FORCE ROW LEVEL SECURITY, ENABLE ROW LEVEL SECURITY;
1480
+
1481
+ statement ok
1482
+ CREATE POLICY access ON uniq USING (rls_col = 'cat');
1483
+
1484
+ statement ok
1485
+ INSERT INTO uniq VALUES ('cat', 1), ('cat', 2), ('dog', 3), ('cat', 4), ('hamster', 5);
1486
+
1487
+ statement ok
1488
+ ALTER TABLE uniq FORCE ROW LEVEL SECURITY;
1489
+
1490
+ statement error pq: duplicate key value violates unique constraint "uniq_uniq_col_key"\nDETAIL: Key \(uniq_col\)=\(3\) already exists.
1491
+ INSERT INTO uniq VALUES ('cat', 3);
1492
+
1493
+ statement ok
1494
+ INSERT INTO uniq VALUES ('cat', 6);
1495
+
1496
+ statement error pq: new row violates row-level security policy for table "uniq"
1497
+ INSERT INTO uniq VALUES ('dog', 6);
1498
+
1499
+ statement error pq: duplicate key value violates unique constraint "uniq_uniq_col_key"\nDETAIL: Key \(uniq_col\)=\(5\) already exists.
1500
+ UPDATE uniq SET uniq_col = 5 WHERE uniq_col = 1;
1501
+
1502
+ statement ok
1503
+ UPDATE uniq SET uniq_col = 7 WHERE uniq_col = 1;
1504
+
1505
+ # Ensure that any attempts to update an invisible row will be a no-op
1506
+ query TI
1507
+ UPDATE uniq SET uniq_col = 8 WHERE uniq_col = 5 RETURNING rls_col, uniq_col;
1508
+ ----
1509
+
1510
+ statement ok
1511
+ ALTER TABLE uniq NO FORCE ROW LEVEL SECURITY;
1512
+
1513
+ query TI
1514
+ select rls_col, uniq_col FROM uniq ORDER BY uniq_col;
1515
+ ----
1516
+ cat 2
1517
+ dog 3
1518
+ cat 4
1519
+ hamster 5
1520
+ cat 6
1521
+ cat 7
1522
+
1523
+ statement ok
1524
+ SET ROLE root;
1525
+
1526
+ statement ok
1527
+ DROP TABLE uniq;
1528
+
1529
+ statement ok
1530
+ DROP USER uniq_user;
1531
+
1532
+ # Test to make sure that the scan to enforce foreign keys is exempt from RLS policies.
1533
+ subtest fk
1534
+
1535
+ statement ok
1536
+ CREATE TABLE parent (key INT8 NOT NULL PRIMARY KEY);
1537
+
1538
+ statement ok
1539
+ CREATE TABLE child (
1540
+ rls_col TEXT,
1541
+ key INT8 NOT NULL,
1542
+ CONSTRAINT fk FOREIGN KEY (key) REFERENCES parent(key) ON DELETE CASCADE
1543
+ );
1544
+
1545
+ statement ok
1546
+ CREATE USER fk_user;
1547
+
1548
+ statement ok
1549
+ GRANT ALL ON parent TO fk_user;
1550
+
1551
+ statement ok
1552
+ GRANT ALL ON child TO fk_user;
1553
+
1554
+ statement ok
1555
+ ALTER TABLE parent OWNER TO fk_user;
1556
+
1557
+ statement ok
1558
+ ALTER TABLE child OWNER TO fk_user;
1559
+
1560
+ statement ok
1561
+ SET ROLE fk_user;
1562
+
1563
+ statement ok
1564
+ INSERT INTO parent SELECT * FROM generate_series(1,6);
1565
+
1566
+ statement ok
1567
+ INSERT INTO child VALUES ('bedroom', 1), ('office', 2)
1568
+
1569
+ # Set RLS at the parent and ensure FK still enforced.
1570
+ statement ok
1571
+ ALTER TABLE parent ENABLE ROW LEVEL SECURITY, FORCE ROW LEVEL SECURITY;
1572
+
1573
+ statement error pq: insert on table "child" violates foreign key constraint "fk"
1574
+ INSERT INTO child VALUES ('hall', 7);
1575
+
1576
+ statement ok
1577
+ INSERT INTO child VALUES ('hall', 3);
1578
+
1579
+ # mimic the FK lookup to show that the given RLS policies will hide the value
1580
+ query I
1581
+ SELECT 1 FROM parent WHERE key = 3;
1582
+ ----
1583
+
1584
+ query I
1585
+ SELECT key FROM child ORDER BY key;
1586
+ ----
1587
+ 1
1588
+ 2
1589
+ 3
1590
+
1591
+ # Set RLS at the child and ensure FK still enforced
1592
+ statement ok
1593
+ ALTER TABLE child ENABLE ROW LEVEL SECURITY, FORCE ROW LEVEL SECURITY;
1594
+
1595
+ statement ok
1596
+ CREATE POLICY ins1 ON child FOR INSERT WITH CHECK (rls_col = 'bedroom');
1597
+
1598
+ statement error pq: insert on table "child" violates foreign key constraint "fk"
1599
+ INSERT INTO child VALUES ('bedroom', 7);
1600
+
1601
+ statement error pq: new row violates row-level security policy for table "child"
1602
+ INSERT INTO child VALUES ('deck', 7);
1603
+
1604
+ statement ok
1605
+ INSERT INTO child VALUES ('bedroom', 4);
1606
+
1607
+ # Disable RLS at the parent so that we can do a delete and have it cascade down
1608
+ statement ok
1609
+ ALTER TABLE parent NO FORCE ROW LEVEL SECURITY;
1610
+
1611
+ statement ok
1612
+ DELETE FROM parent WHERE key = 1;
1613
+
1614
+ statement ok
1615
+ CREATE POLICY sel1 ON child FOR SELECT USING (true);
1616
+
1617
+ query I
1618
+ SELECT key FROM child ORDER BY key;
1619
+ ----
1620
+ 2
1621
+ 3
1622
+ 4
1623
+
1624
+ statement ok
1625
+ SET ROLE root
1626
+
1627
+ statement ok
1628
+ DROP TABLE child;
1629
+
1630
+ statement ok
1631
+ DROP TABLE parent;
1632
+
1633
+ statement ok
1634
+ DROP USER fk_user;
1635
+
1636
+ # Ensure CHECK constraints can work alongside RLS policies
1637
+ subtest check_constraint
1638
+
1639
+ statement ok
1640
+ CREATE TABLE rgb_only (col text, check (col = 'red' or col = 'green' or col = 'blue'));
1641
+
1642
+ statement ok
1643
+ CREATE USER rgb_only_user;
1644
+
1645
+ statement ok
1646
+ ALTER TABLE rgb_only OWNER TO rgb_only_user;
1647
+
1648
+ statement ok
1649
+ SET ROLE rgb_only_user;
1650
+
1651
+ statement ok
1652
+ ALTER TABLE rgb_only ENABLE ROW LEVEL SECURITY, FORCE ROW LEVEL SECURITY;
1653
+
1654
+ statement ok
1655
+ CREATE POLICY p_sel ON rgb_only FOR SELECT USING (true);
1656
+
1657
+ statement ok
1658
+ CREATE POLICY p_subset ON rgb_only FOR INSERT WITH CHECK (col = 'red' or col = 'brown');
1659
+
1660
+ statement ok
1661
+ INSERT INTO rgb_only VALUES ('red')
1662
+
1663
+ # Allowed by policy, reject by CHECK constraint
1664
+ statement error pq: failed to satisfy CHECK constraint \(\(\(col = 'red':::STRING\) OR \(col = 'green':::STRING\)\) OR \(col = 'blue':::STRING\)\)
1665
+ INSERT INTO rgb_only VALUES ('brown')
1666
+
1667
+ # Disallowed by policy, accepted by CHECK constraint
1668
+ statement error pq: new row violates row-level security policy for table "rgb_only"
1669
+ INSERT INTO rgb_only VALUES ('green')
1670
+
1671
+ statement ok
1672
+ DROP POLICY p_subset ON rgb_only;
1673
+
1674
+ statement ok
1675
+ CREATE POLICY p_disjoint ON rgb_only FOR INSERT WITH CHECK (col = 'black');
1676
+
1677
+ # Disallowed by both.
1678
+ statement error pq: new row violates row-level security policy for table "rgb_only"
1679
+ INSERT INTO rgb_only VALUES ('blue')
1680
+
1681
+ query T
1682
+ SELECT col FROM rgb_only ORDER BY col;
1683
+ ----
1684
+ red
1685
+
1686
+ statement ok
1687
+ SET ROLE root;
1688
+
1689
+ statement ok
1690
+ DROP TABLE rgb_only;
1691
+
1692
+ statement ok
1693
+ DROP USER rgb_only_user;
1694
+
1460
1695
subtest truncate
1461
1696
1462
1697
statement ok
0 commit comments