Skip to content

Commit 0d3b49d

Browse files
committed
Fix Assert failure for MERGE into a partitioned table with RLS.
In ExecInitPartitionInfo(), the Assert when building the WITH CHECK OPTION list for the new partition assumed that the command would be an INSERT or UPDATE, but it can also be a MERGE. This can be triggered by a MERGE into a partitioned table with RLS checks to enforce. Fix, and back-patch to v15, where MERGE was introduced. Discussion: https://postgr.es/m/CAEZATCWWFtQmW67F3XTyMU5Am10Oxa_b8oe0x%2BNu5Mo%2BCdRErg%40mail.gmail.com
1 parent 83a611a commit 0d3b49d

File tree

3 files changed

+31
-3
lines changed

3 files changed

+31
-3
lines changed

src/backend/executor/execPartition.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -545,8 +545,8 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
545545
* Build WITH CHECK OPTION constraints for the partition. Note that we
546546
* didn't build the withCheckOptionList for partitions within the planner,
547547
* but simple translation of varattnos will suffice. This only occurs for
548-
* the INSERT case or in the case of UPDATE tuple routing where we didn't
549-
* find a result rel to reuse.
548+
* the INSERT case or in the case of UPDATE/MERGE tuple routing where we
549+
* didn't find a result rel to reuse.
550550
*/
551551
if (node && node->withCheckOptionLists != NIL)
552552
{
@@ -557,12 +557,15 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
557557
/*
558558
* In the case of INSERT on a partitioned table, there is only one
559559
* plan. Likewise, there is only one WCO list, not one per partition.
560-
* For UPDATE, there are as many WCO lists as there are plans.
560+
* For UPDATE/MERGE, there are as many WCO lists as there are plans.
561561
*/
562562
Assert((node->operation == CMD_INSERT &&
563563
list_length(node->withCheckOptionLists) == 1 &&
564564
list_length(node->resultRelations) == 1) ||
565565
(node->operation == CMD_UPDATE &&
566+
list_length(node->withCheckOptionLists) ==
567+
list_length(node->resultRelations)) ||
568+
(node->operation == CMD_MERGE &&
566569
list_length(node->withCheckOptionLists) ==
567570
list_length(node->resultRelations)));
568571

@@ -619,6 +622,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
619622
List *returningList;
620623

621624
/* See the comment above for WCO lists. */
625+
/* (except no RETURNING support for MERGE yet) */
622626
Assert((node->operation == CMD_INSERT &&
623627
list_length(node->returningLists) == 1 &&
624628
list_length(node->resultRelations) == 1) ||

src/test/regress/expected/merge.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,18 @@ SELECT * FROM pa_target ORDER BY tid;
17361736
14 | 140 | inserted by merge
17371737
(14 rows)
17381738

1739+
ROLLBACK;
1740+
-- test RLS enforcement
1741+
BEGIN;
1742+
ALTER TABLE pa_target ENABLE ROW LEVEL SECURITY;
1743+
ALTER TABLE pa_target FORCE ROW LEVEL SECURITY;
1744+
CREATE POLICY pa_target_pol ON pa_target USING (tid != 0);
1745+
MERGE INTO pa_target t
1746+
USING pa_source s
1747+
ON t.tid = s.sid AND t.tid IN (1,2,3,4)
1748+
WHEN MATCHED THEN
1749+
UPDATE SET tid = tid - 1;
1750+
ERROR: new row violates row-level security policy for table "pa_target"
17391751
ROLLBACK;
17401752
DROP TABLE pa_source;
17411753
DROP TABLE pa_target CASCADE;

src/test/regress/sql/merge.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,6 +1082,18 @@ MERGE INTO pa_target t
10821082
SELECT * FROM pa_target ORDER BY tid;
10831083
ROLLBACK;
10841084

1085+
-- test RLS enforcement
1086+
BEGIN;
1087+
ALTER TABLE pa_target ENABLE ROW LEVEL SECURITY;
1088+
ALTER TABLE pa_target FORCE ROW LEVEL SECURITY;
1089+
CREATE POLICY pa_target_pol ON pa_target USING (tid != 0);
1090+
MERGE INTO pa_target t
1091+
USING pa_source s
1092+
ON t.tid = s.sid AND t.tid IN (1,2,3,4)
1093+
WHEN MATCHED THEN
1094+
UPDATE SET tid = tid - 1;
1095+
ROLLBACK;
1096+
10851097
DROP TABLE pa_source;
10861098
DROP TABLE pa_target CASCADE;
10871099

0 commit comments

Comments
 (0)