Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite180c8a

Browse files
committed
Fire per-statement triggers on partitioned tables.
Even though no actual tuples are ever inserted into a partitionedtable (the actual tuples are in the partitions, not the partitionedtable itself), we still need to have a ResultRelInfo for thepartitioned table, or per-statement triggers won't get fired.Amit Langote, per a report from Rajkumar Raghuwanshi. Reviewed by me.Discussion:http://postgr.es/m/CAKcux6%3DwYospCRY2J4XEFuVy0L41S%3Dfic7rmkbsU-GXhhSbmBg%40mail.gmail.com
1 parente18b2c4 commite180c8a

File tree

14 files changed

+296
-27
lines changed

14 files changed

+296
-27
lines changed

‎doc/src/sgml/trigger.sgml

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
<para>
3434
A trigger is a specification that the database should automatically
3535
execute a particular function whenever a certain type of operation is
36-
performed. Triggers can be attached to tables, views, and foreign tables.
36+
performed. Triggers can be attached to tables (partitioned or not),
37+
views, and foreign tables.
3738
</para>
3839

3940
<para>
@@ -111,14 +112,14 @@
111112
Statement-level <literal>BEFORE</> triggers naturally fire before the
112113
statement starts to do anything, while statement-level <literal>AFTER</>
113114
triggers fire at the very end of the statement. These types of
114-
triggers may be defined on tablesorviews. Row-level <literal>BEFORE</>
115-
triggers fire immediately before a particular row is operated on,
116-
while row-level <literal>AFTER</> triggers fire at the end of the
117-
statement (but before any statement-level <literal>AFTER</> triggers).
118-
These types of triggers may only be defined on tables and foreign tables.
119-
Row-level <literal>INSTEAD OF</> triggers may only be defined on views,
120-
and fire immediately as each row in the view is identified as needing to
121-
be operated on.
115+
triggers may be defined on tables, views,orforeign tables. Row-level
116+
<literal>BEFORE</>triggers fire immediately before a particular row is
117+
operated on,while row-level <literal>AFTER</> triggers fire at the end of
118+
thestatement (but before any statement-level <literal>AFTER</> triggers).
119+
These types of triggers may only be defined onnon-partitionedtables and
120+
foreign tables.Row-level <literal>INSTEAD OF</> triggers may only be
121+
defined on views,and fire immediately as each row in the view is
122+
identified as needing tobe operated on.
122123
</para>
123124

124125
<para>

‎src/backend/executor/execMain.c

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -861,17 +861,52 @@ InitPlan(QueryDesc *queryDesc, int eflags)
861861

862862
/*
863863
* In the partitioned result relation case, lock the non-leaf result
864-
* relations too. We don't however need ResultRelInfos for them.
864+
* relations too. A subset of these are the roots of respective
865+
* partitioned tables, for which we also allocate ResulRelInfos.
865866
*/
867+
estate->es_root_result_relations=NULL;
868+
estate->es_num_root_result_relations=0;
866869
if (plannedstmt->nonleafResultRelations)
867870
{
871+
intnum_roots=list_length(plannedstmt->rootResultRelations);
872+
873+
/*
874+
* Firstly, build ResultRelInfos for all the partitioned table
875+
* roots, because we will need them to fire the statement-level
876+
* triggers, if any.
877+
*/
878+
resultRelInfos= (ResultRelInfo*)
879+
palloc(num_roots*sizeof(ResultRelInfo));
880+
resultRelInfo=resultRelInfos;
881+
foreach(l,plannedstmt->rootResultRelations)
882+
{
883+
IndexresultRelIndex=lfirst_int(l);
884+
OidresultRelOid;
885+
RelationresultRelDesc;
886+
887+
resultRelOid=getrelid(resultRelIndex,rangeTable);
888+
resultRelDesc=heap_open(resultRelOid,RowExclusiveLock);
889+
InitResultRelInfo(resultRelInfo,
890+
resultRelDesc,
891+
lfirst_int(l),
892+
NULL,
893+
estate->es_instrument);
894+
resultRelInfo++;
895+
}
896+
897+
estate->es_root_result_relations=resultRelInfos;
898+
estate->es_num_root_result_relations=num_roots;
899+
900+
/* Simply lock the rest of them. */
868901
foreach(l,plannedstmt->nonleafResultRelations)
869902
{
870-
IndexresultRelationIndex=lfirst_int(l);
871-
OidresultRelationOid;
903+
IndexresultRelIndex=lfirst_int(l);
872904

873-
resultRelationOid=getrelid(resultRelationIndex,rangeTable);
874-
LockRelationOid(resultRelationOid,RowExclusiveLock);
905+
/* We locked the roots above. */
906+
if (!list_member_int(plannedstmt->rootResultRelations,
907+
resultRelIndex))
908+
LockRelationOid(getrelid(resultRelIndex,rangeTable),
909+
RowExclusiveLock);
875910
}
876911
}
877912
}
@@ -883,6 +918,8 @@ InitPlan(QueryDesc *queryDesc, int eflags)
883918
estate->es_result_relations=NULL;
884919
estate->es_num_result_relations=0;
885920
estate->es_result_relation_info=NULL;
921+
estate->es_root_result_relations=NULL;
922+
estate->es_num_root_result_relations=0;
886923
}
887924

888925
/*
@@ -1565,6 +1602,14 @@ ExecEndPlan(PlanState *planstate, EState *estate)
15651602
resultRelInfo++;
15661603
}
15671604

1605+
/* Close the root target relation(s). */
1606+
resultRelInfo=estate->es_root_result_relations;
1607+
for (i=estate->es_num_root_result_relations;i>0;i--)
1608+
{
1609+
heap_close(resultRelInfo->ri_RelationDesc,NoLock);
1610+
resultRelInfo++;
1611+
}
1612+
15681613
/*
15691614
* likewise close any trigger target relations
15701615
*/

‎src/backend/executor/nodeModifyTable.c

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,19 +1328,29 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
13281328
staticvoid
13291329
fireBSTriggers(ModifyTableState*node)
13301330
{
1331+
ResultRelInfo*resultRelInfo=node->resultRelInfo;
1332+
1333+
/*
1334+
* If the node modifies a partitioned table, we must fire its triggers.
1335+
* Note that in that case, node->resultRelInfo points to the first leaf
1336+
* partition, not the root table.
1337+
*/
1338+
if (node->rootResultRelInfo!=NULL)
1339+
resultRelInfo=node->rootResultRelInfo;
1340+
13311341
switch (node->operation)
13321342
{
13331343
caseCMD_INSERT:
1334-
ExecBSInsertTriggers(node->ps.state,node->resultRelInfo);
1344+
ExecBSInsertTriggers(node->ps.state,resultRelInfo);
13351345
if (node->mt_onconflict==ONCONFLICT_UPDATE)
13361346
ExecBSUpdateTriggers(node->ps.state,
1337-
node->resultRelInfo);
1347+
resultRelInfo);
13381348
break;
13391349
caseCMD_UPDATE:
1340-
ExecBSUpdateTriggers(node->ps.state,node->resultRelInfo);
1350+
ExecBSUpdateTriggers(node->ps.state,resultRelInfo);
13411351
break;
13421352
caseCMD_DELETE:
1343-
ExecBSDeleteTriggers(node->ps.state,node->resultRelInfo);
1353+
ExecBSDeleteTriggers(node->ps.state,resultRelInfo);
13441354
break;
13451355
default:
13461356
elog(ERROR,"unknown operation");
@@ -1354,19 +1364,29 @@ fireBSTriggers(ModifyTableState *node)
13541364
staticvoid
13551365
fireASTriggers(ModifyTableState*node)
13561366
{
1367+
ResultRelInfo*resultRelInfo=node->resultRelInfo;
1368+
1369+
/*
1370+
* If the node modifies a partitioned table, we must fire its triggers.
1371+
* Note that in that case, node->resultRelInfo points to the first leaf
1372+
* partition, not the root table.
1373+
*/
1374+
if (node->rootResultRelInfo!=NULL)
1375+
resultRelInfo=node->rootResultRelInfo;
1376+
13571377
switch (node->operation)
13581378
{
13591379
caseCMD_INSERT:
13601380
if (node->mt_onconflict==ONCONFLICT_UPDATE)
13611381
ExecASUpdateTriggers(node->ps.state,
1362-
node->resultRelInfo);
1363-
ExecASInsertTriggers(node->ps.state,node->resultRelInfo);
1382+
resultRelInfo);
1383+
ExecASInsertTriggers(node->ps.state,resultRelInfo);
13641384
break;
13651385
caseCMD_UPDATE:
1366-
ExecASUpdateTriggers(node->ps.state,node->resultRelInfo);
1386+
ExecASUpdateTriggers(node->ps.state,resultRelInfo);
13671387
break;
13681388
caseCMD_DELETE:
1369-
ExecASDeleteTriggers(node->ps.state,node->resultRelInfo);
1389+
ExecASDeleteTriggers(node->ps.state,resultRelInfo);
13701390
break;
13711391
default:
13721392
elog(ERROR,"unknown operation");
@@ -1652,6 +1672,12 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
16521672

16531673
mtstate->mt_plans= (PlanState**)palloc0(sizeof(PlanState*)*nplans);
16541674
mtstate->resultRelInfo=estate->es_result_relations+node->resultRelIndex;
1675+
1676+
/* If modifying a partitioned table, initialize the root table info */
1677+
if (node->rootResultRelIndex >=0)
1678+
mtstate->rootResultRelInfo=estate->es_root_result_relations+
1679+
node->rootResultRelIndex;
1680+
16551681
mtstate->mt_arowmarks= (List**)palloc0(sizeof(List*)*nplans);
16561682
mtstate->mt_nplans=nplans;
16571683
mtstate->mt_onconflict=node->onConflictAction;

‎src/backend/nodes/copyfuncs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ _copyPlannedStmt(const PlannedStmt *from)
9191
COPY_NODE_FIELD(rtable);
9292
COPY_NODE_FIELD(resultRelations);
9393
COPY_NODE_FIELD(nonleafResultRelations);
94+
COPY_NODE_FIELD(rootResultRelations);
9495
COPY_NODE_FIELD(subplans);
9596
COPY_BITMAPSET_FIELD(rewindPlanIDs);
9697
COPY_NODE_FIELD(rowMarks);
@@ -205,6 +206,7 @@ _copyModifyTable(const ModifyTable *from)
205206
COPY_NODE_FIELD(partitioned_rels);
206207
COPY_NODE_FIELD(resultRelations);
207208
COPY_SCALAR_FIELD(resultRelIndex);
209+
COPY_SCALAR_FIELD(rootResultRelIndex);
208210
COPY_NODE_FIELD(plans);
209211
COPY_NODE_FIELD(withCheckOptionLists);
210212
COPY_NODE_FIELD(returningLists);

‎src/backend/nodes/outfuncs.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
253253
WRITE_NODE_FIELD(rtable);
254254
WRITE_NODE_FIELD(resultRelations);
255255
WRITE_NODE_FIELD(nonleafResultRelations);
256+
WRITE_NODE_FIELD(rootResultRelations);
256257
WRITE_NODE_FIELD(subplans);
257258
WRITE_BITMAPSET_FIELD(rewindPlanIDs);
258259
WRITE_NODE_FIELD(rowMarks);
@@ -350,6 +351,7 @@ _outModifyTable(StringInfo str, const ModifyTable *node)
350351
WRITE_NODE_FIELD(partitioned_rels);
351352
WRITE_NODE_FIELD(resultRelations);
352353
WRITE_INT_FIELD(resultRelIndex);
354+
WRITE_INT_FIELD(rootResultRelIndex);
353355
WRITE_NODE_FIELD(plans);
354356
WRITE_NODE_FIELD(withCheckOptionLists);
355357
WRITE_NODE_FIELD(returningLists);
@@ -2145,6 +2147,7 @@ _outPlannerGlobal(StringInfo str, const PlannerGlobal *node)
21452147
WRITE_NODE_FIELD(finalrowmarks);
21462148
WRITE_NODE_FIELD(resultRelations);
21472149
WRITE_NODE_FIELD(nonleafResultRelations);
2150+
WRITE_NODE_FIELD(rootResultRelations);
21482151
WRITE_NODE_FIELD(relationOids);
21492152
WRITE_NODE_FIELD(invalItems);
21502153
WRITE_INT_FIELD(nParamExec);

‎src/backend/nodes/readfuncs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,6 +1453,7 @@ _readPlannedStmt(void)
14531453
READ_NODE_FIELD(rtable);
14541454
READ_NODE_FIELD(resultRelations);
14551455
READ_NODE_FIELD(nonleafResultRelations);
1456+
READ_NODE_FIELD(rootResultRelations);
14561457
READ_NODE_FIELD(subplans);
14571458
READ_BITMAPSET_FIELD(rewindPlanIDs);
14581459
READ_NODE_FIELD(rowMarks);
@@ -1548,6 +1549,7 @@ _readModifyTable(void)
15481549
READ_NODE_FIELD(partitioned_rels);
15491550
READ_NODE_FIELD(resultRelations);
15501551
READ_INT_FIELD(resultRelIndex);
1552+
READ_INT_FIELD(rootResultRelIndex);
15511553
READ_NODE_FIELD(plans);
15521554
READ_NODE_FIELD(withCheckOptionLists);
15531555
READ_NODE_FIELD(returningLists);

‎src/backend/optimizer/plan/createplan.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6437,6 +6437,7 @@ make_modifytable(PlannerInfo *root,
64376437
node->partitioned_rels=partitioned_rels;
64386438
node->resultRelations=resultRelations;
64396439
node->resultRelIndex=-1;/* will be set correctly in setrefs.c */
6440+
node->rootResultRelIndex=-1;/* will be set correctly in setrefs.c */
64406441
node->plans=subplans;
64416442
if (!onconflict)
64426443
{

‎src/backend/optimizer/plan/planner.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
240240
glob->finalrowmarks=NIL;
241241
glob->resultRelations=NIL;
242242
glob->nonleafResultRelations=NIL;
243+
glob->rootResultRelations=NIL;
243244
glob->relationOids=NIL;
244245
glob->invalItems=NIL;
245246
glob->nParamExec=0;
@@ -408,6 +409,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
408409
Assert(glob->finalrowmarks==NIL);
409410
Assert(glob->resultRelations==NIL);
410411
Assert(glob->nonleafResultRelations==NIL);
412+
Assert(glob->rootResultRelations==NIL);
411413
top_plan=set_plan_references(root,top_plan);
412414
/* ... and the subplans (both regular subplans and initplans) */
413415
Assert(list_length(glob->subplans)==list_length(glob->subroots));
@@ -434,6 +436,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
434436
result->rtable=glob->finalrtable;
435437
result->resultRelations=glob->resultRelations;
436438
result->nonleafResultRelations=glob->nonleafResultRelations;
439+
result->rootResultRelations=glob->rootResultRelations;
437440
result->subplans=glob->subplans;
438441
result->rewindPlanIDs=glob->rewindPlanIDs;
439442
result->rowMarks=glob->finalrowmarks;

‎src/backend/optimizer/plan/setrefs.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -882,11 +882,22 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
882882
/*
883883
* If the main target relation is a partitioned table, the
884884
* following list contains the RT indexes of partitioned child
885-
* relations, which are not included in the above list.
885+
* relations including the root, which are not included in the
886+
* above list. We also keep RT indexes of the roots separately
887+
* to be identitied as such during the executor initialization.
886888
*/
887-
root->glob->nonleafResultRelations=
888-
list_concat(root->glob->nonleafResultRelations,
889-
list_copy(splan->partitioned_rels));
889+
if (splan->partitioned_rels!=NIL)
890+
{
891+
root->glob->nonleafResultRelations=
892+
list_concat(root->glob->nonleafResultRelations,
893+
list_copy(splan->partitioned_rels));
894+
/* Remember where this root will be in the global list. */
895+
splan->rootResultRelIndex=
896+
list_length(root->glob->rootResultRelations);
897+
root->glob->rootResultRelations=
898+
lappend_int(root->glob->rootResultRelations,
899+
linitial_int(splan->partitioned_rels));
900+
}
890901
}
891902
break;
892903
caseT_Append:

‎src/include/nodes/execnodes.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,16 @@ typedef struct EState
422422
intes_num_result_relations;/* length of array */
423423
ResultRelInfo*es_result_relation_info;/* currently active array elt */
424424

425+
/*
426+
* Info about the target partitioned target table root(s) for
427+
* update/delete queries. They required only to fire any per-statement
428+
* triggers defined on the table. It exists separately from
429+
* es_result_relations, because partitioned tables don't appear in the
430+
* plan tree for the update/delete cases.
431+
*/
432+
ResultRelInfo*es_root_result_relations;/* array of ResultRelInfos */
433+
intes_num_root_result_relations;/* length of the array */
434+
425435
/* Stuff used for firing triggers: */
426436
List*es_trig_target_relations;/* trigger-only ResultRelInfos */
427437
TupleTableSlot*es_trig_tuple_slot;/* for trigger output tuples */
@@ -914,6 +924,8 @@ typedef struct ModifyTableState
914924
intmt_nplans;/* number of plans in the array */
915925
intmt_whichplan;/* which one is being executed (0..n-1) */
916926
ResultRelInfo*resultRelInfo;/* per-subplan target relations */
927+
ResultRelInfo*rootResultRelInfo;/* root target relation (partitioned
928+
* table root) */
917929
List**mt_arowmarks;/* per-subplan ExecAuxRowMark lists */
918930
EPQStatemt_epqstate;/* for evaluating EvalPlanQual rechecks */
919931
boolfireBSTriggers;/* do we need to fire stmt triggers? */

‎src/include/nodes/plannodes.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,19 @@ typedef struct PlannedStmt
6565
/* rtable indexes of target relations for INSERT/UPDATE/DELETE */
6666
List*resultRelations;/* integer list of RT indexes, or NIL */
6767

68-
/* rtable indexes of non-leaf target relations for INSERT/UPDATE/DELETE */
68+
/*
69+
* rtable indexes of non-leaf target relations for UPDATE/DELETE on
70+
* all the partitioned table mentioned in the query.
71+
*/
6972
List*nonleafResultRelations;
7073

74+
/*
75+
* rtable indexes of root target relations for UPDATE/DELETE; this list
76+
* maintains a subset of the RT indexes in nonleafResultRelations,
77+
* indicating the roots of the respective partition hierarchies.
78+
*/
79+
List*rootResultRelations;
80+
7181
List*subplans;/* Plan trees for SubPlan expressions; note
7282
* that some could be NULL */
7383

@@ -211,6 +221,7 @@ typedef struct ModifyTable
211221
List*partitioned_rels;
212222
List*resultRelations;/* integer list of RT indexes */
213223
intresultRelIndex;/* index of first resultRel in plan's list */
224+
introotResultRelIndex;/* index of the partitioned table root */
214225
List*plans;/* plan(s) producing source data */
215226
List*withCheckOptionLists;/* per-target-table WCO lists */
216227
List*returningLists;/* per-target-table RETURNING tlists */

‎src/include/nodes/relation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ typedef struct PlannerGlobal
108108
List*resultRelations;/* "flat" list of integer RT indexes */
109109

110110
List*nonleafResultRelations;/* "flat" list of integer RT indexes */
111+
List*rootResultRelations;/* "flat" list of integer RT indexes */
111112

112113
List*relationOids;/* OIDs of relations the plan depends on */
113114

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp