v9_delta.patch.txt
text/plain
Filename: v9_delta.patch.txt
Type: text/plain
Part: 0
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 993c3ac49a3..f271ffccc00 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -224,10 +224,8 @@ typedef struct RI_FastPathEntry
Oid conoid; /* hash key: pg_constraint OID */
Relation pk_rel;
Relation idx_rel;
- IndexScanDesc scandesc;
TupleTableSlot *pk_slot;
TupleTableSlot *fk_slot;
- Snapshot snapshot; /* registered snapshot for the scan */
MemoryContext scan_cxt; /* index scan allocations */
MemoryContext flush_cxt; /* short-lived context for per-flush work */
@@ -301,9 +299,11 @@ static void ri_FastPathCheck(const RI_ConstraintInfo *riinfo,
static void ri_FastPathBatchAdd(const RI_ConstraintInfo *riinfo,
Relation fk_rel, TupleTableSlot *newslot);
static void ri_FastPathFlushArray(RI_FastPathEntry *fpentry, TupleTableSlot *fk_slot,
- const RI_ConstraintInfo *riinfo, Relation fk_rel);
+ const RI_ConstraintInfo *riinfo, Relation fk_rel,
+ Snapshot snapshot);
static void ri_FastPathFlushLoop(RI_FastPathEntry *fpentry, TupleTableSlot *fk_slot,
- const RI_ConstraintInfo *riinfo, Relation fk_rel);
+ const RI_ConstraintInfo *riinfo, Relation fk_rel,
+ Snapshot snapshot);
static void ri_FastPathBatchFlush(RI_FastPathEntry *fpentry,
Relation fk_rel);
static bool ri_FastPathProbeOne(Relation pk_rel, Relation idx_rel,
@@ -2857,8 +2857,8 @@ ri_FastPathBatchFlush(RI_FastPathEntry *fpentry, Relation fk_rel)
const RI_ConstraintInfo *riinfo = fpentry->riinfo;
Relation pk_rel = fpentry->pk_rel;
Relation idx_rel = fpentry->idx_rel;
- Snapshot snapshot = fpentry->snapshot;
TupleTableSlot *fk_slot = fpentry->fk_slot;
+ Snapshot snapshot;
Oid saved_userid;
int saved_sec_context;
MemoryContext oldcxt = CurrentMemoryContext;
@@ -2882,7 +2882,7 @@ ri_FastPathBatchFlush(RI_FastPathEntry *fpentry, Relation fk_rel)
* context per row whereas we do it once around the whole batch.
*/
CommandCounterIncrement();
- snapshot->curcid = GetCurrentCommandId(false);
+ snapshot = RegisterSnapshot(GetTransactionSnapshot());
GetUserIdAndSecContext(&saved_userid, &saved_sec_context);
SetUserIdAndSecContext(RelationGetForm(pk_rel)->relowner,
@@ -2891,11 +2891,12 @@ ri_FastPathBatchFlush(RI_FastPathEntry *fpentry, Relation fk_rel)
SECURITY_NOFORCE_RLS);
if (riinfo->nkeys == 1)
- ri_FastPathFlushArray(fpentry, fk_slot, riinfo, fk_rel);
+ ri_FastPathFlushArray(fpentry, fk_slot, riinfo, fk_rel, snapshot);
else
- ri_FastPathFlushLoop(fpentry, fk_slot, riinfo, fk_rel);
+ ri_FastPathFlushLoop(fpentry, fk_slot, riinfo, fk_rel, snapshot);
MemoryContextSwitchTo(oldcxt);
SetUserIdAndSecContext(saved_userid, saved_sec_context);
+ UnregisterSnapshot(snapshot);
/* Free materialized tuples and reset */
for (int i = 0; i < fpentry->batch_count; i++)
@@ -2912,29 +2913,30 @@ ri_FastPathBatchFlush(RI_FastPathEntry *fpentry, Relation fk_rel)
*/
static void
ri_FastPathFlushLoop(RI_FastPathEntry *fpentry, TupleTableSlot *fk_slot,
- const RI_ConstraintInfo *riinfo, Relation fk_rel)
+ const RI_ConstraintInfo *riinfo, Relation fk_rel,
+ Snapshot snapshot)
{
Relation pk_rel = fpentry->pk_rel;
Relation idx_rel = fpentry->idx_rel;
- IndexScanDesc scandesc = fpentry->scandesc;
TupleTableSlot *pk_slot = fpentry->pk_slot;
- Snapshot snapshot = fpentry->snapshot;
+ IndexScanDesc scandesc;
Datum pk_vals[INDEX_MAX_KEYS];
char pk_nulls[INDEX_MAX_KEYS];
ScanKeyData skey[INDEX_MAX_KEYS];
+ bool found = true;
+ /*
+ * build_index_scankeys() may palloc cast results for cross-type FKs.
+ * Use the entry's short-lived flush context so these don't accumulate
+ * across batches.
+ */
+ MemoryContext oldcxt = MemoryContextSwitchTo(fpentry->flush_cxt);
+ scandesc = index_beginscan(pk_rel, idx_rel, snapshot, NULL,
+ riinfo->nkeys, 0);
for (int i = 0; i < fpentry->batch_count; i++)
{
- bool found = false;
ExecStoreHeapTuple(fpentry->batch[i], fk_slot, false);
-
- /*
- * build_index_scankeys() may palloc cast results for cross-type FKs.
- * Use the entry's short-lived flush context so these don't accumulate
- * across batches.
- */
- MemoryContextSwitchTo(fpentry->flush_cxt);
ri_ExtractValues(fk_rel, fk_slot, riinfo, false, pk_vals, pk_nulls);
build_index_scankeys(riinfo, idx_rel, pk_vals, pk_nulls, skey);
MemoryContextSwitchTo(fpentry->scan_cxt);
@@ -2943,11 +2945,15 @@ ri_FastPathFlushLoop(RI_FastPathEntry *fpentry, TupleTableSlot *fk_slot,
snapshot, riinfo, skey, riinfo->nkeys);
if (!found)
- ri_ReportViolation(riinfo, pk_rel, fk_rel,
- fk_slot, NULL,
- RI_PLAN_CHECK_LOOKUPPK, false, false);
+ break;
}
+ index_endscan(scandesc);
MemoryContextReset(fpentry->flush_cxt);
+ MemoryContextSwitchTo(oldcxt);
+ if (!found)
+ ri_ReportViolation(riinfo, pk_rel, fk_rel,
+ fk_slot, NULL,
+ RI_PLAN_CHECK_LOOKUPPK, false, false);
}
/*
@@ -2962,14 +2968,14 @@ ri_FastPathFlushLoop(RI_FastPathEntry *fpentry, TupleTableSlot *fk_slot,
*/
static void
ri_FastPathFlushArray(RI_FastPathEntry *fpentry, TupleTableSlot *fk_slot,
- const RI_ConstraintInfo *riinfo, Relation fk_rel)
+ const RI_ConstraintInfo *riinfo, Relation fk_rel,
+ Snapshot snapshot)
{
FastPathMeta *fpmeta = riinfo->fpmeta;
Relation pk_rel = fpentry->pk_rel;
Relation idx_rel = fpentry->idx_rel;
- IndexScanDesc scandesc = fpentry->scandesc;
TupleTableSlot *pk_slot = fpentry->pk_slot;
- Snapshot snapshot = fpentry->snapshot;
+ IndexScanDesc scandesc;
Datum search_vals[RI_FASTPATH_BATCH_SIZE];
bool matched[RI_FASTPATH_BATCH_SIZE];
int nvals = fpentry->batch_count;
@@ -2983,16 +2989,19 @@ ri_FastPathFlushArray(RI_FastPathEntry *fpentry, TupleTableSlot *fk_slot,
char elem_align;
ArrayType *arr;
- Assert(fpmeta);
-
- memset(matched, 0, nvals * sizeof(bool));
-
/*
* Transient per-flush allocations (cast results, the search array) must
* not accumulate across repeated flushes. Use the entry's short-lived
* flush context, reset after each flush.
*/
- MemoryContextSwitchTo(fpentry->flush_cxt);
+ MemoryContext oldcxt = MemoryContextSwitchTo(fpentry->flush_cxt);
+
+ Assert(fpmeta);
+
+ memset(matched, 0, nvals * sizeof(bool));
+
+ scandesc = index_beginscan(pk_rel, idx_rel, snapshot, NULL,
+ riinfo->nkeys, 0);
/*
* Extract FK values, casting to the operator's expected input type if
@@ -3103,6 +3112,11 @@ ri_FastPathFlushArray(RI_FastPathEntry *fpentry, TupleTableSlot *fk_slot,
}
}
+ index_endscan(scandesc);
+
+ MemoryContextReset(fpentry->flush_cxt);
+ MemoryContextSwitchTo(oldcxt);
+
/* Report first unmatched row */
for (int i = 0; i < nvals; i++)
{
@@ -3114,8 +3128,6 @@ ri_FastPathFlushArray(RI_FastPathEntry *fpentry, TupleTableSlot *fk_slot,
RI_PLAN_CHECK_LOOKUPPK, false, false);
}
}
-
- MemoryContextReset(fpentry->flush_cxt);
}
/*
@@ -4106,9 +4118,6 @@ ri_FastPathTeardown(void)
hash_seq_init(&status, ri_fastpath_cache);
while ((entry = hash_seq_search(&status)) != NULL)
{
- /* Close both scans before closing idx_rel. */
- if (entry->scandesc)
- index_endscan(entry->scandesc);
if (entry->idx_rel)
index_close(entry->idx_rel, NoLock);
if (entry->pk_rel)
@@ -4117,8 +4126,6 @@ ri_FastPathTeardown(void)
ExecDropSingleTupleTableSlot(entry->pk_slot);
if (entry->fk_slot)
ExecDropSingleTupleTableSlot(entry->fk_slot);
- if (entry->snapshot)
- UnregisterSnapshot(entry->snapshot);
if (entry->scan_cxt)
MemoryContextDelete(entry->scan_cxt);
}
@@ -4232,21 +4239,10 @@ ri_FastPathGetEntry(const RI_ConstraintInfo *riinfo, Relation fk_rel)
entry->pk_rel = table_open(riinfo->pk_relid, RowShareLock);
entry->idx_rel = index_open(riinfo->conindid, AccessShareLock);
- /*
- * Register an initial snapshot. Its curcid will be patched in place
- * on each subsequent row (see ri_FastPathBatchFlush()), avoiding
- * per-row GetSnapshotData() overhead.
- */
- entry->snapshot = RegisterSnapshot(GetTransactionSnapshot());
-
entry->pk_slot = table_slot_create(entry->pk_rel, NULL);
entry->fk_slot = MakeSingleTupleTableSlot(RelationGetDescr(fk_rel),
&TTSOpsHeapTuple);
- entry->scandesc = index_beginscan(entry->pk_rel, entry->idx_rel,
- entry->snapshot, NULL,
- riinfo->nkeys, 0);
-
entry->scan_cxt = AllocSetContextCreate(TopTransactionContext,
"RI fast path scan context",
ALLOCSET_DEFAULT_SIZES);