On 2017/06/12 11:51, Tom Lane wrote:
> Amit Langote <langote_amit...@lab.ntt.co.jp> writes:
>> On 2017/06/12 11:09, Joe Conway wrote:
>>> On 06/11/2017 05:35 PM, Tom Lane wrote:
>>>> First guess is that map_partition_varattnos has forgotten to handle
>>>> WithCheckOption.qual.
> 
>>> Drat. I'll take a look, but it would probably be good if someone
>>> generally familiar with the partitioned tables patches have a look as well.
> 
>> I am looking too.  Commit 587cda35ca3 which added that code did add a test
>> in updatable_views.sql, but tests added by this commit have perhaps
>> exposed something not previously covered.
> 
> My first guess above is wrong -- the undefined reference is actually
> "mtstate->mt_plans[i]".  This is because mtstate->mt_num_partitions is
> more than mtstate->mt_nplans in the failing case, so that the blithe
> assumption that we can use the partition number to index into
> mtstate->mt_plans is certainly wrong.

Yes, the code should never access mtstate->mt_plans[i] for i > 0, because
in this case (the INSERT case), there is only one plan.  Unlike
UPDATE/DELETE cases, we don't build plans for every partition in the
INSERT case.

> Don't know how this should
> be corrected, offhand, but do we really have more than one plan
> for a partitioned query?

There can't be, as mentioned, in the INSERT case.

How about something like the attached? The patch makes
mtstate->mt_plans[0] to be passed for all invocations of ExecInitQual() on
WithCheckOption.qual that is being initialized for each partition.  Note
that we are passing a PlanState that's based on the root parent table's
properties to initialize WITH CHECK OPTION quals to be checked against
rows that will be inserted into partitions (that is, after tuple-routing).

I tried to come up with a test that would cause the existing (unpatched)
code to crash, but couldn't.  How would one define a policy or WITH CHECK
OPTIONS view or something else, such that ExecInitQual() called on
WithCheckOptions.qual would try to access parent planstate and would crash
once parent becomes an invalid pointer (mtstate->mt_plans[i] for i > 0)?
After looking at the code downstream to ExecInitQual(), it seems that the
following cases would cases would cause parent planstate to be accessed:

* Qual references a whole row var
* Qual references an Aggref or a GroupingFunc or a WindowFunc
* Qual references a (Alternative) SubPlan

Thanks,
Amit
From 90fdad27c04db70f78c24e4999cd3aef7c06d1f7 Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Mon, 12 Jun 2017 14:35:05 +0900
Subject: [PATCH] Don't pass invalid PlanState pointer to ExecInitQual

Current code in ExecInitModifyTable that initializes
WithCheckOption.qual failed to consider that there *isn't* one
plan per partition in the ModifyTableState.mt_plans[] array.
---
 src/backend/executor/nodeModifyTable.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/backend/executor/nodeModifyTable.c 
b/src/backend/executor/nodeModifyTable.c
index bf26488c51..89991e34ae 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1841,8 +1841,17 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
        if (node->withCheckOptionLists != NIL && mtstate->mt_num_partitions > 0)
        {
                List       *wcoList;
+               PlanState  *plan;
 
-               Assert(operation == CMD_INSERT);
+               /*
+                * In case of INSERT on partitioned tables, there is only plan; 
in the
+                * planner we don't build one for each partition.  Likewise, 
there is
+                * only one WITH CHECK OPTIONS list, not one per partition.
+                */
+               Assert(operation == CMD_INSERT &&
+                          list_length(node->withCheckOptionLists) == 1 &&
+                          mtstate->mt_nplans == 1);
+               plan = mtstate->mt_plans[0];    /* The only plan */
                resultRelInfo = mtstate->mt_partitions;
                wcoList = linitial(node->withCheckOptionLists);
                for (i = 0; i < mtstate->mt_num_partitions; i++)
@@ -1858,10 +1867,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((List *) 
wco->qual, plan);
                                wcoExprs = lappend(wcoExprs, wcoExpr);
                        }
 
-- 
2.11.0

-- 
Sent via pgsql-committers mailing list (pgsql-committers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-committers

Reply via email to