Skip to content

Commit 37b547a

Browse files
yugo-nCommitfest Bot
authored andcommitted
Allow to prolong life span of transition tables until transaction end
Originally, tuplestores of AFTER trigger's transition tables were freed for each query depth. For our IVM implementation, we would like to prolong life of the tuplestores because we have to preserve them for a whole query assuming that some base tables might be changed in some trigger functions.
1 parent 46794f9 commit 37b547a

File tree

2 files changed

+81
-4
lines changed

2 files changed

+81
-4
lines changed

src/backend/commands/trigger.c

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3754,6 +3754,10 @@ typedef struct AfterTriggerEventList
37543754
* end of the list, so it is relatively easy to discard them. The event
37553755
* list chunks themselves are stored in event_cxt.
37563756
*
3757+
* prolonged_tuplestored is a list of transition table tuplestores whose
3758+
* life are prolonged to the end of the outmost query instead of each nested
3759+
* query.
3760+
*
37573761
* query_depth is the current depth of nested AfterTriggerBeginQuery calls
37583762
* (-1 when the stack is empty).
37593763
*
@@ -3819,6 +3823,7 @@ typedef struct AfterTriggersData
38193823
SetConstraintState state; /* the active S C state */
38203824
AfterTriggerEventList events; /* deferred-event list */
38213825
MemoryContext event_cxt; /* memory context for events, if any */
3826+
List *prolonged_tuplestores; /* list of prolonged tuplestores */
38223827

38233828
/* per-query-level data: */
38243829
AfterTriggersQueryData *query_stack; /* array of structs shown below */
@@ -3854,6 +3859,7 @@ struct AfterTriggersTableData
38543859
bool closed; /* true when no longer OK to add tuples */
38553860
bool before_trig_done; /* did we already queue BS triggers? */
38563861
bool after_trig_done; /* did we already queue AS triggers? */
3862+
bool prolonged; /* are transition tables prolonged? */
38573863
AfterTriggerEventList after_trig_events; /* if so, saved list pointer */
38583864

38593865
/*
@@ -3903,6 +3909,7 @@ static void TransitionTableAddTuple(EState *estate,
39033909
TupleTableSlot *original_insert_tuple,
39043910
Tuplestorestate *tuplestore);
39053911
static void AfterTriggerFreeQuery(AfterTriggersQueryData *qs);
3912+
static void release_or_prolong_tuplestore(Tuplestorestate *ts, bool prolonged);
39063913
static SetConstraintState SetConstraintStateCreate(int numalloc);
39073914
static SetConstraintState SetConstraintStateCopy(SetConstraintState origstate);
39083915
static SetConstraintState SetConstraintStateAddItem(SetConstraintState state,
@@ -4782,6 +4789,45 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events,
47824789
}
47834790

47844791

4792+
/*
4793+
* SetTransitionTablePreserved
4794+
*
4795+
* Prolong lifespan of transition tables corresponding specified relid and
4796+
* command type to the end of the outmost query instead of each nested query.
4797+
* This enables to use nested AFTER trigger's transition tables from outer
4798+
* query's triggers. Currently, only immediate incremental view maintenance
4799+
* uses this.
4800+
*/
4801+
void
4802+
SetTransitionTablePreserved(Oid relid, CmdType cmdType)
4803+
{
4804+
AfterTriggersTableData *table;
4805+
AfterTriggersQueryData *qs;
4806+
bool found = false;
4807+
ListCell *lc;
4808+
4809+
/* Check state, like AfterTriggerSaveEvent. */
4810+
if (afterTriggers.query_depth < 0)
4811+
elog(ERROR, "SetTransitionTablePreserved() called outside of query");
4812+
4813+
qs = &afterTriggers.query_stack[afterTriggers.query_depth];
4814+
4815+
foreach(lc, qs->tables)
4816+
{
4817+
table = (AfterTriggersTableData *) lfirst(lc);
4818+
if (table->relid == relid && table->cmdType == cmdType &&
4819+
table->closed)
4820+
{
4821+
table->prolonged = true;
4822+
found = true;
4823+
}
4824+
}
4825+
4826+
if (!found)
4827+
elog(ERROR,"could not find table with OID %d and command type %d", relid, cmdType);
4828+
}
4829+
4830+
47854831
/*
47864832
* GetAfterTriggersTableData
47874833
*
@@ -4992,6 +5038,7 @@ AfterTriggerBeginXact(void)
49925038
*/
49935039
afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
49945040
afterTriggers.query_depth = -1;
5041+
afterTriggers.prolonged_tuplestores = NIL;
49955042

49965043
/*
49975044
* Verify that there is no leftover state remaining. If these assertions
@@ -5152,19 +5199,19 @@ AfterTriggerFreeQuery(AfterTriggersQueryData *qs)
51525199
ts = table->old_upd_tuplestore;
51535200
table->old_upd_tuplestore = NULL;
51545201
if (ts)
5155-
tuplestore_end(ts);
5202+
release_or_prolong_tuplestore(ts, table->prolonged);
51565203
ts = table->new_upd_tuplestore;
51575204
table->new_upd_tuplestore = NULL;
51585205
if (ts)
5159-
tuplestore_end(ts);
5206+
release_or_prolong_tuplestore(ts, table->prolonged);
51605207
ts = table->old_del_tuplestore;
51615208
table->old_del_tuplestore = NULL;
51625209
if (ts)
5163-
tuplestore_end(ts);
5210+
release_or_prolong_tuplestore(ts, table->prolonged);
51645211
ts = table->new_ins_tuplestore;
51655212
table->new_ins_tuplestore = NULL;
51665213
if (ts)
5167-
tuplestore_end(ts);
5214+
release_or_prolong_tuplestore(ts, table->prolonged);
51685215
if (table->storeslot)
51695216
{
51705217
TupleTableSlot *slot = table->storeslot;
@@ -5181,6 +5228,34 @@ AfterTriggerFreeQuery(AfterTriggersQueryData *qs)
51815228
*/
51825229
qs->tables = NIL;
51835230
list_free_deep(tables);
5231+
5232+
/* Release prolonged tuplestores at the end of the outmost query */
5233+
if (afterTriggers.query_depth == 0)
5234+
{
5235+
foreach(lc, afterTriggers.prolonged_tuplestores)
5236+
{
5237+
ts = (Tuplestorestate *) lfirst(lc);
5238+
if (ts)
5239+
tuplestore_end(ts);
5240+
}
5241+
afterTriggers.prolonged_tuplestores = NIL;
5242+
}
5243+
}
5244+
5245+
/*
5246+
* Release the tuplestore, or append it to the prolonged tuplestores list.
5247+
*/
5248+
static void
5249+
release_or_prolong_tuplestore(Tuplestorestate *ts, bool prolonged)
5250+
{
5251+
if (prolonged && afterTriggers.query_depth > 0)
5252+
{
5253+
MemoryContext oldcxt = MemoryContextSwitchTo(CurTransactionContext);
5254+
afterTriggers.prolonged_tuplestores = lappend(afterTriggers.prolonged_tuplestores, ts);
5255+
MemoryContextSwitchTo(oldcxt);
5256+
}
5257+
else
5258+
tuplestore_end(ts);
51845259
}
51855260

51865261

src/include/commands/trigger.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ extern void AfterTriggerEndSubXact(bool isCommit);
265265
extern void AfterTriggerSetState(ConstraintsSetStmt *stmt);
266266
extern bool AfterTriggerPendingOnRel(Oid relid);
267267

268+
extern void SetTransitionTablePreserved(Oid relid, CmdType cmdType);
269+
268270

269271
/*
270272
* in utils/adt/ri_triggers.c

0 commit comments

Comments
 (0)