diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2017-06-12 23:29:44 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2017-06-12 23:29:53 -0400 |
commit | 78a030a441966d91bc7e932ef84da39c3ea7d970 (patch) | |
tree | 52b89450f9f11fa3f0b3b114218c3edac70cf82c /src/backend/executor/nodeModifyTable.c | |
parent | 791ef001c9fe980e32092227a72ec24a7d66fa3d (diff) | |
download | postgresql-78a030a441966d91bc7e932ef84da39c3ea7d970.tar.gz postgresql-78a030a441966d91bc7e932ef84da39c3ea7d970.zip |
Fix confusion about number of subplans in partitioned INSERT setup.
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
Diffstat (limited to 'src/backend/executor/nodeModifyTable.c')
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index bf26488c510..96fbfc96e8e 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -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); } |