Fix relcache leak when row triggers on partitions are fired by COPY.
authorRobert Haas
Tue, 16 May 2017 16:46:32 +0000 (12:46 -0400)
committerRobert Haas
Tue, 16 May 2017 16:46:32 +0000 (12:46 -0400)
Thomas Munro, reviewed by Amit Langote

Discussion: http://postgr.es/m/CAEepm=15Jss-yhFApuKzxcoCuFnb8TR8iQiWMjG=CLYPx48QLw@mail.gmail.com

src/backend/commands/copy.c
src/backend/commands/trigger.c
src/backend/executor/execMain.c
src/include/executor/executor.h
src/test/regress/expected/triggers.out
src/test/regress/sql/triggers.sql

index f22d0a079872ecf5d0735bbd77b35175a61940d4..137b1ef42d9662bd65007156020c2e0711629bb5 100644 (file)
@@ -2773,6 +2773,9 @@ CopyFrom(CopyState cstate)
        ExecDropSingleTupleTableSlot(cstate->partition_tuple_slot);
    }
 
+   /* Close any trigger target relations */
+   ExecCleanUpTriggerState(estate);
+
    FreeExecutorState(estate);
 
    /*
index 819395a9678ae88352a1d7bc790aa21a3675b97a..1566fb46074a16509859eaeb7a8c0481306cca19 100644 (file)
@@ -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);
    }
 
index 2535d2ee69587a0b00d27d890994f2254082d0e5..fb2ba3302c0a5c5a38ae3ad6f5ad7274a34d68ac 100644 (file)
@@ -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);
 
index 3107cf5b89e9b481fd86ec60f9313340c3278187..4f19579ee0b701d27adead35b47224c464453d75 100644 (file)
@@ -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);
index c300449f3aaa978537db532dd5b6b9f8a046a9d0..0d560fb3eed3519f09fbe77d00b20faabefa9c2d 100644 (file)
@@ -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;
index e5dbcaeea36f9df9edf68a6d64e4fcf71393a64f..5581fcb16485ac7ccee7fd79a936e5695841b15e 100644 (file)
@@ -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;