]> granicus.if.org Git - postgresql/commitdiff
Fix confusion about number of subplans in partitioned INSERT setup.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 13 Jun 2017 03:29:44 +0000 (23:29 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 13 Jun 2017 03:29:53 +0000 (23:29 -0400)
ExecInitModifyTable() thought there was a plan per partition, but no,
there's only one.  The problem had escaped detection so far because there
would only be visible misbehavior if there were a SubPlan (not an InitPlan)
in the quals being duplicated for each partition.  However, valgrind
detected a bogus memory access in test cases added by commit 4f7a95be2,
and investigation of that led to discovery of the bug.  The additional
test case added here crashes without the patch.

Patch by Amit Langote, test case by me.

Discussion: https://postgr.es/m/10974.1497227727@sss.pgh.pa.us

src/backend/executor/nodeModifyTable.c
src/test/regress/expected/rowsecurity.out
src/test/regress/sql/rowsecurity.sql

index bf26488c5103358b785d55445dc8596fc40d955f..96fbfc96e8e489ac12dd5923071409c634c54af0 100644 (file)
@@ -1841,10 +1841,21 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
        if (node->withCheckOptionLists != NIL && mtstate->mt_num_partitions > 0)
        {
                List       *wcoList;
+               PlanState  *plan;
 
-               Assert(operation == CMD_INSERT);
-               resultRelInfo = mtstate->mt_partitions;
+               /*
+                * In case of INSERT on partitioned tables, there is only one plan.
+                * Likewise, there is only one WITH CHECK OPTIONS list, not one per
+                * partition.  We make a copy of the WCO qual for each partition; note
+                * that, if there are SubPlans in there, they all end up attached to
+                * the one parent Plan node.
+                */
+               Assert(operation == CMD_INSERT &&
+                          list_length(node->withCheckOptionLists) == 1 &&
+                          mtstate->mt_nplans == 1);
                wcoList = linitial(node->withCheckOptionLists);
+               plan = mtstate->mt_plans[0];
+               resultRelInfo = mtstate->mt_partitions;
                for (i = 0; i < mtstate->mt_num_partitions; i++)
                {
                        Relation        partrel = resultRelInfo->ri_RelationDesc;
@@ -1858,9 +1869,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                                                                                                         partrel, rel);
                        foreach(ll, mapped_wcoList)
                        {
-                               WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
-                               ExprState  *wcoExpr = ExecInitQual((List *) wco->qual,
-                                                                                                  mtstate->mt_plans[i]);
+                               WithCheckOption *wco = castNode(WithCheckOption, lfirst(ll));
+                               ExprState  *wcoExpr = ExecInitQual(castNode(List, wco->qual),
+                                                                                                  plan);
 
                                wcoExprs = lappend(wcoExprs, wcoExpr);
                        }
index d382a9f4cc101f43283e3e2b40c3ccffb024bd7e..e2ec961ad9c1045119ccc42bfb2e80c3d0ed26c1 100644 (file)
@@ -1327,6 +1327,14 @@ SELECT * FROM part_document ORDER by did;
 ERROR:  query would be affected by row-level security policy for table "part_document"
 SELECT * FROM part_document_satire ORDER by did;
 ERROR:  query would be affected by row-level security policy for table "part_document_satire"
+-- Check behavior with a policy that uses a SubPlan not an InitPlan.
+SET SESSION AUTHORIZATION regress_rls_alice;
+SET row_security TO ON;
+CREATE POLICY pp3 ON part_document AS RESTRICTIVE
+    USING ((SELECT dlevel <= seclv FROM uaccount WHERE pguser = current_user));
+SET SESSION AUTHORIZATION regress_rls_carol;
+INSERT INTO part_document VALUES (100, 11, 5, 'regress_rls_carol', 'testing pp3'); -- fail
+ERROR:  new row violates row-level security policy "pp3" for table "part_document"
 ----- Dependencies -----
 SET SESSION AUTHORIZATION regress_rls_alice;
 SET row_security TO ON;
index 80537ffcac76152a98378129e5a5b8587ad77a5c..3ce929320a2e19ec5d249edb2fed7c81d4506f22 100644 (file)
@@ -450,6 +450,15 @@ SET row_security TO OFF;
 SELECT * FROM part_document ORDER by did;
 SELECT * FROM part_document_satire ORDER by did;
 
+-- Check behavior with a policy that uses a SubPlan not an InitPlan.
+SET SESSION AUTHORIZATION regress_rls_alice;
+SET row_security TO ON;
+CREATE POLICY pp3 ON part_document AS RESTRICTIVE
+    USING ((SELECT dlevel <= seclv FROM uaccount WHERE pguser = current_user));
+
+SET SESSION AUTHORIZATION regress_rls_carol;
+INSERT INTO part_document VALUES (100, 11, 5, 'regress_rls_carol', 'testing pp3'); -- fail
+
 ----- Dependencies -----
 SET SESSION AUTHORIZATION regress_rls_alice;
 SET row_security TO ON;