From 59f40566cab95181ec132b3f0208f34e4c67f2b0 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Tue, 16 May 2017 12:46:32 -0400 Subject: [PATCH] Fix relcache leak when row triggers on partitions are fired by COPY. Thomas Munro, reviewed by Amit Langote Discussion: http://postgr.es/m/CAEepm=15Jss-yhFApuKzxcoCuFnb8TR8iQiWMjG=CLYPx48QLw@mail.gmail.com --- src/backend/commands/copy.c | 3 ++ src/backend/commands/trigger.c | 11 +------- src/backend/executor/execMain.c | 39 ++++++++++++++------------ src/include/executor/executor.h | 1 + src/test/regress/expected/triggers.out | 10 +++++++ src/test/regress/sql/triggers.sql | 12 ++++++++ 6 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index f22d0a0798..137b1ef42d 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -2773,6 +2773,9 @@ CopyFrom(CopyState cstate) ExecDropSingleTupleTableSlot(cstate->partition_tuple_slot); } + /* Close any trigger target relations */ + ExecCleanUpTriggerState(estate); + FreeExecutorState(estate); /* diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 819395a967..1566fb4607 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -4110,16 +4110,7 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events, if (local_estate) { - ListCell *l; - - foreach(l, estate->es_trig_target_relations) - { - ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l); - - /* Close indices and then the relation itself */ - ExecCloseIndices(resultRelInfo); - heap_close(resultRelInfo->ri_RelationDesc, NoLock); - } + ExecCleanUpTriggerState(estate); FreeExecutorState(estate); } diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 2535d2ee69..fb2ba3302c 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1446,6 +1446,24 @@ ExecGetTriggerResultRel(EState *estate, Oid relid) return rInfo; } +/* + * Close any relations that have been opened by ExecGetTriggerResultRel(). + */ +void +ExecCleanUpTriggerState(EState *estate) +{ + ListCell *l; + + foreach(l, estate->es_trig_target_relations) + { + ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l); + + /* Close indices and then the relation itself */ + ExecCloseIndices(resultRelInfo); + heap_close(resultRelInfo->ri_RelationDesc, NoLock); + } +} + /* * ExecContextForcesOids * @@ -1610,16 +1628,8 @@ ExecEndPlan(PlanState *planstate, EState *estate) resultRelInfo++; } - /* - * likewise close any trigger target relations - */ - foreach(l, estate->es_trig_target_relations) - { - resultRelInfo = (ResultRelInfo *) lfirst(l); - /* Close indices and then the relation itself */ - ExecCloseIndices(resultRelInfo); - heap_close(resultRelInfo->ri_RelationDesc, NoLock); - } + /* likewise close any trigger target relations */ + ExecCleanUpTriggerState(estate); /* * close any relations selected FOR [KEY] UPDATE/SHARE, again keeping @@ -3173,14 +3183,7 @@ EvalPlanQualEnd(EPQState *epqstate) ExecResetTupleTable(estate->es_tupleTable, false); /* close any trigger target relations attached to this EState */ - foreach(l, estate->es_trig_target_relations) - { - ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l); - - /* Close indices and then the relation itself */ - ExecCloseIndices(resultRelInfo); - heap_close(resultRelInfo->ri_RelationDesc, NoLock); - } + ExecCleanUpTriggerState(estate); MemoryContextSwitchTo(oldcontext); diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 3107cf5b89..4f19579ee0 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -184,6 +184,7 @@ extern void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation partition_root, int instrument_options); extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid); +extern void ExecCleanUpTriggerState(EState *estate); extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids); extern void ExecConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate); diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out index c300449f3a..0d560fb3ee 100644 --- a/src/test/regress/expected/triggers.out +++ b/src/test/regress/expected/triggers.out @@ -1882,4 +1882,14 @@ NOTICE: trigger on parted2_stmt_trig AFTER UPDATE for STATEMENT delete from parted_stmt_trig; NOTICE: trigger on parted_stmt_trig BEFORE DELETE for STATEMENT NOTICE: trigger on parted_stmt_trig AFTER DELETE for STATEMENT +-- insert via copy on the parent +copy parted_stmt_trig(a) from stdin; +NOTICE: trigger on parted_stmt_trig BEFORE INSERT for STATEMENT +NOTICE: trigger on parted_stmt_trig1 BEFORE INSERT for ROW +NOTICE: trigger on parted_stmt_trig1 AFTER INSERT for ROW +NOTICE: trigger on parted_stmt_trig AFTER INSERT for STATEMENT +-- insert via copy on the first partition +copy parted_stmt_trig1(a) from stdin; +NOTICE: trigger on parted_stmt_trig1 BEFORE INSERT for ROW +NOTICE: trigger on parted_stmt_trig1 AFTER INSERT for ROW drop table parted_stmt_trig, parted2_stmt_trig; diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql index e5dbcaeea3..5581fcb164 100644 --- a/src/test/regress/sql/triggers.sql +++ b/src/test/regress/sql/triggers.sql @@ -1347,4 +1347,16 @@ with upd as ( ) update parted_stmt_trig set a = a; delete from parted_stmt_trig; + +-- insert via copy on the parent +copy parted_stmt_trig(a) from stdin; +1 +2 +\. + +-- insert via copy on the first partition +copy parted_stmt_trig1(a) from stdin; +1 +\. + drop table parted_stmt_trig, parted2_stmt_trig; -- 2.40.0