diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index d98b4e6a1b3..1ae40ffe044 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -6671,6 +6671,16 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, &new_event, &new_shared, rowId1, rowId2); } + /* + * slot_getsysattr(RowIdAttributeNumber) returns an owning palloc'd copy. + * afterTriggerAddEvent() copies rowids into its event chunk, so these + * temporary copies don't need to live until PortalContext reset. + */ + if (rowId1) + pfree(rowId1); + if (rowId2 && rowId2 != rowId1) + pfree(rowId2); + /* * Finally, spool any foreign tuple(s). The tuplestore squashes them to * minimal tuples, so this loses any system columns. The executor lost diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c index b13c0c8b3df..2d765244d3c 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -116,6 +116,25 @@ #include "storage/lmgr.h" #include "utils/snapmgr.h" +static inline bool +ExecIndexTupleIdNeedsFree(Relation heapRelation) +{ + /* + * ROW_REF_ROWID table AMs are expected to return a caller-owned palloc'd + * Datum from slot_getsysattr(RowIdAttributeNumber). Freeing it here + * relies on that ownership contract; a future ROW_REF_ROWID AM that + * returns a borrowed pointer must not use this path unchanged. + */ + return table_get_row_ref_type(heapRelation) == ROW_REF_ROWID; +} + +static inline void +ExecIndexFreeTupleId(Relation heapRelation, Datum tupleid) +{ + if (ExecIndexTupleIdNeedsFree(heapRelation)) + pfree(DatumGetPointer(tupleid)); +} + static bool index_recheck_constraint(Relation index, const Oid *constr_procs, const Datum *existing_values, const bool *existing_isnull, const Datum *new_values); @@ -298,7 +317,7 @@ ExecInsertIndexTuples(ResultRelInfo *resultRelInfo, bool isnull[INDEX_MAX_KEYS]; Datum tupleidDatum; - if (table_get_row_ref_type(resultRelInfo->ri_RelationDesc) == ROW_REF_ROWID) + if (ExecIndexTupleIdNeedsFree(resultRelInfo->ri_RelationDesc)) { bool isnull; tupleidDatum = slot_getsysattr(slot, RowIdAttributeNumber, &isnull); @@ -496,6 +515,8 @@ ExecInsertIndexTuples(ResultRelInfo *resultRelInfo, } } + ExecIndexFreeTupleId(heapRelation, tupleidDatum); + return result; } @@ -520,7 +541,7 @@ ExecUpdateIndexTuples(ResultRelInfo *resultRelInfo, bool isnull[INDEX_MAX_KEYS]; Datum tupleidDatum; - if (table_get_row_ref_type(resultRelInfo->ri_RelationDesc) == ROW_REF_ROWID) + if (ExecIndexTupleIdNeedsFree(resultRelInfo->ri_RelationDesc)) { bool isnull; tupleidDatum = slot_getsysattr(slot, RowIdAttributeNumber, &isnull); @@ -661,9 +682,10 @@ ExecUpdateIndexTuples(ResultRelInfo *resultRelInfo, Datum oldTupleidDatum; bool old_valid = true; - if (table_get_row_ref_type(resultRelInfo->ri_RelationDesc) == ROW_REF_ROWID) + if (ExecIndexTupleIdNeedsFree(resultRelInfo->ri_RelationDesc)) { bool isnull; + oldTupleidDatum = slot_getsysattr(oldSlot, RowIdAttributeNumber, &isnull); Assert(!isnull); } @@ -718,6 +740,8 @@ ExecUpdateIndexTuples(ResultRelInfo *resultRelInfo, indexUnchanged, /* UPDATE without logical change? */ indexInfo); /* index AM may need this */ + ExecIndexFreeTupleId(heapRelation, oldTupleidDatum); + } else { @@ -791,6 +815,8 @@ ExecUpdateIndexTuples(ResultRelInfo *resultRelInfo, } } + ExecIndexFreeTupleId(heapRelation, tupleidDatum); + return result; } @@ -808,7 +834,7 @@ ExecDeleteIndexTuples(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, bool isnull[INDEX_MAX_KEYS]; Datum tupleid; - if (table_get_row_ref_type(resultRelInfo->ri_RelationDesc) == ROW_REF_ROWID) + if (ExecIndexTupleIdNeedsFree(resultRelInfo->ri_RelationDesc)) { bool isnull; tupleid = slot_getsysattr(slot, RowIdAttributeNumber, &isnull); @@ -898,6 +924,8 @@ ExecDeleteIndexTuples(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, heapRelation, /* heap relation */ indexInfo); /* index AM may need this */ } + + ExecIndexFreeTupleId(heapRelation, tupleid); } /* ----------------------------------------------------------------