0001-Initialize-WITH-CHECK-OPTIONS-and-RETURNING-expressi.patch
application/octet-stream
Filename: 0001-Initialize-WITH-CHECK-OPTIONS-and-RETURNING-expressi.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch 0001
Subject: Initialize WITH CHECK OPTIONS and RETURNING expressions on demand
| File | + | − |
|---|---|---|
| src/backend/executor/execMain.c | 18 | 1 |
| src/backend/executor/execPartition.c | 6 | 27 |
| src/backend/executor/nodeModifyTable.c | 120 | 90 |
| src/include/executor/executor.h | 2 | 1 |
| src/test/regress/expected/updatable_views.out | 6 | 12 |
From c6456053de33fd43f9389ab056a0e67670be2f43 Mon Sep 17 00:00:00 2001
From: amitlan <amitlangote09@gmail.com>
Date: Fri, 9 Apr 2021 15:23:56 +0900
Subject: [PATCH] Initialize WITH CHECK OPTIONS and RETURNING expressions on
demand
---
src/backend/executor/execMain.c | 19 +-
src/backend/executor/execPartition.c | 33 +--
src/backend/executor/nodeModifyTable.c | 210 ++++++++++--------
src/include/executor/executor.h | 3 +-
src/test/regress/expected/updatable_views.out | 18 +-
5 files changed, 152 insertions(+), 131 deletions(-)
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index b2e2df8773..fca60736f0 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1950,7 +1950,8 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
*/
void
ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
- TupleTableSlot *slot, EState *estate)
+ TupleTableSlot *slot, EState *estate,
+ PlanState *parent)
{
Relation rel = resultRelInfo->ri_RelationDesc;
TupleDesc tupdesc = RelationGetDescr(rel);
@@ -1958,6 +1959,22 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
ListCell *l1,
*l2;
+ /* Initialize the quals if not already done. */
+ if (resultRelInfo->ri_WithCheckOptionExprs == NIL)
+ {
+ List *wcoExprs = NIL;
+
+ foreach(l1, resultRelInfo->ri_WithCheckOptions)
+ {
+ WithCheckOption *wco = (WithCheckOption *) lfirst(l1);
+ ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
+ parent);
+
+ wcoExprs = lappend(wcoExprs, wcoExpr);
+ }
+ resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
+ }
+
/*
* We will use the EState's per-tuple context for evaluating constraint
* expressions (creating it if it's not already there).
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 99780ebb96..7dccc55006 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -543,8 +543,6 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
if (node && node->withCheckOptionLists != NIL)
{
List *wcoList;
- List *wcoExprs = NIL;
- ListCell *ll;
/*
* In the case of INSERT on a partitioned table, there is only one
@@ -582,18 +580,11 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
RelationGetForm(partrel)->reltype,
&found_whole_row);
/* We ignore the value of found_whole_row. */
-
- foreach(ll, wcoList)
- {
- WithCheckOption *wco = castNode(WithCheckOption, lfirst(ll));
- ExprState *wcoExpr = ExecInitQual(castNode(List, wco->qual),
- &mtstate->ps);
-
- wcoExprs = lappend(wcoExprs, wcoExpr);
- }
-
leaf_part_rri->ri_WithCheckOptions = wcoList;
- leaf_part_rri->ri_WithCheckOptionExprs = wcoExprs;
+ /*
+ * ri_WithCheckOptionExprs is built the first time it needs to be
+ * used (see ExecWithCheckOptions()).
+ */
}
/*
@@ -605,8 +596,6 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
*/
if (node && node->returningLists != NIL)
{
- TupleTableSlot *slot;
- ExprContext *econtext;
List *returningList;
/* See the comment above for WCO lists. */
@@ -641,20 +630,10 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
/* We ignore the value of found_whole_row. */
leaf_part_rri->ri_returningList = returningList;
-
/*
- * Initialize the projection itself.
- *
- * Use the slot and the expression context that would have been set up
- * in ExecInitModifyTable() for projection's output.
+ * ri_projectReturning is built the first time it needs to be
+ * used (see ExecProcessReturning()).
*/
- Assert(mtstate->ps.ps_ResultTupleSlot != NULL);
- slot = mtstate->ps.ps_ResultTupleSlot;
- Assert(mtstate->ps.ps_ExprContext != NULL);
- econtext = mtstate->ps.ps_ExprContext;
- leaf_part_rri->ri_projectReturning =
- ExecBuildProjectionInfo(returningList, econtext, slot,
- &mtstate->ps, RelationGetDescr(partrel));
}
/* Set up information needed for routing tuples to the partition. */
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index c5a2a9a054..dba9f684a5 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -154,12 +154,37 @@ ExecCheckPlanOutput(Relation resultRel, List *targetList)
errdetail("Query has too few columns.")));
}
+/* Initializes the RETURNING projection for given result relation. */
+static void
+ExecInitReturningProjection(ResultRelInfo *resultRelInfo,
+ ModifyTableState *mtstate)
+{
+ TupleTableSlot *slot;
+ ExprContext *econtext;
+
+ /* should not get called twice */
+ Assert(resultRelInfo->ri_projectReturning == NULL);
+
+ /* ExecInitModifyTable() should've initialized these. */
+ Assert(mtstate->ps.ps_ExprContext != NULL);
+ econtext = mtstate->ps.ps_ExprContext;
+ Assert(mtstate->ps.ps_ResultTupleSlot != NULL);
+ slot = mtstate->ps.ps_ResultTupleSlot;
+
+ Assert(resultRelInfo->ri_returningList != NIL);
+ resultRelInfo->ri_projectReturning =
+ ExecBuildProjectionInfo(resultRelInfo->ri_returningList,
+ econtext, slot, &mtstate->ps,
+ resultRelInfo->ri_RelationDesc->rd_att);
+}
+
/*
* ExecProcessReturning --- evaluate a RETURNING list
*
* resultRelInfo: current result rel
* tupleSlot: slot holding tuple actually inserted/updated/deleted
* planSlot: slot holding tuple returned by top subplan node
+ * mtstate: query's plan state
*
* Note: If tupleSlot is NULL, the FDW should have already provided econtext's
* scan tuple.
@@ -169,10 +194,18 @@ ExecCheckPlanOutput(Relation resultRel, List *targetList)
static TupleTableSlot *
ExecProcessReturning(ResultRelInfo *resultRelInfo,
TupleTableSlot *tupleSlot,
- TupleTableSlot *planSlot)
+ TupleTableSlot *planSlot,
+ ModifyTableState *mtstate)
{
- ProjectionInfo *projectReturning = resultRelInfo->ri_projectReturning;
- ExprContext *econtext = projectReturning->pi_exprContext;
+ ProjectionInfo *projectReturning;
+ ExprContext *econtext;
+
+ /* Initialize the projection if not already done. */
+ if (resultRelInfo->ri_projectReturning == NULL)
+ ExecInitReturningProjection(resultRelInfo, mtstate);
+
+ projectReturning = resultRelInfo->ri_projectReturning;
+ econtext = projectReturning->pi_exprContext;
/* Make tuple and any needed join variables available to ExecProject */
if (tupleSlot)
@@ -767,7 +800,8 @@ ExecInsert(ModifyTableState *mtstate,
* we are looking for at this point.
*/
if (resultRelInfo->ri_WithCheckOptions != NIL)
- ExecWithCheckOptions(wco_kind, resultRelInfo, slot, estate);
+ ExecWithCheckOptions(wco_kind, resultRelInfo, slot, estate,
+ &mtstate->ps);
/*
* Check the constraints of the tuple.
@@ -962,11 +996,12 @@ ExecInsert(ModifyTableState *mtstate,
* are looking for at this point.
*/
if (resultRelInfo->ri_WithCheckOptions != NIL)
- ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
+ ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate,
+ &mtstate->ps);
/* Process RETURNING if present */
- if (resultRelInfo->ri_projectReturning)
- result = ExecProcessReturning(resultRelInfo, slot, planSlot);
+ if (resultRelInfo->ri_returningList)
+ result = ExecProcessReturning(resultRelInfo, slot, planSlot, mtstate);
return result;
}
@@ -1022,7 +1057,8 @@ ExecBatchInsert(ModifyTableState *mtstate,
* comment in ExecInsert.
*/
if (resultRelInfo->ri_WithCheckOptions != NIL)
- ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
+ ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate,
+ &mtstate->ps);
}
if (canSetTag && numInserted > 0)
@@ -1345,7 +1381,7 @@ ldelete:;
ar_delete_trig_tcs);
/* Process RETURNING if present and if requested */
- if (processReturning && resultRelInfo->ri_projectReturning)
+ if (processReturning && resultRelInfo->ri_returningList)
{
/*
* We have to put the target tuple into a slot, which means first we
@@ -1373,7 +1409,7 @@ ldelete:;
}
}
- rslot = ExecProcessReturning(resultRelInfo, slot, planSlot);
+ rslot = ExecProcessReturning(resultRelInfo, slot, planSlot, mtstate);
/*
* Before releasing the target tuple again, make sure rslot has a
@@ -1707,7 +1743,8 @@ lreplace:;
* kind we are looking for at this point.
*/
ExecWithCheckOptions(WCO_RLS_UPDATE_CHECK,
- resultRelInfo, slot, estate);
+ resultRelInfo, slot, estate,
+ &mtstate->ps);
}
/*
@@ -1934,11 +1971,12 @@ lreplace:;
* are looking for at this point.
*/
if (resultRelInfo->ri_WithCheckOptions != NIL)
- ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
+ ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate,
+ &mtstate->ps);
/* Process RETURNING if present */
- if (resultRelInfo->ri_projectReturning)
- return ExecProcessReturning(resultRelInfo, slot, planSlot);
+ if (resultRelInfo->ri_returningList)
+ return ExecProcessReturning(resultRelInfo, slot, planSlot, mtstate);
return NULL;
}
@@ -2132,7 +2170,8 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
*/
ExecWithCheckOptions(WCO_RLS_CONFLICT_CHECK, resultRelInfo,
existing,
- mtstate->ps.state);
+ mtstate->ps.state,
+ &mtstate->ps);
}
/* Project the new tuple version */
@@ -2439,7 +2478,7 @@ ExecModifyTable(PlanState *pstate)
* ExecProcessReturning by IterateDirectModify, so no need to
* provide it here.
*/
- slot = ExecProcessReturning(resultRelInfo, NULL, planSlot);
+ slot = ExecProcessReturning(resultRelInfo, NULL, planSlot, node);
return slot;
}
@@ -2748,6 +2787,33 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
ExecSetupTransitionCaptureState(mtstate, estate);
+ /*
+ * Initialize result tuple slot and assign its rowtype using the first
+ * RETURNING list. We assume the rest will look the same.
+ */
+ if (node->returningLists)
+ {
+ mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists);
+
+ /* Set up a slot for the output of the RETURNING projection(s) */
+ ExecInitResultTupleSlotTL(&mtstate->ps, &TTSOpsVirtual);
+
+ /* Need an econtext too */
+ if (mtstate->ps.ps_ExprContext == NULL)
+ ExecAssignExprContext(estate, &mtstate->ps);
+ }
+ else
+ {
+ /*
+ * We still must construct a dummy result tuple type, because InitPlan
+ * expects one (maybe should change that?).
+ */
+ mtstate->ps.plan->targetlist = NIL;
+ ExecInitResultTypeTL(&mtstate->ps);
+
+ mtstate->ps.ps_ExprContext = NULL;
+ }
+
/*
* Open all the result relations and initialize the ResultRelInfo structs.
* (But root relation was initialized above, if it's part of the array.)
@@ -2856,6 +2922,44 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
elog(ERROR, "could not find junk wholerow column");
}
}
+
+ /*
+ * Initialize any WITH CHECK OPTION constraints if needed.
+ */
+ if (node->withCheckOptionLists)
+ {
+ List *wcoList = (List *) list_nth(node->withCheckOptionLists, i);
+
+ resultRelInfo->ri_WithCheckOptions = wcoList;
+ /*
+ * ri_WithCheckOptionExprs is built the first time it needs to be
+ * used (see ExecWithCheckOptions()).
+ */
+ }
+
+ /*
+ * Initialize RETURNING projections if needed.
+ */
+ if (node->returningLists)
+ {
+ List *rlist = (List *) list_nth(node->returningLists, i);
+
+ resultRelInfo->ri_returningList = rlist;
+
+ /*
+ * ri_projectReturning is built the first time it needs to be used
+ * (see ExecProcessReturning()), unless the relation is to be
+ * "directly modified", in that case, IterateDirectModify()
+ * expects ri_projectReturning to be valid. Because the child
+ * relations (their ResultRelInfos) that are directly modified are
+ * accessed from their corresponding ForeignScanState nodes,
+ * they can get switched without the control returning to the top-
+ * level ModifyTable, so there's no better way than initializing
+ * the projection for all such result relations here.
+ */
+ if (resultRelInfo->ri_usesFdwDirectModify)
+ ExecInitReturningProjection(resultRelInfo, mtstate);
+ }
}
/*
@@ -2883,80 +2987,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->mt_partition_tuple_routing =
ExecSetupPartitionTupleRouting(estate, rel);
- /*
- * Initialize any WITH CHECK OPTION constraints if needed.
- */
- resultRelInfo = mtstate->resultRelInfo;
- foreach(l, node->withCheckOptionLists)
- {
- List *wcoList = (List *) lfirst(l);
- List *wcoExprs = NIL;
- ListCell *ll;
-
- foreach(ll, wcoList)
- {
- WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
- ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
- &mtstate->ps);
-
- wcoExprs = lappend(wcoExprs, wcoExpr);
- }
-
- resultRelInfo->ri_WithCheckOptions = wcoList;
- resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
- resultRelInfo++;
- }
-
- /*
- * Initialize RETURNING projections if needed.
- */
- if (node->returningLists)
- {
- TupleTableSlot *slot;
- ExprContext *econtext;
-
- /*
- * Initialize result tuple slot and assign its rowtype using the first
- * RETURNING list. We assume the rest will look the same.
- */
- mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists);
-
- /* Set up a slot for the output of the RETURNING projection(s) */
- ExecInitResultTupleSlotTL(&mtstate->ps, &TTSOpsVirtual);
- slot = mtstate->ps.ps_ResultTupleSlot;
-
- /* Need an econtext too */
- if (mtstate->ps.ps_ExprContext == NULL)
- ExecAssignExprContext(estate, &mtstate->ps);
- econtext = mtstate->ps.ps_ExprContext;
-
- /*
- * Build a projection for each result rel.
- */
- resultRelInfo = mtstate->resultRelInfo;
- foreach(l, node->returningLists)
- {
- List *rlist = (List *) lfirst(l);
-
- resultRelInfo->ri_returningList = rlist;
- resultRelInfo->ri_projectReturning =
- ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
- resultRelInfo->ri_RelationDesc->rd_att);
- resultRelInfo++;
- }
- }
- else
- {
- /*
- * We still must construct a dummy result tuple type, because InitPlan
- * expects one (maybe should change that?).
- */
- mtstate->ps.plan->targetlist = NIL;
- ExecInitResultTypeTL(&mtstate->ps);
-
- mtstate->ps.ps_ExprContext = NULL;
- }
-
/* Set the list of arbiter indexes if needed for ON CONFLICT */
resultRelInfo = mtstate->resultRelInfo;
if (node->onConflictAction != ONCONFLICT_NONE)
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 6eae134c08..622cb26c88 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -211,7 +211,8 @@ extern bool ExecPartitionCheck(ResultRelInfo *resultRelInfo,
extern void ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate);
extern void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
- TupleTableSlot *slot, EState *estate);
+ TupleTableSlot *slot, EState *estate,
+ PlanState *parent);
extern LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo);
extern ExecRowMark *ExecFindRowMark(EState *estate, Index rti, bool missing_ok);
extern ExecAuxRowMark *ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist);
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index cdff914b93..dd309283be 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -1892,28 +1892,22 @@ UPDATE rw_view1 SET a = a + 5; -- should fail
ERROR: new row violates check option for view "rw_view1"
DETAIL: Failing row contains (15).
EXPLAIN (costs off) INSERT INTO rw_view1 VALUES (5);
- QUERY PLAN
----------------------------------------------------------
+ QUERY PLAN
+----------------------
Insert on base_tbl b
-> Result
- SubPlan 1
- -> Index Only Scan using ref_tbl_pkey on ref_tbl r
- Index Cond: (a = b.a)
-(5 rows)
+(2 rows)
EXPLAIN (costs off) UPDATE rw_view1 SET a = a + 5;
- QUERY PLAN
------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------
Update on base_tbl b
-> Hash Join
Hash Cond: (b.a = r.a)
-> Seq Scan on base_tbl b
-> Hash
-> Seq Scan on ref_tbl r
- SubPlan 1
- -> Index Only Scan using ref_tbl_pkey on ref_tbl r_1
- Index Cond: (a = b.a)
-(9 rows)
+(6 rows)
DROP TABLE base_tbl, ref_tbl CASCADE;
NOTICE: drop cascades to view rw_view1
--
2.24.1