From b98a8b002a0fddbbd665a55abcc820273a88b0f3 Mon Sep 17 00:00:00 2001 From: Hari Babu Kommi Date: Fri, 14 Jul 2017 22:13:09 +1000 Subject: [PATCH] WIP tuple replace with slot --- contrib/dblink/dblink.c | 38 ++-- contrib/lo/lo.c | 24 +-- contrib/spi/autoinc.c | 16 +- contrib/spi/insert_username.c | 10 +- contrib/spi/moddatetime.c | 9 +- contrib/spi/refint.c | 40 ++-- contrib/spi/timetravel.c | 40 ++-- contrib/tablefunc/tablefunc.c | 34 ++-- contrib/tcn/tcn.c | 6 +- contrib/xml2/xpath.c | 8 +- src/backend/bootstrap/bootstrap.c | 4 +- src/backend/catalog/aclchk.c | 12 +- src/backend/catalog/index.c | 4 +- src/backend/catalog/pg_conversion.c | 2 +- src/backend/catalog/pg_db_role_setting.c | 2 +- src/backend/catalog/pg_publication.c | 2 +- src/backend/catalog/pg_subscription.c | 2 +- src/backend/commands/constraint.c | 14 +- src/backend/commands/copy.c | 27 ++- src/backend/commands/dbcommands.c | 1 + src/backend/commands/indexcmds.c | 2 +- src/backend/commands/matview.c | 2 +- src/backend/commands/tablecmds.c | 14 +- src/backend/commands/trigger.c | 334 +++++++++++++++++-------------- src/backend/executor/execReplication.c | 7 +- src/backend/executor/execTuples.c | 60 ++++++ src/backend/executor/nodeModifyTable.c | 57 ++++-- src/backend/executor/spi.c | 92 +++++++-- src/backend/replication/logical/worker.c | 1 + src/backend/utils/adt/ri_triggers.c | 230 ++++++++++----------- src/backend/utils/adt/ruleutils.c | 50 +++-- src/backend/utils/adt/trigfuncs.c | 4 +- src/backend/utils/adt/tsquery_rewrite.c | 4 +- src/backend/utils/adt/tsvector_op.c | 26 ++- src/backend/utils/adt/xml.c | 2 - src/include/access/htup.h | 1 + src/include/commands/trigger.h | 26 ++- src/include/executor/spi.h | 8 +- src/include/executor/tuptable.h | 6 + src/pl/plperl/plperl.c | 20 +- src/pl/plpgsql/src/pl_comp.c | 2 +- src/pl/plpgsql/src/pl_exec.c | 102 ++++------ src/pl/plpgsql/src/plpgsql.h | 2 +- src/pl/plpython/plpy_exec.c | 14 +- src/pl/tcl/pltcl.c | 10 +- src/test/modules/worker_spi/worker_spi.c | 2 - src/test/regress/regress.c | 55 +++-- 47 files changed, 779 insertions(+), 649 deletions(-) diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index 81136b1..cad2039 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -107,7 +107,7 @@ static char *get_sql_delete(Relation rel, int *pkattnums, int pknumatts, char ** static char *get_sql_update(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals, char **tgt_pkattvals); static char *quote_ident_cstr(char *rawstr); static int get_attnum_pk_pos(int *pkattnums, int pknumatts, int key); -static HeapTuple get_tuple_of_interest(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals); +static TupleTableSlot* get_tuple_of_interest(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals); static Relation get_rel_from_relname(text *relname_text, LOCKMODE lockmode, AclMode aclmode); static char *generate_relation_name(Relation rel); static void dblink_connstr_check(const char *connstr); @@ -2144,7 +2144,7 @@ static char * get_sql_insert(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals, char **tgt_pkattvals) { char *relname; - HeapTuple tuple; + TupleTableSlot *slot; TupleDesc tupdesc; int natts; StringInfoData buf; @@ -2158,15 +2158,15 @@ get_sql_insert(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals /* get relation name including any needed schema prefix and quoting */ relname = generate_relation_name(rel); - tupdesc = rel->rd_att; - natts = tupdesc->natts; - - tuple = get_tuple_of_interest(rel, pkattnums, pknumatts, src_pkattvals); - if (!tuple) + slot = get_tuple_of_interest(rel, pkattnums, pknumatts, src_pkattvals); + if (!slot) ereport(ERROR, (errcode(ERRCODE_CARDINALITY_VIOLATION), errmsg("source row not found"))); + tupdesc = slot->tts_tupleDescriptor; + natts = tupdesc->natts; + appendStringInfo(&buf, "INSERT INTO %s(", relname); needComma = false; @@ -2202,7 +2202,7 @@ get_sql_insert(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals if (key >= 0) val = tgt_pkattvals[key] ? pstrdup(tgt_pkattvals[key]) : NULL; else - val = SPI_getvalue(tuple, tupdesc, i + 1); + val = SPI_getvalue(slot, i + 1); if (val != NULL) { @@ -2258,7 +2258,7 @@ static char * get_sql_update(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals, char **tgt_pkattvals) { char *relname; - HeapTuple tuple; + TupleTableSlot *slot; TupleDesc tupdesc; int natts; StringInfoData buf; @@ -2272,15 +2272,15 @@ get_sql_update(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals /* get relation name including any needed schema prefix and quoting */ relname = generate_relation_name(rel); - tupdesc = rel->rd_att; - natts = tupdesc->natts; - - tuple = get_tuple_of_interest(rel, pkattnums, pknumatts, src_pkattvals); - if (!tuple) + slot = get_tuple_of_interest(rel, pkattnums, pknumatts, src_pkattvals); + if (!slot) ereport(ERROR, (errcode(ERRCODE_CARDINALITY_VIOLATION), errmsg("source row not found"))); + tupdesc = slot->tts_tupleDescriptor; + natts = tupdesc->natts; + appendStringInfo(&buf, "UPDATE %s SET ", relname); /* @@ -2303,7 +2303,7 @@ get_sql_update(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals if (key >= 0) val = tgt_pkattvals[key] ? pstrdup(tgt_pkattvals[key]) : NULL; else - val = SPI_getvalue(tuple, tupdesc, i + 1); + val = SPI_getvalue(slot, i + 1); if (val != NULL) { @@ -2372,7 +2372,7 @@ get_attnum_pk_pos(int *pkattnums, int pknumatts, int key) return -1; } -static HeapTuple +static TupleTableSlot * get_tuple_of_interest(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals) { char *relname; @@ -2380,7 +2380,7 @@ get_tuple_of_interest(Relation rel, int *pkattnums, int pknumatts, char **src_pk int natts; StringInfoData buf; int ret; - HeapTuple tuple; + TupleTableSlot *slot; int i; /* @@ -2456,10 +2456,10 @@ get_tuple_of_interest(Relation rel, int *pkattnums, int pknumatts, char **src_pk { SPITupleTable *tuptable = SPI_tuptable; - tuple = SPI_copytuple(tuptable->vals[0]); + slot = tuptable->vals[0]; SPI_finish(); - return tuple; + return slot; } else { diff --git a/contrib/lo/lo.c b/contrib/lo/lo.c index 4585923..432bedb 100644 --- a/contrib/lo/lo.c +++ b/contrib/lo/lo.c @@ -27,10 +27,10 @@ lo_manage(PG_FUNCTION_ARGS) int attnum; /* attribute number to monitor */ char **args; /* Args containing attr name */ TupleDesc tupdesc; /* Tuple Descriptor */ - HeapTuple rettuple; /* Tuple to be returned */ + TupleTableSlot* retslot; /* Tuple to be returned */ bool isdelete; /* are we deleting? */ - HeapTuple newtuple; /* The new value for tuple */ - HeapTuple trigtuple; /* The original value of tuple */ + TupleTableSlot* newslot; /* The new value for tuple */ + TupleTableSlot* trigslot; /* The original value of tuple */ if (!CALLED_AS_TRIGGER(fcinfo)) /* internal error */ elog(ERROR, "%s: not fired by trigger manager", @@ -43,8 +43,8 @@ lo_manage(PG_FUNCTION_ARGS) /* * Fetch some values from trigdata */ - newtuple = trigdata->tg_newtuple; - trigtuple = trigdata->tg_trigtuple; + newslot = trigdata->tg_newslot; + trigslot = trigdata->tg_trigslot; tupdesc = trigdata->tg_relation->rd_att; args = trigdata->tg_trigger->tgargs; @@ -54,9 +54,9 @@ lo_manage(PG_FUNCTION_ARGS) /* tuple to return to Executor */ if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) - rettuple = newtuple; + retslot = newslot; else - rettuple = trigtuple; + retslot = trigslot; /* Are we deleting the row? */ isdelete = TRIGGER_FIRED_BY_DELETE(trigdata->tg_event); @@ -74,10 +74,10 @@ lo_manage(PG_FUNCTION_ARGS) * Here, if the value of the monitored attribute changes, then the large * object associated with the original value is unlinked. */ - if (newtuple != NULL) + if (newslot != NULL) { - char *orig = SPI_getvalue(trigtuple, tupdesc, attnum); - char *newv = SPI_getvalue(newtuple, tupdesc, attnum); + char *orig = SPI_getvalue(trigslot, attnum); + char *newv = SPI_getvalue(newslot, attnum); if (orig != NULL && (newv == NULL || strcmp(orig, newv) != 0)) DirectFunctionCall1(be_lo_unlink, @@ -96,7 +96,7 @@ lo_manage(PG_FUNCTION_ARGS) */ if (isdelete) { - char *orig = SPI_getvalue(trigtuple, tupdesc, attnum); + char *orig = SPI_getvalue(trigslot, attnum); if (orig != NULL) { @@ -107,5 +107,5 @@ lo_manage(PG_FUNCTION_ARGS) } } - return PointerGetDatum(rettuple); + return PointerGetDatum(retslot->tts_storageam->slot_get_tuple(retslot)); } diff --git a/contrib/spi/autoinc.c b/contrib/spi/autoinc.c index 8bf7422..b4a207e 100644 --- a/contrib/spi/autoinc.c +++ b/contrib/spi/autoinc.c @@ -28,7 +28,7 @@ autoinc(PG_FUNCTION_ARGS) char **args; /* arguments */ char *relname; /* triggered relation name */ Relation rel; /* triggered relation */ - HeapTuple rettuple = NULL; + TupleTableSlot *retslot = NULL; TupleDesc tupdesc; /* tuple description */ bool isnull; int i; @@ -44,9 +44,9 @@ autoinc(PG_FUNCTION_ARGS) elog(ERROR, "must be fired before event"); if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) - rettuple = trigdata->tg_trigtuple; + retslot = trigdata->tg_trigslot; else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) - rettuple = trigdata->tg_newtuple; + retslot = trigdata->tg_newslot; else /* internal error */ elog(ERROR, "cannot process DELETE events"); @@ -86,7 +86,7 @@ autoinc(PG_FUNCTION_ARGS) errmsg("attribute \"%s\" of \"%s\" must be type INT4", args[i], relname))); - val = DatumGetInt32(SPI_getbinval(rettuple, tupdesc, attnum, &isnull)); + val = DatumGetInt32(SPI_getbinval(retslot, attnum, &isnull)); if (!isnull && val != 0) { @@ -113,9 +113,9 @@ autoinc(PG_FUNCTION_ARGS) if (chnattrs > 0) { - rettuple = heap_modify_tuple_by_cols(rettuple, tupdesc, - chnattrs, chattrs, - newvals, newnulls); + retslot = heap_modify_slot_by_cols(retslot, + chnattrs, chattrs, + newvals, newnulls); } pfree(relname); @@ -123,5 +123,5 @@ autoinc(PG_FUNCTION_ARGS) pfree(newvals); pfree(newnulls); - return PointerGetDatum(rettuple); + return PointerGetDatum(retslot->tts_tuple); } diff --git a/contrib/spi/insert_username.c b/contrib/spi/insert_username.c index a2e1747..f3093ed 100644 --- a/contrib/spi/insert_username.c +++ b/contrib/spi/insert_username.c @@ -29,7 +29,7 @@ insert_username(PG_FUNCTION_ARGS) char **args; /* arguments */ char *relname; /* triggered relation name */ Relation rel; /* triggered relation */ - HeapTuple rettuple = NULL; + TupleTableSlot *retslot; TupleDesc tupdesc; /* tuple description */ int attnum; @@ -45,9 +45,9 @@ insert_username(PG_FUNCTION_ARGS) elog(ERROR, "insert_username: must be fired before event"); if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) - rettuple = trigdata->tg_trigtuple; + retslot = trigdata->tg_trigslot; else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) - rettuple = trigdata->tg_newtuple; + retslot = trigdata->tg_newslot; else /* internal error */ elog(ERROR, "insert_username: cannot process DELETE events"); @@ -83,10 +83,10 @@ insert_username(PG_FUNCTION_ARGS) newnull = false; /* construct new tuple */ - rettuple = heap_modify_tuple_by_cols(rettuple, tupdesc, + retslot = heap_modify_slot_by_cols(retslot, 1, &attnum, &newval, &newnull); pfree(relname); - return PointerGetDatum(rettuple); + return PointerGetDatum(retslot->tts_tuple); } diff --git a/contrib/spi/moddatetime.c b/contrib/spi/moddatetime.c index 70476f7..2ab74a7 100644 --- a/contrib/spi/moddatetime.c +++ b/contrib/spi/moddatetime.c @@ -39,7 +39,7 @@ moddatetime(PG_FUNCTION_ARGS) char **args; /* arguments */ char *relname; /* triggered relation name */ Relation rel; /* triggered relation */ - HeapTuple rettuple = NULL; + TupleTableSlot *slot; TupleDesc tupdesc; /* tuple description */ if (!CALLED_AS_TRIGGER(fcinfo)) @@ -58,7 +58,7 @@ moddatetime(PG_FUNCTION_ARGS) /* internal error */ elog(ERROR, "moddatetime: cannot process INSERT events"); else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) - rettuple = trigdata->tg_newtuple; + slot = trigdata->tg_newslot; else /* internal error */ elog(ERROR, "moddatetime: cannot process DELETE events"); @@ -120,11 +120,10 @@ moddatetime(PG_FUNCTION_ARGS) newdtnull = false; /* Replace the attnum'th column with newdt */ - rettuple = heap_modify_tuple_by_cols(rettuple, tupdesc, - 1, &attnum, &newdt, &newdtnull); + slot = heap_modify_slot_by_cols(slot, 1, &attnum, &newdt, &newdtnull); /* Clean up */ pfree(relname); - return PointerGetDatum(rettuple); + return PointerGetDatum(slot->tts_tuple); } diff --git a/contrib/spi/refint.c b/contrib/spi/refint.c index 46205c7..0d87f59 100644 --- a/contrib/spi/refint.c +++ b/contrib/spi/refint.c @@ -53,7 +53,7 @@ check_primary_key(PG_FUNCTION_ARGS) Datum *kvals; /* key values */ char *relname; /* referenced relation name */ Relation rel; /* triggered relation */ - HeapTuple tuple = NULL; /* tuple to return */ + TupleTableSlot *slot = NULL; /* tuple to return */ TupleDesc tupdesc; /* tuple description */ EPlan *plan; /* prepared plan */ Oid *argtypes = NULL; /* key types to prepare execution plan */ @@ -82,7 +82,7 @@ check_primary_key(PG_FUNCTION_ARGS) /* If INSERTion then must check Tuple to being inserted */ if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) - tuple = trigdata->tg_trigtuple; + slot = trigdata->tg_trigslot; /* Not should be called for DELETE */ else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) @@ -91,7 +91,7 @@ check_primary_key(PG_FUNCTION_ARGS) /* If UPDATE, then must check new Tuple, not old one */ else - tuple = trigdata->tg_newtuple; + slot = trigdata->tg_newslot; trigger = trigdata->tg_trigger; nargs = trigger->tgnargs; @@ -142,7 +142,7 @@ check_primary_key(PG_FUNCTION_ARGS) args[i], SPI_getrelname(rel)))); /* Well, get binary (in internal format) value of column */ - kvals[i] = SPI_getbinval(tuple, tupdesc, fnumber, &isnull); + kvals[i] = SPI_getbinval(slot, fnumber, &isnull); /* * If it's NULL then nothing to do! DON'T FORGET call SPI_finish ()! @@ -152,7 +152,7 @@ check_primary_key(PG_FUNCTION_ARGS) if (isnull) { SPI_finish(); - return PointerGetDatum(tuple); + return PointerGetDatum(slot->tts_tuple); } if (plan->nplans <= 0) /* Get typeId of column */ @@ -217,7 +217,7 @@ check_primary_key(PG_FUNCTION_ARGS) SPI_finish(); - return PointerGetDatum(tuple); + return PointerGetDatum(slot->tts_tuple); } /* @@ -248,8 +248,8 @@ check_foreign_key(PG_FUNCTION_ARGS) Datum *kvals; /* key values */ char *relname; /* referencing relation name */ Relation rel; /* triggered relation */ - HeapTuple trigtuple = NULL; /* tuple to being changed */ - HeapTuple newtuple = NULL; /* tuple to return */ + TupleTableSlot* trigslot = NULL; /* tuple to being changed */ + TupleTableSlot* newslot = NULL; /* tuple to return */ TupleDesc tupdesc; /* tuple description */ EPlan *plan; /* prepared plan(s) */ Oid *argtypes = NULL; /* key types to prepare execution plan */ @@ -285,7 +285,7 @@ check_foreign_key(PG_FUNCTION_ARGS) elog(ERROR, "check_foreign_key: cannot process INSERT events"); /* Have to check tg_trigtuple - tuple being deleted */ - trigtuple = trigdata->tg_trigtuple; + trigslot = trigdata->tg_trigslot; /* * But if this is UPDATE then we have to return tg_newtuple. Also, if key @@ -294,7 +294,7 @@ check_foreign_key(PG_FUNCTION_ARGS) is_update = 0; if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) { - newtuple = trigdata->tg_newtuple; + newslot = trigdata->tg_newslot; is_update = 1; } trigger = trigdata->tg_trigger; @@ -369,7 +369,7 @@ check_foreign_key(PG_FUNCTION_ARGS) args[i], SPI_getrelname(rel)))); /* Well, get binary (in internal format) value of column */ - kvals[i] = SPI_getbinval(trigtuple, tupdesc, fnumber, &isnull); + kvals[i] = SPI_getbinval(trigslot, fnumber, &isnull); /* * If it's NULL then nothing to do! DON'T FORGET call SPI_finish ()! @@ -379,7 +379,8 @@ check_foreign_key(PG_FUNCTION_ARGS) if (isnull) { SPI_finish(); - return PointerGetDatum((newtuple == NULL) ? trigtuple : newtuple); + return PointerGetDatum((newslot == NULL) ? + trigslot->tts_tuple : newslot->tts_tuple); } /* @@ -387,16 +388,16 @@ check_foreign_key(PG_FUNCTION_ARGS) * compare is this the same as old one. For the moment we use string * presentation of values... */ - if (newtuple != NULL) + if (newslot != NULL) { - char *oldval = SPI_getvalue(trigtuple, tupdesc, fnumber); + char *oldval = SPI_getvalue(trigslot, fnumber); char *newval; /* this shouldn't happen! SPI_ERROR_NOOUTFUNC ? */ if (oldval == NULL) /* internal error */ elog(ERROR, "check_foreign_key: SPI_getvalue returned %d", SPI_result); - newval = SPI_getvalue(newtuple, tupdesc, fnumber); + newval = SPI_getvalue(newslot, fnumber); if (newval == NULL || strcmp(oldval, newval) != 0) isequal = false; } @@ -470,7 +471,7 @@ check_foreign_key(PG_FUNCTION_ARGS) fn = SPI_fnumber(tupdesc, args_temp[k - 1]); Assert(fn > 0); /* already checked above */ - nv = SPI_getvalue(newtuple, tupdesc, fn); + nv = SPI_getvalue(newslot, fn); type = SPI_gettype(tupdesc, fn); if ((strcmp(type, "text") && strcmp(type, "varchar") && @@ -552,10 +553,10 @@ check_foreign_key(PG_FUNCTION_ARGS) /* * If UPDATE and key is not changed ... */ - if (newtuple != NULL && isequal) + if (newslot != NULL && isequal) { SPI_finish(); - return PointerGetDatum(newtuple); + return PointerGetDatum(newslot->tts_tuple); } /* @@ -604,7 +605,8 @@ check_foreign_key(PG_FUNCTION_ARGS) SPI_finish(); - return PointerGetDatum((newtuple == NULL) ? trigtuple : newtuple); + return PointerGetDatum((newslot == NULL) ? + trigslot->tts_tuple : newslot->tts_tuple); } static EPlan * diff --git a/contrib/spi/timetravel.c b/contrib/spi/timetravel.c index f7905e2..2127cd6 100644 --- a/contrib/spi/timetravel.c +++ b/contrib/spi/timetravel.c @@ -96,8 +96,8 @@ timetravel(PG_FUNCTION_ARGS) char *cnulls; /* column nulls */ char *relname; /* triggered relation name */ Relation rel; /* triggered relation */ - HeapTuple trigtuple; - HeapTuple newtuple = NULL; + TupleTableSlot *trigslot; + TupleTableSlot *newslot = NULL; HeapTuple rettuple; TupleDesc tupdesc; /* tuple description */ int natts; /* # of attributes */ @@ -129,9 +129,9 @@ timetravel(PG_FUNCTION_ARGS) isinsert = true; if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) - newtuple = trigdata->tg_newtuple; + newslot = trigdata->tg_newslot; - trigtuple = trigdata->tg_trigtuple; + trigslot = trigdata->tg_trigslot; rel = trigdata->tg_relation; relname = SPI_getrelname(rel); @@ -141,7 +141,8 @@ timetravel(PG_FUNCTION_ARGS) { /* OFF - nothing to do */ pfree(relname); - return PointerGetDatum((newtuple != NULL) ? newtuple : trigtuple); + return PointerGetDatum((newslot != NULL) ? + newslot->tts_tuple : trigslot->tts_tuple); } trigger = trigdata->tg_trigger; @@ -186,7 +187,7 @@ timetravel(PG_FUNCTION_ARGS) Datum newvals[MaxAttrNum]; bool newnulls[MaxAttrNum]; - oldtimeon = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_on], &isnull); + oldtimeon = SPI_getbinval(trigslot, attnum[a_time_on], &isnull); if (isnull) { newvals[chnattrs] = GetCurrentAbsoluteTime(); @@ -195,7 +196,7 @@ timetravel(PG_FUNCTION_ARGS) chnattrs++; } - oldtimeoff = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_off], &isnull); + oldtimeoff = SPI_getbinval(trigslot, attnum[a_time_off], &isnull); if (isnull) { if ((chnattrs == 0 && DatumGetInt32(oldtimeon) >= NOEND_ABSTIME) || @@ -215,7 +216,7 @@ timetravel(PG_FUNCTION_ARGS) pfree(relname); if (chnattrs <= 0) - return PointerGetDatum(trigtuple); + return PointerGetDatum(trigslot->tts_tuple); if (argc == MaxAttrNum) { @@ -235,7 +236,8 @@ timetravel(PG_FUNCTION_ARGS) chattrs[chnattrs] = attnum[a_ins_user]; chnattrs++; } - rettuple = heap_modify_tuple_by_cols(trigtuple, tupdesc, + rettuple = heap_modify_tuple_by_cols(trigslot->tts_tuple, + tupdesc, chnattrs, chattrs, newvals, newnulls); return PointerGetDatum(rettuple); @@ -243,11 +245,11 @@ timetravel(PG_FUNCTION_ARGS) } /* UPDATE/DELETE: */ - oldtimeon = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_on], &isnull); + oldtimeon = SPI_getbinval(trigslot, attnum[a_time_on], &isnull); if (isnull) elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_on]); - oldtimeoff = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_off], &isnull); + oldtimeoff = SPI_getbinval(trigslot, attnum[a_time_off], &isnull); if (isnull) elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_off]); @@ -255,13 +257,13 @@ timetravel(PG_FUNCTION_ARGS) * If DELETE/UPDATE of tuple with stop_date neq INFINITY then say upper * Executor to skip operation for this tuple */ - if (newtuple != NULL) + if (newslot != NULL) { /* UPDATE */ - newtimeon = SPI_getbinval(newtuple, tupdesc, attnum[a_time_on], &isnull); + newtimeon = SPI_getbinval(newslot, attnum[a_time_on], &isnull); if (isnull) elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_on]); - newtimeoff = SPI_getbinval(newtuple, tupdesc, attnum[a_time_off], &isnull); + newtimeoff = SPI_getbinval(newslot, attnum[a_time_off], &isnull); if (isnull) elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_off]); @@ -286,7 +288,7 @@ timetravel(PG_FUNCTION_ARGS) cnulls = (char *) palloc(natts * sizeof(char)); for (i = 0; i < natts; i++) { - cvals[i] = SPI_getbinval(trigtuple, tupdesc, i + 1, &isnull); + cvals[i] = SPI_getbinval(trigslot, i + 1, &isnull); cnulls[i] = (isnull) ? 'n' : ' '; } @@ -294,7 +296,7 @@ timetravel(PG_FUNCTION_ARGS) cvals[attnum[a_time_off] - 1] = newtimeoff; /* stop_date eq current date */ cnulls[attnum[a_time_off] - 1] = ' '; - if (!newtuple) + if (!newslot) { /* DELETE */ if (argc == MaxAttrNum) { @@ -362,7 +364,7 @@ timetravel(PG_FUNCTION_ARGS) elog(ERROR, "timetravel (%s): SPI_execp returned %d", relname, ret); /* Tuple to return to upper Executor ... */ - if (newtuple) + if (newslot) { /* UPDATE */ int chnattrs = 0; int chattrs[MaxAttrNum]; @@ -402,11 +404,11 @@ timetravel(PG_FUNCTION_ARGS) * Use SPI_modifytuple() here because we are inside SPI environment * but rettuple must be allocated in caller's context. */ - rettuple = SPI_modifytuple(rel, newtuple, chnattrs, chattrs, newvals, newnulls); + rettuple = SPI_modifytuple(rel, newslot->tts_tuple, chnattrs, chattrs, newvals, newnulls); } else /* DELETE case */ - rettuple = trigtuple; + rettuple = trigslot->tts_tuple; SPI_finish(); /* don't forget say Bye to SPI mgr */ diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c index 0bc8177..cd11947 100644 --- a/contrib/tablefunc/tablefunc.c +++ b/contrib/tablefunc/tablefunc.c @@ -492,7 +492,7 @@ crosstab(PG_FUNCTION_ARGS) */ for (i = 0; i < num_categories; i++) { - HeapTuple spi_tuple; + TupleTableSlot* spislot; char *rowid; /* see if we've gone too far already */ @@ -500,10 +500,10 @@ crosstab(PG_FUNCTION_ARGS) break; /* get the next sql result tuple */ - spi_tuple = spi_tuptable->vals[call_cntr]; + spislot = spi_tuptable->vals[call_cntr]; /* get the rowid from the current sql result tuple */ - rowid = SPI_getvalue(spi_tuple, spi_tupdesc, 1); + rowid = SPI_getvalue(spislot, 1); /* * If this is the first pass through the values for this rowid, @@ -538,7 +538,7 @@ crosstab(PG_FUNCTION_ARGS) * Be careful to assign the value to the array index based on * which category we are presently processing. */ - values[1 + i] = SPI_getvalue(spi_tuple, spi_tupdesc, 3); + values[1 + i] = SPI_getvalue(spislot, 3); /* * increment the counter since we consume a row for each @@ -756,13 +756,13 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx) { crosstab_cat_desc *catdesc; char *catname; - HeapTuple spi_tuple; + TupleTableSlot* spislot; /* get the next sql result tuple */ - spi_tuple = spi_tuptable->vals[i]; + spislot = spi_tuptable->vals[i]; /* get the category from the current sql result tuple */ - catname = SPI_getvalue(spi_tuple, spi_tupdesc, 1); + catname = SPI_getvalue(spislot, 1); SPIcontext = MemoryContextSwitchTo(per_query_ctx); @@ -875,15 +875,15 @@ get_crosstab_tuplestore(char *sql, for (i = 0; i < proc; i++) { - HeapTuple spi_tuple; + TupleTableSlot* spislot; crosstab_cat_desc *catdesc; char *catname; /* get the next sql result tuple */ - spi_tuple = spi_tuptable->vals[i]; + spislot = spi_tuptable->vals[i]; /* get the rowid from the current sql result tuple */ - rowid = SPI_getvalue(spi_tuple, spi_tupdesc, 1); + rowid = SPI_getvalue(spislot, 1); /* * if we're on a new output row, grab the column values up to @@ -908,14 +908,14 @@ get_crosstab_tuplestore(char *sql, values[0] = rowid; for (j = 1; j < ncols - 2; j++) - values[j] = SPI_getvalue(spi_tuple, spi_tupdesc, j + 1); + values[j] = SPI_getvalue(spislot, j + 1); /* we're no longer on the first pass */ firstpass = false; } /* look up the category and fill in the appropriate column */ - catname = SPI_getvalue(spi_tuple, spi_tupdesc, ncols - 1); + catname = SPI_getvalue(spislot, ncols - 1); if (catname != NULL) { @@ -923,7 +923,7 @@ get_crosstab_tuplestore(char *sql, if (catdesc) values[catdesc->attidx + ncols - 2] = - SPI_getvalue(spi_tuple, spi_tupdesc, ncols); + SPI_getvalue(spislot, ncols); } xpfree(lastrowid); @@ -1310,7 +1310,7 @@ build_tuplestore_recursively(char *key_fld, /* Check for qualifying tuples */ if ((ret == SPI_OK_SELECT) && (proc > 0)) { - HeapTuple spi_tuple; + TupleTableSlot* spislot; SPITupleTable *tuptable = SPI_tuptable; TupleDesc spi_tupdesc = tuptable->tupdesc; uint64 i; @@ -1335,13 +1335,13 @@ build_tuplestore_recursively(char *key_fld, appendStringInfo(&chk_branchstr, "%s%s%s", branch_delim, branch, branch_delim); /* get the next sql result tuple */ - spi_tuple = tuptable->vals[i]; + spislot = tuptable->vals[i]; /* get the current key (might be NULL) */ - current_key = SPI_getvalue(spi_tuple, spi_tupdesc, 1); + current_key = SPI_getvalue(spislot, 1); /* get the parent key (might be NULL) */ - current_key_parent = SPI_getvalue(spi_tuple, spi_tupdesc, 2); + current_key_parent = SPI_getvalue(spislot, 2); /* get the current level */ sprintf(current_level, "%d", level); diff --git a/contrib/tcn/tcn.c b/contrib/tcn/tcn.c index 0b9acbf..c311a3b 100644 --- a/contrib/tcn/tcn.c +++ b/contrib/tcn/tcn.c @@ -58,7 +58,7 @@ triggered_change_notification(PG_FUNCTION_ARGS) TriggerData *trigdata = (TriggerData *) fcinfo->context; Trigger *trigger; int nargs; - HeapTuple trigtuple; + TupleTableSlot* trigslot; Relation rel; TupleDesc tupdesc; char *channel; @@ -112,7 +112,7 @@ triggered_change_notification(PG_FUNCTION_ARGS) channel = trigger->tgargs[0]; /* get tuple data */ - trigtuple = trigdata->tg_trigtuple; + trigslot = trigdata->tg_trigslot; rel = trigdata->tg_relation; tupdesc = rel->rd_att; @@ -157,7 +157,7 @@ triggered_change_notification(PG_FUNCTION_ARGS) appendStringInfoCharMacro(payload, ','); strcpy_quoted(payload, NameStr((tupdesc->attrs[colno - 1])->attname), '"'); appendStringInfoCharMacro(payload, '='); - strcpy_quoted(payload, SPI_getvalue(trigtuple, tupdesc, colno), '\''); + strcpy_quoted(payload, SPI_getvalue(trigslot, colno), '\''); } Async_Notify(channel, payload->data); diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 95e580d..b344d1f 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -533,7 +533,7 @@ xpath_table(PG_FUNCTION_ARGS) /* SPI (input tuple) support */ SPITupleTable *tuptable; - HeapTuple spi_tuple; + TupleTableSlot* spislot; TupleDesc spi_tupdesc; /* Output tuple (tuplestore) support */ @@ -702,9 +702,9 @@ xpath_table(PG_FUNCTION_ARGS) xmlXPathCompExprPtr comppath; /* Extract the row data as C Strings */ - spi_tuple = tuptable->vals[i]; - pkey = SPI_getvalue(spi_tuple, spi_tupdesc, 1); - xmldoc = SPI_getvalue(spi_tuple, spi_tupdesc, 2); + spislot = tuptable->vals[i]; + pkey = SPI_getvalue(spislot, 1); + xmldoc = SPI_getvalue(spislot, 2); /* * Clear the values array, so that not-well-formed documents diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index b3f0b3c..d09a0fa 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -564,7 +564,7 @@ boot_openrel(char *relname) struct typmap **app; Relation rel; HeapScanDesc scan; - HeapTuple tup; + HeapTuple tup; if (strlen(relname) >= NAMEDATALEN) relname[NAMEDATALEN - 1] = '\0'; @@ -880,7 +880,7 @@ gettype(char *type) int i; Relation rel; HeapScanDesc scan; - HeapTuple tup; + HeapTuple tup; struct typmap **app; if (Typ != NULL) diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index ccde66a..38a1d06 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -789,7 +789,7 @@ objectsInSchemaToOids(GrantObjectType objtype, List *nspnames) ScanKeyData key[1]; Relation rel; HeapScanDesc scan; - HeapTuple tuple; + HeapTuple tup; ScanKeyInit(&key[0], Anum_pg_proc_pronamespace, @@ -799,9 +799,9 @@ objectsInSchemaToOids(GrantObjectType objtype, List *nspnames) rel = heap_open(ProcedureRelationId, AccessShareLock); scan = heap_beginscan_catalog(rel, 1, key); - while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL) { - objects = lappend_oid(objects, HeapTupleGetOid(tuple)); + objects = lappend_oid(objects, HeapTupleGetOid(tup)); } heap_endscan(scan); @@ -830,7 +830,7 @@ getRelationsInNamespace(Oid namespaceId, char relkind) ScanKeyData key[2]; Relation rel; HeapScanDesc scan; - HeapTuple tuple; + HeapTuple tup; ScanKeyInit(&key[0], Anum_pg_class_relnamespace, @@ -844,9 +844,9 @@ getRelationsInNamespace(Oid namespaceId, char relkind) rel = heap_open(RelationRelationId, AccessShareLock); scan = heap_beginscan_catalog(rel, 2, key); - while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL) { - relations = lappend_oid(relations, HeapTupleGetOid(tuple)); + relations = lappend_oid(relations, HeapTupleGetOid(tup)); } heap_endscan(scan); diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 027abd5..5f807ae 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -2641,11 +2641,11 @@ IndexCheckExclusion(Relation heapRelation, IndexInfo *indexInfo) { HeapScanDesc scan; - HeapTuple heapTuple; Datum values[INDEX_MAX_KEYS]; bool isnull[INDEX_MAX_KEYS]; ExprState *predicate; TupleTableSlot *slot; + HeapTuple heapTuple; EState *estate; ExprContext *econtext; Snapshot snapshot; @@ -2715,7 +2715,7 @@ IndexCheckExclusion(Relation heapRelation, */ check_exclusion_constraint(heapRelation, indexRelation, indexInfo, - &(heapTuple->t_self), values, isnull, + &(slot->tts_tid), values, isnull, estate, true); } diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c index 5746dc3..5fbef3f 100644 --- a/src/backend/catalog/pg_conversion.c +++ b/src/backend/catalog/pg_conversion.c @@ -149,7 +149,7 @@ void RemoveConversionById(Oid conversionOid) { Relation rel; - HeapTuple tuple; + HeapTuple tuple; HeapScanDesc scan; ScanKeyData scanKeyData; diff --git a/src/backend/catalog/pg_db_role_setting.c b/src/backend/catalog/pg_db_role_setting.c index 323471b..52e0de7 100644 --- a/src/backend/catalog/pg_db_role_setting.c +++ b/src/backend/catalog/pg_db_role_setting.c @@ -172,7 +172,7 @@ DropSetting(Oid databaseid, Oid roleid) Relation relsetting; HeapScanDesc scan; ScanKeyData keys[2]; - HeapTuple tup; + HeapTuple tup; int numkeys = 0; relsetting = heap_open(DbRoleSettingRelationId, RowExclusiveLock); diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index 3ef7ba8..59abef4 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -314,7 +314,7 @@ GetAllTablesPublicationRelations(void) Relation classRel; ScanKeyData key[1]; HeapScanDesc scan; - HeapTuple tuple; + HeapTuple tuple; List *result = NIL; classRel = heap_open(RelationRelationId, AccessShareLock); diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c index fb53d71..a3eb79d 100644 --- a/src/backend/catalog/pg_subscription.c +++ b/src/backend/catalog/pg_subscription.c @@ -378,7 +378,7 @@ RemoveSubscriptionRel(Oid subid, Oid relid) Relation rel; HeapScanDesc scan; ScanKeyData skey[2]; - HeapTuple tup; + HeapTuple tup; int nkeys = 0; rel = heap_open(SubscriptionRelRelationId, RowExclusiveLock); diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c index e2544e5..02a8dc5 100644 --- a/src/backend/commands/constraint.c +++ b/src/backend/commands/constraint.c @@ -39,7 +39,7 @@ unique_key_recheck(PG_FUNCTION_ARGS) { TriggerData *trigdata = castNode(TriggerData, fcinfo->context); const char *funcname = "unique_key_recheck"; - HeapTuple new_row; + TupleTableSlot *newslot; ItemPointerData tmptid; Relation indexRel; IndexInfo *indexInfo; @@ -71,16 +71,16 @@ unique_key_recheck(PG_FUNCTION_ARGS) * Get the new data that was inserted/updated. */ if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) - new_row = trigdata->tg_trigtuple; + newslot = trigdata->tg_trigslot; else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) - new_row = trigdata->tg_newtuple; + newslot = trigdata->tg_newslot; else { ereport(ERROR, (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), errmsg("function \"%s\" must be fired for INSERT or UPDATE", funcname))); - new_row = NULL; /* keep compiler quiet */ + newslot = NULL; /* keep compiler quiet */ } /* @@ -101,7 +101,7 @@ unique_key_recheck(PG_FUNCTION_ARGS) * it's possible the index entry has also been marked dead, and even * removed. */ - tmptid = new_row->t_self; + tmptid = newslot->tts_tid; if (!heap_hot_search(&tmptid, trigdata->tg_relation, SnapshotSelf, NULL)) { /* @@ -124,7 +124,7 @@ unique_key_recheck(PG_FUNCTION_ARGS) */ slot = MakeSingleTupleTableSlot(RelationGetDescr(trigdata->tg_relation)); - ExecStoreTuple(new_row, slot, InvalidBuffer, false); + ExecCopySlot(slot, newslot); /* * Typically the index won't have expressions, but if it does we need an @@ -164,7 +164,7 @@ unique_key_recheck(PG_FUNCTION_ARGS) * correct even if t_self is now dead, because that is the TID the * index will know about. */ - index_insert(indexRel, values, isnull, &(new_row->t_self), + index_insert(indexRel, values, isnull, &tmptid, trigdata->tg_relation, UNIQUE_CHECK_EXISTING, indexInfo); } diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index fc5f4f6..5d3f22e 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -2068,13 +2068,9 @@ CopyTo(CopyState cstate) if (cstate->rel) { - Datum *values; - bool *nulls; HeapScanDesc scandesc; - HeapTuple tuple; - - values = (Datum *) palloc(num_phys_attrs * sizeof(Datum)); - nulls = (bool *) palloc(num_phys_attrs * sizeof(bool)); + HeapTuple tuple; + TupleTableSlot *slot = MakeSingleTupleTableSlot(RelationGetDescr(cstate->rel)); scandesc = heap_beginscan(cstate->rel, GetActiveSnapshot(), 0, NULL); @@ -2083,18 +2079,15 @@ CopyTo(CopyState cstate) { CHECK_FOR_INTERRUPTS(); - /* Deconstruct the tuple ... faster than repeated heap_getattr */ - heap_deform_tuple(tuple, tupDesc, values, nulls); + ExecStoreTuple(tuple, slot, InvalidBuffer, false); + slot_getallattrs(slot); /* Format and send the data */ - CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls); + CopyOneRowTo(cstate, HeapTupleGetOid(slot->tts_tuple), slot->tts_values, slot->tts_isnull); processed++; } heap_endscan(scandesc); - - pfree(values); - pfree(nulls); } else { @@ -2752,6 +2745,7 @@ CopyFrom(CopyState cstate) heap_insert(resultRelInfo->ri_RelationDesc, tuple, mycid, hi_options, bistate); + ItemPointerCopy(&(tuple->t_self), &(slot->tts_tid)); if (resultRelInfo->ri_NumIndices > 0) recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self), @@ -2761,7 +2755,7 @@ CopyFrom(CopyState cstate) NIL); /* AFTER ROW INSERT Triggers */ - ExecARInsertTriggers(estate, resultRelInfo, tuple, + ExecARInsertTriggers(estate, resultRelInfo, slot, recheckIndexes, cstate->transition_capture); list_free(recheckIndexes); @@ -2910,11 +2904,12 @@ CopyFromInsertBatch(CopyState cstate, EState *estate, CommandId mycid, cstate->cur_lineno = firstBufferedLineNo + i; ExecStoreTuple(bufferedTuples[i], myslot, InvalidBuffer, false); + ItemPointerCopy(&(bufferedTuples[i]->t_self), &(myslot->tts_tid)); recheckIndexes = ExecInsertIndexTuples(myslot, &(bufferedTuples[i]->t_self), estate, false, NULL, NIL); ExecARInsertTriggers(estate, resultRelInfo, - bufferedTuples[i], + myslot, recheckIndexes, cstate->transition_capture); list_free(recheckIndexes); } @@ -2931,8 +2926,10 @@ CopyFromInsertBatch(CopyState cstate, EState *estate, CommandId mycid, for (i = 0; i < nBufferedTuples; i++) { cstate->cur_lineno = firstBufferedLineNo + i; + ExecStoreTuple(bufferedTuples[i], myslot, InvalidBuffer, false); + ItemPointerCopy(&(bufferedTuples[i]->t_self), &(myslot->tts_tid)); ExecARInsertTriggers(estate, resultRelInfo, - bufferedTuples[i], + myslot, NIL, cstate->transition_capture); } } diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index e138539..e12c1db 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -590,6 +590,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt) * each one to the new database. */ rel = heap_open(TableSpaceRelationId, AccessShareLock); + scan = heap_beginscan_catalog(rel, 0, NULL); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 620704e..675b348 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -1876,7 +1876,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, Relation relationRelation; HeapScanDesc scan; ScanKeyData scan_keys[1]; - HeapTuple tuple; + HeapTuple tuple; MemoryContext private_context; MemoryContext old; List *relids = NIL; diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c index 7d57f97..062665e 100644 --- a/src/backend/commands/matview.c +++ b/src/backend/commands/matview.c @@ -678,7 +678,7 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner, errmsg("new data for materialized view \"%s\" contains duplicate rows without any null columns", RelationGetRelationName(matviewRel)), errdetail("Row: %s", - SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1)))); + SPI_getvalue(SPI_tuptable->vals[0], 1)))); } SetUserIdAndSecContext(relowner, diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index bb00858..c47a69f 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8090,7 +8090,6 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup) char *conbin; Expr *origexpr; ExprState *exprstate; - TupleDesc tupdesc; HeapScanDesc scan; HeapTuple tuple; ExprContext *econtext; @@ -8127,8 +8126,7 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup) exprstate = ExecPrepareExpr(origexpr, estate); econtext = GetPerTupleExprContext(estate); - tupdesc = RelationGetDescr(rel); - slot = MakeSingleTupleTableSlot(tupdesc); + slot = MakeSingleTupleTableSlot(RelationGetDescr(rel)); econtext->ecxt_scantuple = slot; snapshot = RegisterSnapshot(GetLatestSnapshot()); @@ -8157,7 +8155,6 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup) MemoryContextSwitchTo(oldcxt); heap_endscan(scan); UnregisterSnapshot(snapshot); - ExecDropSingleTupleTableSlot(slot); FreeExecutorState(estate); } @@ -8216,6 +8213,9 @@ validateForeignKeyConstraint(char *conname, { FunctionCallInfoData fcinfo; TriggerData trigdata; + TupleTableSlot *slot = MakeSingleTupleTableSlot(RelationGetDescr(rel)); + + ExecStoreTuple(tuple, slot, InvalidBuffer, false); /* * Make a call to the trigger function @@ -8230,11 +8230,9 @@ validateForeignKeyConstraint(char *conname, trigdata.type = T_TriggerData; trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW; trigdata.tg_relation = rel; - trigdata.tg_trigtuple = tuple; - trigdata.tg_newtuple = NULL; + trigdata.tg_trigslot = slot; + trigdata.tg_newslot = NULL; trigdata.tg_trigger = &trig; - trigdata.tg_trigtuplebuf = scan->rs_cbuf; - trigdata.tg_newtuplebuf = InvalidBuffer; fcinfo.context = (Node *) &trigdata; diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index b502941..38b7215 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -88,7 +88,7 @@ static HeapTuple GetTupleForTrigger(EState *estate, static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, - HeapTuple oldtup, HeapTuple newtup); + TupleTableSlot *oldslot, TupleTableSlot *newslot); static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, @@ -96,7 +96,7 @@ static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, MemoryContext per_tuple_context); static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, - HeapTuple oldtup, HeapTuple newtup, + TupleTableSlot *oldslot, TupleTableSlot *newslot, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture); static void AfterTriggerEnlargeQueryState(void); @@ -2298,12 +2298,10 @@ ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo) LocTriggerData.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; - LocTriggerData.tg_trigtuple = NULL; - LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_trigslot = NULL; + LocTriggerData.tg_newslot = NULL; LocTriggerData.tg_oldtable = NULL; LocTriggerData.tg_newtable = NULL; - LocTriggerData.tg_trigtuplebuf = InvalidBuffer; - LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) { Trigger *trigger = &trigdesc->triggers[i]; @@ -2359,10 +2357,9 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; - LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_newslot = NULL; LocTriggerData.tg_oldtable = NULL; LocTriggerData.tg_newtable = NULL; - LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) { Trigger *trigger = &trigdesc->triggers[i]; @@ -2373,21 +2370,22 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TRIGGER_TYPE_INSERT)) continue; if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event, - NULL, NULL, newtuple)) + NULL, NULL, slot)) continue; - LocTriggerData.tg_trigtuple = oldtuple = newtuple; - LocTriggerData.tg_trigtuplebuf = InvalidBuffer; + oldtuple = newtuple; + LocTriggerData.tg_trigslot = slot; LocTriggerData.tg_trigger = trigger; newtuple = ExecCallTriggerFunc(&LocTriggerData, i, relinfo->ri_TrigFunctions, relinfo->ri_TrigInstrument, GetPerTupleMemoryContext(estate)); - if (oldtuple != newtuple && oldtuple != slottuple) - heap_freetuple(oldtuple); if (newtuple == NULL) return NULL; /* "do nothing" */ + + if (oldtuple != newtuple) //hari + ExecStoreTuple(newtuple, slot, InvalidBuffer, true); } if (newtuple != slottuple) @@ -2411,7 +2409,7 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, void ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, - HeapTuple trigtuple, List *recheckIndexes, + TupleTableSlot *slot, List *recheckIndexes, TransitionCaptureState *transition_capture) { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; @@ -2419,7 +2417,7 @@ ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, if ((trigdesc && trigdesc->trig_insert_after_row) || (transition_capture && transition_capture->tcs_insert_new_table)) AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_INSERT, - true, NULL, trigtuple, + true, NULL, slot, recheckIndexes, NULL, transition_capture); } @@ -2440,10 +2438,9 @@ ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TRIGGER_EVENT_ROW | TRIGGER_EVENT_INSTEAD; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; - LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_newslot = NULL; LocTriggerData.tg_oldtable = NULL; LocTriggerData.tg_newtable = NULL; - LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) { Trigger *trigger = &trigdesc->triggers[i]; @@ -2454,21 +2451,22 @@ ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TRIGGER_TYPE_INSERT)) continue; if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event, - NULL, NULL, newtuple)) + NULL, NULL, slot)) continue; - LocTriggerData.tg_trigtuple = oldtuple = newtuple; - LocTriggerData.tg_trigtuplebuf = InvalidBuffer; + oldtuple = newtuple; + LocTriggerData.tg_trigslot = slot; LocTriggerData.tg_trigger = trigger; newtuple = ExecCallTriggerFunc(&LocTriggerData, i, relinfo->ri_TrigFunctions, relinfo->ri_TrigInstrument, GetPerTupleMemoryContext(estate)); - if (oldtuple != newtuple && oldtuple != slottuple) - heap_freetuple(oldtuple); if (newtuple == NULL) return NULL; /* "do nothing" */ + + if (oldtuple != newtuple) //hari + ExecStoreTuple(newtuple, slot, InvalidBuffer, true); } if (newtuple != slottuple) @@ -2508,12 +2506,10 @@ ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo) LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; - LocTriggerData.tg_trigtuple = NULL; - LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_trigslot = NULL; + LocTriggerData.tg_newslot = NULL; LocTriggerData.tg_oldtable = NULL; LocTriggerData.tg_newtable = NULL; - LocTriggerData.tg_trigtuplebuf = InvalidBuffer; - LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) { Trigger *trigger = &trigdesc->triggers[i]; @@ -2557,7 +2553,7 @@ bool ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, - HeapTuple fdw_trigtuple) + TupleTableSlot *trigslot) { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; bool result = true; @@ -2565,28 +2561,31 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, HeapTuple trigtuple; HeapTuple newtuple; TupleTableSlot *newSlot; + TupleTableSlot *oldslot = trigslot; int i; - Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid)); - if (fdw_trigtuple == NULL) + Assert(PointerIsValid(trigslot) ^ ItemPointerIsValid(tupleid)); + if (trigslot == NULL) { trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid, LockTupleExclusive, &newSlot); if (trigtuple == NULL) return false; + + oldslot = MakeSingleTupleTableSlot(RelationGetDescr(relinfo->ri_RelationDesc)); + ExecStoreTuple(trigtuple, oldslot, InvalidBuffer, false); } else - trigtuple = fdw_trigtuple; + trigtuple = ExecMaterializeSlot(trigslot); LocTriggerData.type = T_TriggerData; LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; - LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_newslot = NULL; LocTriggerData.tg_oldtable = NULL; LocTriggerData.tg_newtable = NULL; - LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) { Trigger *trigger = &trigdesc->triggers[i]; @@ -2597,11 +2596,10 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, TRIGGER_TYPE_DELETE)) continue; if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event, - NULL, trigtuple, NULL)) + NULL, oldslot, NULL)) continue; - LocTriggerData.tg_trigtuple = trigtuple; - LocTriggerData.tg_trigtuplebuf = InvalidBuffer; + LocTriggerData.tg_trigslot = oldslot; LocTriggerData.tg_trigger = trigger; newtuple = ExecCallTriggerFunc(&LocTriggerData, i, @@ -2616,8 +2614,9 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, if (newtuple != trigtuple) heap_freetuple(newtuple); } - if (trigtuple != fdw_trigtuple) - heap_freetuple(trigtuple); + + if (trigslot != oldslot) + ExecDropSingleTupleTableSlot(oldslot); return result; } @@ -2625,7 +2624,7 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, void ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, - HeapTuple fdw_trigtuple, + TupleTableSlot *slot, TransitionCaptureState *transition_capture) { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; @@ -2634,33 +2633,38 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, (transition_capture && transition_capture->tcs_delete_old_table)) { HeapTuple trigtuple; + TupleTableSlot *oldslot = slot; - Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid)); - if (fdw_trigtuple == NULL) + Assert(PointerIsValid(slot) ^ ItemPointerIsValid(tupleid)); + if (oldslot == NULL) + { trigtuple = GetTupleForTrigger(estate, NULL, relinfo, tupleid, LockTupleExclusive, NULL); - else - trigtuple = fdw_trigtuple; + oldslot = MakeSingleTupleTableSlot(RelationGetDescr(relinfo->ri_RelationDesc)); + ExecStoreTuple(trigtuple, oldslot, InvalidBuffer, false); + } AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_DELETE, - true, trigtuple, NULL, NIL, NULL, + true, oldslot, NULL, NIL, NULL, transition_capture); - if (trigtuple != fdw_trigtuple) - heap_freetuple(trigtuple); + + if (oldslot != slot) + ExecDropSingleTupleTableSlot(oldslot); } } bool ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, - HeapTuple trigtuple) + TupleTableSlot *slot) { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; TriggerData LocTriggerData; HeapTuple rettuple; + HeapTuple trigtuple = ExecMaterializeSlot(slot); int i; LocTriggerData.type = T_TriggerData; @@ -2668,10 +2672,9 @@ ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, TRIGGER_EVENT_ROW | TRIGGER_EVENT_INSTEAD; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; - LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_newslot = NULL; LocTriggerData.tg_oldtable = NULL; LocTriggerData.tg_newtable = NULL; - LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) { Trigger *trigger = &trigdesc->triggers[i]; @@ -2682,11 +2685,10 @@ ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, TRIGGER_TYPE_DELETE)) continue; if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event, - NULL, trigtuple, NULL)) + NULL, slot, NULL)) continue; - LocTriggerData.tg_trigtuple = trigtuple; - LocTriggerData.tg_trigtuplebuf = InvalidBuffer; + LocTriggerData.tg_trigslot = slot; LocTriggerData.tg_trigger = trigger; rettuple = ExecCallTriggerFunc(&LocTriggerData, i, @@ -2694,10 +2696,14 @@ ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, relinfo->ri_TrigInstrument, GetPerTupleMemoryContext(estate)); if (rettuple == NULL) + { + ExecDropSingleTupleTableSlot(slot); return false; /* Delete was suppressed */ + } if (rettuple != trigtuple) heap_freetuple(rettuple); } + return true; } @@ -2722,12 +2728,10 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo) LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; - LocTriggerData.tg_trigtuple = NULL; - LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_trigslot = NULL; + LocTriggerData.tg_newslot = NULL; LocTriggerData.tg_oldtable = NULL; LocTriggerData.tg_newtable = NULL; - LocTriggerData.tg_trigtuplebuf = InvalidBuffer; - LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) { Trigger *trigger = &trigdesc->triggers[i]; @@ -2773,16 +2777,16 @@ TupleTableSlot * ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, - HeapTuple fdw_trigtuple, + TupleTableSlot *trigslot, TupleTableSlot *slot) { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; HeapTuple slottuple = ExecMaterializeSlot(slot); HeapTuple newtuple = slottuple; TriggerData LocTriggerData; - HeapTuple trigtuple; HeapTuple oldtuple; TupleTableSlot *newSlot; + TupleTableSlot *oldSlot = trigslot; int i; Bitmapset *updatedCols; LockTupleMode lockmode; @@ -2790,18 +2794,22 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, /* Determine lock mode to use */ lockmode = ExecUpdateLockMode(estate, relinfo); - Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid)); - if (fdw_trigtuple == NULL) + Assert(PointerIsValid(trigslot) ^ ItemPointerIsValid(tupleid)); + if (trigslot == NULL) { + HeapTuple trigtuple; + /* get a copy of the on-disk tuple we are planning to update */ trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid, lockmode, &newSlot); if (trigtuple == NULL) return NULL; /* cancel the update action */ + + oldSlot = MakeSingleTupleTableSlot(RelationGetDescr(relinfo->ri_RelationDesc)); + ExecStoreTuple(trigtuple, oldSlot, InvalidBuffer, true); } else { - trigtuple = fdw_trigtuple; newSlot = NULL; } @@ -2842,30 +2850,32 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, TRIGGER_TYPE_UPDATE)) continue; if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event, - updatedCols, trigtuple, newtuple)) + updatedCols, oldSlot, slot)) continue; - LocTriggerData.tg_trigtuple = trigtuple; - LocTriggerData.tg_newtuple = oldtuple = newtuple; - LocTriggerData.tg_trigtuplebuf = InvalidBuffer; - LocTriggerData.tg_newtuplebuf = InvalidBuffer; + oldtuple = newtuple; + LocTriggerData.tg_trigslot = oldSlot; + LocTriggerData.tg_newslot = slot; LocTriggerData.tg_trigger = trigger; newtuple = ExecCallTriggerFunc(&LocTriggerData, i, relinfo->ri_TrigFunctions, relinfo->ri_TrigInstrument, GetPerTupleMemoryContext(estate)); - if (oldtuple != newtuple && oldtuple != slottuple) - heap_freetuple(oldtuple); if (newtuple == NULL) { - if (trigtuple != fdw_trigtuple) - heap_freetuple(trigtuple); + if (oldSlot != trigslot) + ExecDropSingleTupleTableSlot(oldSlot); + return NULL; /* "do nothing" */ } + + if (oldtuple != newtuple) //hari + ExecStoreTuple(newtuple, slot, InvalidBuffer, true); } - if (trigtuple != fdw_trigtuple) - heap_freetuple(trigtuple); + + if (oldSlot != trigslot) + ExecDropSingleTupleTableSlot(oldSlot); if (newtuple != slottuple) { @@ -2889,8 +2899,8 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, void ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, - HeapTuple fdw_trigtuple, - HeapTuple newtuple, + TupleTableSlot *oldslot, + TupleTableSlot *slot, List *recheckIndexes, TransitionCaptureState *transition_capture) { @@ -2902,30 +2912,35 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, transition_capture->tcs_update_new_table))) { HeapTuple trigtuple; + TupleTableSlot *trigslot = oldslot; - Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid)); - if (fdw_trigtuple == NULL) + Assert(PointerIsValid(oldslot) ^ ItemPointerIsValid(tupleid)); + if (oldslot == NULL) + { trigtuple = GetTupleForTrigger(estate, NULL, relinfo, tupleid, LockTupleExclusive, NULL); - else - trigtuple = fdw_trigtuple; + + trigslot = MakeSingleTupleTableSlot(RelationGetDescr(relinfo->ri_RelationDesc)); + ExecStoreTuple(trigtuple, trigslot, InvalidBuffer, false); + } AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_UPDATE, - true, trigtuple, newtuple, recheckIndexes, + true, trigslot, slot, recheckIndexes, GetUpdatedColumns(relinfo, estate), transition_capture); - if (trigtuple != fdw_trigtuple) - heap_freetuple(trigtuple); + + if (oldslot != trigslot) + ExecDropSingleTupleTableSlot(trigslot); } } TupleTableSlot * ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, - HeapTuple trigtuple, TupleTableSlot *slot) + TupleTableSlot *oldslot, TupleTableSlot *slot) { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; HeapTuple slottuple = ExecMaterializeSlot(slot); @@ -2951,13 +2966,12 @@ ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, TRIGGER_TYPE_UPDATE)) continue; if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event, - NULL, trigtuple, newtuple)) + NULL, oldslot, slot)) continue; - LocTriggerData.tg_trigtuple = trigtuple; - LocTriggerData.tg_newtuple = oldtuple = newtuple; - LocTriggerData.tg_trigtuplebuf = InvalidBuffer; - LocTriggerData.tg_newtuplebuf = InvalidBuffer; + oldtuple = newtuple; + LocTriggerData.tg_trigslot = oldslot; + LocTriggerData.tg_newslot = slot; LocTriggerData.tg_trigger = trigger; newtuple = ExecCallTriggerFunc(&LocTriggerData, i, @@ -2968,6 +2982,8 @@ ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, heap_freetuple(oldtuple); if (newtuple == NULL) return NULL; /* "do nothing" */ + + ExecStoreTuple(newtuple, slot, InvalidBuffer, false); } if (newtuple != slottuple) @@ -3007,12 +3023,10 @@ ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo) LocTriggerData.tg_event = TRIGGER_EVENT_TRUNCATE | TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; - LocTriggerData.tg_trigtuple = NULL; - LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_trigslot = NULL; + LocTriggerData.tg_newslot = NULL; LocTriggerData.tg_oldtable = NULL; LocTriggerData.tg_newtable = NULL; - LocTriggerData.tg_trigtuplebuf = InvalidBuffer; - LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) { Trigger *trigger = &trigdesc->triggers[i]; @@ -3200,7 +3214,7 @@ static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, - HeapTuple oldtup, HeapTuple newtup) + TupleTableSlot *oldslot, TupleTableSlot *newslot) { /* Check replication-role-dependent enable state */ if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA) @@ -3245,8 +3259,8 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo, TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc); ExprState **predicate; ExprContext *econtext; - TupleTableSlot *oldslot = NULL; - TupleTableSlot *newslot = NULL; + TupleTableSlot *old_localslot = NULL; + TupleTableSlot *new_localslot = NULL; MemoryContext oldContext; int i; @@ -3290,7 +3304,7 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo, * These slots can be shared across the whole estate, but be careful * that they have the current resultrel's tupdesc. */ - if (HeapTupleIsValid(oldtup)) + if (PointerIsValid(oldslot)) { if (estate->es_trig_oldtup_slot == NULL) { @@ -3298,12 +3312,12 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo, estate->es_trig_oldtup_slot = ExecInitExtraTupleSlot(estate); MemoryContextSwitchTo(oldContext); } - oldslot = estate->es_trig_oldtup_slot; - if (oldslot->tts_tupleDescriptor != tupdesc) - ExecSetSlotDescriptor(oldslot, tupdesc); - ExecStoreTuple(oldtup, oldslot, InvalidBuffer, false); + old_localslot = estate->es_trig_oldtup_slot; + if (old_localslot->tts_tupleDescriptor != tupdesc) + ExecSetSlotDescriptor(old_localslot, tupdesc); + ExecStoreTuple(oldslot->tts_tuple, old_localslot, InvalidBuffer, false); } - if (HeapTupleIsValid(newtup)) + if (PointerIsValid(newslot)) { if (estate->es_trig_newtup_slot == NULL) { @@ -3311,18 +3325,18 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo, estate->es_trig_newtup_slot = ExecInitExtraTupleSlot(estate); MemoryContextSwitchTo(oldContext); } - newslot = estate->es_trig_newtup_slot; - if (newslot->tts_tupleDescriptor != tupdesc) - ExecSetSlotDescriptor(newslot, tupdesc); - ExecStoreTuple(newtup, newslot, InvalidBuffer, false); + new_localslot = estate->es_trig_newtup_slot; + if (new_localslot->tts_tupleDescriptor != tupdesc) + ExecSetSlotDescriptor(new_localslot, tupdesc); + ExecStoreTuple(newslot->tts_tuple, new_localslot, InvalidBuffer, false); } /* * Finally evaluate the expression, making the old and/or new tuples * available as INNER_VAR/OUTER_VAR respectively. */ - econtext->ecxt_innertuple = oldslot; - econtext->ecxt_outertuple = newslot; + econtext->ecxt_innertuple = old_localslot; + econtext->ecxt_outertuple = new_localslot; if (!ExecQual(*predicate, econtext)) return false; } @@ -3900,6 +3914,8 @@ AfterTriggerExecute(AfterTriggerEvent event, TriggerData LocTriggerData; HeapTupleData tuple1; HeapTupleData tuple2; + HeapTuple oldtuple = NULL; + HeapTuple newtuple = NULL; HeapTuple rettuple; Buffer buffer1 = InvalidBuffer; Buffer buffer2 = InvalidBuffer; @@ -3960,15 +3976,11 @@ AfterTriggerExecute(AfterTriggerEvent event, * because we start with a minimal tuple that ExecFetchSlotTuple() * must materialize anyway. */ - LocTriggerData.tg_trigtuple = - ExecMaterializeSlot(trig_tuple_slot1); - LocTriggerData.tg_trigtuplebuf = InvalidBuffer; + LocTriggerData.tg_trigslot = trig_tuple_slot1; - LocTriggerData.tg_newtuple = + LocTriggerData.tg_newslot = ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) == - TRIGGER_EVENT_UPDATE) ? - ExecMaterializeSlot(trig_tuple_slot2) : NULL; - LocTriggerData.tg_newtuplebuf = InvalidBuffer; + TRIGGER_EVENT_UPDATE) ? trig_tuple_slot2 : NULL; break; @@ -3978,13 +3990,12 @@ AfterTriggerExecute(AfterTriggerEvent event, ItemPointerCopy(&(event->ate_ctid1), &(tuple1.t_self)); if (!heap_fetch(rel, SnapshotAny, &tuple1, &buffer1, false, NULL)) elog(ERROR, "failed to fetch tuple1 for AFTER trigger"); - LocTriggerData.tg_trigtuple = &tuple1; - LocTriggerData.tg_trigtuplebuf = buffer1; + LocTriggerData.tg_trigslot = MakeSingleTupleTableSlot(RelationGetDescr(rel)); + ExecStoreTuple(&tuple1, LocTriggerData.tg_trigslot, buffer1, false); } else { - LocTriggerData.tg_trigtuple = NULL; - LocTriggerData.tg_trigtuplebuf = InvalidBuffer; + LocTriggerData.tg_trigslot = NULL; } /* don't touch ctid2 if not there */ @@ -3995,13 +4006,12 @@ AfterTriggerExecute(AfterTriggerEvent event, ItemPointerCopy(&(event->ate_ctid2), &(tuple2.t_self)); if (!heap_fetch(rel, SnapshotAny, &tuple2, &buffer2, false, NULL)) elog(ERROR, "failed to fetch tuple2 for AFTER trigger"); - LocTriggerData.tg_newtuple = &tuple2; - LocTriggerData.tg_newtuplebuf = buffer2; + LocTriggerData.tg_newslot = MakeSingleTupleTableSlot(RelationGetDescr(rel)); + ExecStoreTuple(&tuple2, LocTriggerData.tg_newslot, buffer2, false); } else { - LocTriggerData.tg_newtuple = NULL; - LocTriggerData.tg_newtuplebuf = InvalidBuffer; + LocTriggerData.tg_newslot = NULL; } } @@ -4039,6 +4049,12 @@ AfterTriggerExecute(AfterTriggerEvent event, } } + if (LocTriggerData.tg_trigslot != NULL) + oldtuple = ExecMaterializeSlot(LocTriggerData.tg_trigslot); + + if (LocTriggerData.tg_newslot != NULL) + newtuple = ExecMaterializeSlot(LocTriggerData.tg_newslot); + /* * Setup the remaining trigger information */ @@ -4059,10 +4075,18 @@ AfterTriggerExecute(AfterTriggerEvent event, NULL, per_tuple_context); if (rettuple != NULL && - rettuple != LocTriggerData.tg_trigtuple && - rettuple != LocTriggerData.tg_newtuple) + rettuple != oldtuple && + rettuple != newtuple) heap_freetuple(rettuple); + if ((LocTriggerData.tg_trigslot != NULL) && + (LocTriggerData.tg_trigslot != trig_tuple_slot1)) + ExecDropSingleTupleTableSlot(LocTriggerData.tg_trigslot); + + if ((LocTriggerData.tg_newslot != NULL) && + (LocTriggerData.tg_newslot != trig_tuple_slot2)) + ExecDropSingleTupleTableSlot(LocTriggerData.tg_newslot); + /* * Release buffers */ @@ -5221,7 +5245,7 @@ AfterTriggerPendingOnRel(Oid relid) static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, - HeapTuple oldtup, HeapTuple newtup, + TupleTableSlot *oldslot, TupleTableSlot *newslot, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture) { @@ -5265,25 +5289,27 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, { Tuplestorestate *old_tuplestore; - Assert(oldtup != NULL); + Assert(oldslot != NULL); + Assert(oldslot->tts_tuple != NULL); old_tuplestore = transition_capture->tcs_old_tuplestore; if (map != NULL) { - HeapTuple converted = do_convert_tuple(oldtup, map); + HeapTuple converted = do_convert_tuple(oldslot->tts_tuple, map); tuplestore_puttuple(old_tuplestore, converted); pfree(converted); } else - tuplestore_puttuple(old_tuplestore, oldtup); + tuplestore_puttuple(old_tuplestore, oldslot->tts_tuple); } if ((event == TRIGGER_EVENT_INSERT && insert_new_table) || (event == TRIGGER_EVENT_UPDATE && update_new_table)) { Tuplestorestate *new_tuplestore; - Assert(newtup != NULL); + Assert(newslot != NULL); + Assert(newslot->tts_tuple != NULL); if (event == TRIGGER_EVENT_INSERT) new_tuplestore = transition_capture->tcs_insert_tuplestore; else @@ -5293,13 +5319,13 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, tuplestore_puttuple(new_tuplestore, original_insert_tuple); else if (map != NULL) { - HeapTuple converted = do_convert_tuple(newtup, map); + HeapTuple converted = do_convert_tuple(newslot->tts_tuple, map); tuplestore_puttuple(new_tuplestore, converted); pfree(converted); } else - tuplestore_puttuple(new_tuplestore, newtup); + tuplestore_puttuple(new_tuplestore, newslot->tts_tuple); } /* If transition tables are the only reason we're here, return. */ @@ -5323,15 +5349,15 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, tgtype_event = TRIGGER_TYPE_INSERT; if (row_trigger) { - Assert(oldtup == NULL); - Assert(newtup != NULL); - ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid1)); + Assert(oldslot == NULL); + Assert(newslot != NULL); + ItemPointerCopy(&(newslot->tts_tid), &(new_event.ate_ctid1)); ItemPointerSetInvalid(&(new_event.ate_ctid2)); } else { - Assert(oldtup == NULL); - Assert(newtup == NULL); + Assert(oldslot == NULL); + Assert(newslot == NULL); ItemPointerSetInvalid(&(new_event.ate_ctid1)); ItemPointerSetInvalid(&(new_event.ate_ctid2)); } @@ -5340,15 +5366,15 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, tgtype_event = TRIGGER_TYPE_DELETE; if (row_trigger) { - Assert(oldtup != NULL); - Assert(newtup == NULL); - ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1)); + Assert(oldslot != NULL); + Assert(newslot == NULL); + ItemPointerCopy(&(oldslot->tts_tid), &(new_event.ate_ctid1)); ItemPointerSetInvalid(&(new_event.ate_ctid2)); } else { - Assert(oldtup == NULL); - Assert(newtup == NULL); + Assert(oldslot == NULL); + Assert(newslot == NULL); ItemPointerSetInvalid(&(new_event.ate_ctid1)); ItemPointerSetInvalid(&(new_event.ate_ctid2)); } @@ -5357,23 +5383,23 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, tgtype_event = TRIGGER_TYPE_UPDATE; if (row_trigger) { - Assert(oldtup != NULL); - Assert(newtup != NULL); - ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1)); - ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid2)); + Assert(oldslot != NULL); + Assert(newslot != NULL); + ItemPointerCopy(&(oldslot->tts_tid), &(new_event.ate_ctid1)); + ItemPointerCopy(&(newslot->tts_tid), &(new_event.ate_ctid2)); } else { - Assert(oldtup == NULL); - Assert(newtup == NULL); + Assert(oldslot == NULL); + Assert(newslot == NULL); ItemPointerSetInvalid(&(new_event.ate_ctid1)); ItemPointerSetInvalid(&(new_event.ate_ctid2)); } break; case TRIGGER_EVENT_TRUNCATE: tgtype_event = TRIGGER_TYPE_TRUNCATE; - Assert(oldtup == NULL); - Assert(newtup == NULL); + Assert(oldslot == NULL); + Assert(newslot == NULL); ItemPointerSetInvalid(&(new_event.ate_ctid1)); ItemPointerSetInvalid(&(new_event.ate_ctid2)); break; @@ -5400,7 +5426,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, tgtype_event)) continue; if (!TriggerEnabled(estate, relinfo, trigger, event, - modifiedCols, oldtup, newtup)) + modifiedCols, oldslot, newslot)) continue; if (relkind == RELKIND_FOREIGN_TABLE && row_trigger) @@ -5429,7 +5455,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, case RI_TRIGGER_PK: /* Update on trigger's PK table */ if (!RI_FKey_pk_upd_check_required(trigger, rel, - oldtup, newtup)) + oldslot, newslot)) { /* skip queuing this event */ continue; @@ -5439,7 +5465,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, case RI_TRIGGER_FK: /* Update on trigger's FK table */ if (!RI_FKey_fk_upd_check_required(trigger, rel, - oldtup, newtup)) + oldslot, newslot)) { /* skip queuing this event */ continue; @@ -5487,10 +5513,10 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, */ if (fdw_tuplestore) { - if (oldtup != NULL) - tuplestore_puttuple(fdw_tuplestore, oldtup); - if (newtup != NULL) - tuplestore_puttuple(fdw_tuplestore, newtup); + if (oldslot != NULL) + tuplestore_puttuple(fdw_tuplestore, oldslot->tts_tuple); + if (newslot != NULL) + tuplestore_puttuple(fdw_tuplestore, newslot->tts_tuple); } } diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c index bc53d07..ab4a6c5 100644 --- a/src/backend/executor/execReplication.c +++ b/src/backend/executor/execReplication.c @@ -409,14 +409,14 @@ ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot) /* OK, store the tuple and create index entries for it */ simple_heap_insert(rel, tuple); - + ItemPointerCopy(&(tuple->t_self), &(slot->tts_tid)); if (resultRelInfo->ri_NumIndices > 0) recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false, NULL, NIL); /* AFTER ROW INSERT Triggers */ - ExecARInsertTriggers(estate, resultRelInfo, tuple, + ExecARInsertTriggers(estate, resultRelInfo, slot, recheckIndexes, NULL); /* @@ -482,10 +482,11 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, estate, false, NULL, NIL); + ItemPointerCopy(&(tuple->t_self), &(slot->tts_tid)); /* AFTER ROW UPDATE Triggers */ ExecARUpdateTriggers(estate, resultRelInfo, &searchslot->tts_tuple->t_self, - NULL, tuple, recheckIndexes, NULL); + NULL, slot, recheckIndexes, NULL); list_free(recheckIndexes); } diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 7ae70a8..fabb628 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -116,6 +116,7 @@ MakeTupleTableSlot(void) slot->tts_shouldFree = false; slot->tts_shouldFreeMin = false; slot->tts_tuple = NULL; + ItemPointerSetInvalid(&(slot->tts_tid)); slot->tts_tupleDescriptor = NULL; slot->tts_mcxt = CurrentMemoryContext; slot->tts_buffer = InvalidBuffer; @@ -369,6 +370,8 @@ ExecStoreTuple(HeapTuple tuple, IncrBufferRefCount(buffer); } + ItemPointerCopy(&(tuple->t_self), &(slot->tts_tid)); + return slot; } @@ -427,6 +430,63 @@ ExecStoreMinimalTuple(MinimalTuple mtup, return slot; } +/* + * heap_modify_slot_by_cols + * form a new tuple from an old tuple and a set of replacement values. + * + * This is like heap_modify_tuple, except that instead of specifying which + * column(s) to replace by a boolean map, an array of target column numbers + * is used. This is often more convenient when a fixed number of columns + * are to be replaced. The replCols, replValues, and replIsnull arrays must + * be of length nCols. Target column numbers are indexed from 1. + * + * The result is allocated in the current memory context. + */ +TupleTableSlot* +heap_modify_slot_by_cols(TupleTableSlot *slot, + int nCols, + int *replCols, + Datum *replValues, + bool *replIsnull) +{ + int numberOfAttributes = slot->tts_tupleDescriptor->natts; + HeapTuple newTuple; + int i; + + slot_getallattrs(slot); + + for (i = 0; i < nCols; i++) + { + int attnum = replCols[i]; + + if (attnum <= 0 || attnum > numberOfAttributes) + elog(ERROR, "invalid column number %d", attnum); + slot->tts_values[attnum - 1] = replValues[i]; + slot->tts_isnull[attnum - 1] = replIsnull[i]; + } + + /* + * create a new tuple from the values and isnull arrays + */ + newTuple = heap_form_tuple(slot->tts_tupleDescriptor, slot->tts_values, slot->tts_isnull); + + /* + * copy the identification info of the old tuple: t_ctid, t_self, and OID + * (if any) + */ + newTuple->t_data->t_ctid = slot->tts_tuple->t_data->t_ctid; + newTuple->t_self = slot->tts_tuple->t_self; + newTuple->t_tableOid = slot->tts_tuple->t_tableOid; + if (slot->tts_tupleDescriptor->tdhasoid) + HeapTupleSetOid(newTuple, HeapTupleGetOid(slot->tts_tuple)); + + if (slot->tts_shouldFree) + heap_freetuple(slot->tts_tuple); + + slot->tts_tuple = newTuple; + return slot; +} + /* -------------------------------- * ExecClearTuple * diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 8d17425..387c059 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -557,6 +557,7 @@ ExecInsert(ModifyTableState *mtstate, HEAP_INSERT_SPECULATIVE, NULL); + ItemPointerCopy(&(tuple->t_self), &(slot->tts_tid)); /* insert index entries for tuple */ recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self), estate, true, &specConflict, @@ -602,6 +603,7 @@ ExecInsert(ModifyTableState *mtstate, estate->es_output_cid, 0, NULL); + ItemPointerCopy(&(tuple->t_self), &(slot->tts_tid)); /* insert index entries for tuple */ if (resultRelInfo->ri_NumIndices > 0) recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self), @@ -618,7 +620,7 @@ ExecInsert(ModifyTableState *mtstate, } /* AFTER ROW INSERT Triggers */ - ExecARInsertTriggers(estate, resultRelInfo, tuple, recheckIndexes, + ExecARInsertTriggers(estate, resultRelInfo, slot, recheckIndexes, mtstate->mt_transition_capture); list_free(recheckIndexes); @@ -669,7 +671,7 @@ ExecInsert(ModifyTableState *mtstate, static TupleTableSlot * ExecDelete(ModifyTableState *mtstate, ItemPointer tupleid, - HeapTuple oldtuple, + TupleTableSlot *oldslot, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, @@ -694,7 +696,7 @@ ExecDelete(ModifyTableState *mtstate, bool dodelete; dodelete = ExecBRDeleteTriggers(estate, epqstate, resultRelInfo, - tupleid, oldtuple); + tupleid, oldslot); if (!dodelete) /* "do nothing" */ return NULL; @@ -706,8 +708,8 @@ ExecDelete(ModifyTableState *mtstate, { bool dodelete; - Assert(oldtuple != NULL); - dodelete = ExecIRDeleteTriggers(estate, resultRelInfo, oldtuple); + Assert(oldslot != NULL); + dodelete = ExecIRDeleteTriggers(estate, resultRelInfo, oldslot); if (!dodelete) /* "do nothing" */ return NULL; @@ -844,8 +846,11 @@ ldelete:; if (canSetTag) (estate->es_processed)++; + if (oldslot != NULL) + ItemPointerCopy(tupleid, &(oldslot->tts_tid)); + /* AFTER ROW DELETE Triggers */ - ExecARDeleteTriggers(estate, resultRelInfo, tupleid, oldtuple, + ExecARDeleteTriggers(estate, resultRelInfo, tupleid, oldslot, mtstate->mt_transition_capture); /* Process RETURNING if present */ @@ -868,10 +873,12 @@ ldelete:; else { slot = estate->es_trig_tuple_slot; - if (oldtuple != NULL) + if (oldslot != NULL) { - deltuple = *oldtuple; - delbuffer = InvalidBuffer; + ExecCopySlot(slot, oldslot); + + if (slot->tts_tupleDescriptor != RelationGetDescr(resultRelationDesc)) + ExecSetSlotDescriptor(slot, RelationGetDescr(resultRelationDesc)); } else { @@ -879,11 +886,11 @@ ldelete:; if (!heap_fetch(resultRelationDesc, SnapshotAny, &deltuple, &delbuffer, false, NULL)) elog(ERROR, "failed to fetch deleted tuple for DELETE RETURNING"); - } - if (slot->tts_tupleDescriptor != RelationGetDescr(resultRelationDesc)) - ExecSetSlotDescriptor(slot, RelationGetDescr(resultRelationDesc)); - ExecStoreTuple(&deltuple, slot, InvalidBuffer, false); + if (slot->tts_tupleDescriptor != RelationGetDescr(resultRelationDesc)) + ExecSetSlotDescriptor(slot, RelationGetDescr(resultRelationDesc)); + ExecStoreTuple(&deltuple, slot, InvalidBuffer, false); + } } rslot = ExecProcessReturning(resultRelInfo, slot, planSlot); @@ -929,7 +936,7 @@ ldelete:; static TupleTableSlot * ExecUpdate(ModifyTableState *mtstate, ItemPointer tupleid, - HeapTuple oldtuple, + TupleTableSlot *oldslot, TupleTableSlot *slot, TupleTableSlot *planSlot, EPQState *epqstate, @@ -966,7 +973,7 @@ ExecUpdate(ModifyTableState *mtstate, resultRelInfo->ri_TrigDesc->trig_update_before_row) { slot = ExecBRUpdateTriggers(estate, epqstate, resultRelInfo, - tupleid, oldtuple, slot); + tupleid, oldslot, slot); if (slot == NULL) /* "do nothing" */ return NULL; @@ -980,7 +987,7 @@ ExecUpdate(ModifyTableState *mtstate, resultRelInfo->ri_TrigDesc->trig_update_instead_row) { slot = ExecIRUpdateTriggers(estate, resultRelInfo, - oldtuple, slot); + oldslot, slot); if (slot == NULL) /* "do nothing" */ return NULL; @@ -1138,6 +1145,7 @@ lreplace:; * All we do here is insert new index tuples. -cim 9/27/89 */ + ItemPointerCopy(&(tuple->t_self), &(slot->tts_tid)); /* * insert index entries for tuple * @@ -1155,7 +1163,7 @@ lreplace:; (estate->es_processed)++; /* AFTER ROW UPDATE Triggers */ - ExecARUpdateTriggers(estate, resultRelInfo, tupleid, oldtuple, tuple, + ExecARUpdateTriggers(estate, resultRelInfo, tupleid, oldslot, slot, recheckIndexes, mtstate->mt_transition_capture); @@ -1550,6 +1558,7 @@ ExecModifyTable(ModifyTableState *node) ItemPointerData tuple_ctid; HeapTupleData oldtupdata; HeapTuple oldtuple; + TupleTableSlot *oldslot = NULL; /* * This should NOT get called during EvalPlanQual; we should have passed a @@ -1659,7 +1668,8 @@ ExecModifyTable(ModifyTableState *node) } EvalPlanQualSetSlot(&node->mt_epqstate, planSlot); - slot = planSlot; + slot = MakeSingleTupleTableSlot(planSlot->tts_tupleDescriptor); + ExecCopySlot(slot, planSlot); oldtuple = NULL; if (junkfilter != NULL) @@ -1721,6 +1731,10 @@ ExecModifyTable(ModifyTableState *node) RelationGetRelid(resultRelInfo->ri_RelationDesc); oldtuple = &oldtupdata; + + ItemPointerCopy(tupleid, &(oldslot->tts_tid)); + oldslot = MakeSingleTupleTableSlot(RelationGetDescr(resultRelInfo->ri_RelationDesc)); + ExecStoreTuple(oldtuple, oldslot, InvalidBuffer, false); } else Assert(relkind == RELKIND_FOREIGN_TABLE); @@ -1741,11 +1755,11 @@ ExecModifyTable(ModifyTableState *node) estate, node->canSetTag); break; case CMD_UPDATE: - slot = ExecUpdate(node, tupleid, oldtuple, slot, planSlot, + slot = ExecUpdate(node, tupleid, oldslot, slot, planSlot, &node->mt_epqstate, estate, node->canSetTag); break; case CMD_DELETE: - slot = ExecDelete(node, tupleid, oldtuple, planSlot, + slot = ExecDelete(node, tupleid, oldslot, planSlot, &node->mt_epqstate, estate, node->canSetTag); break; default: @@ -1753,6 +1767,9 @@ ExecModifyTable(ModifyTableState *node) break; } + if (oldslot) + ExecDropSingleTupleTableSlot(oldslot); + /* * If we got a RETURNING result, return it to caller. We'll continue * the work on next call. diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index cd00a6d..79ffa52 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -23,6 +23,7 @@ #include "commands/trigger.h" #include "executor/executor.h" #include "executor/spi_priv.h" +#include "executor/tuptable.h" #include "miscadmin.h" #include "tcop/pquery.h" #include "tcop/utility.h" @@ -757,6 +758,72 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, return mtuple; } +TupleTableSlot * +SPI_modifyslot(TupleTableSlot *slot, int natts, int *attnum, + Datum *Values, const char *Nulls) +{ + MemoryContext oldcxt; + HeapTuple mtuple; + int numberOfAttributes; + int i; + + if (slot == NULL || natts < 0 || attnum == NULL || Values == NULL) + { + SPI_result = SPI_ERROR_ARGUMENT; + return NULL; + } + + if (_SPI_current == NULL) + { + SPI_result = SPI_ERROR_UNCONNECTED; + return NULL; + } + + oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); + + SPI_result = 0; + + numberOfAttributes = slot->tts_tupleDescriptor->natts; + + /* replace values and nulls */ + for (i = 0; i < natts; i++) + { + if (attnum[i] <= 0 || attnum[i] > numberOfAttributes) + break; + slot->tts_values[attnum[i] - 1] = Values[i]; + slot->tts_isnull[attnum[i] - 1] = (Nulls && Nulls[i] == 'n') ? true : false; + } + + if (i == natts) /* no errors in *attnum */ + { + mtuple = heap_form_tuple(slot->tts_tupleDescriptor, slot->tts_values, slot->tts_isnull); + + /* + * copy the identification info of the old tuple: t_ctid, t_self, and + * OID (if any) + */ + mtuple->t_data->t_ctid = slot->tts_tuple->t_data->t_ctid; + mtuple->t_self = slot->tts_tuple->t_self; + mtuple->t_tableOid = slot->tts_tuple->t_tableOid; + if (slot->tts_tupleDescriptor->tdhasoid) + HeapTupleSetOid(mtuple, HeapTupleGetOid(slot->tts_tuple)); + } + else + { + mtuple = NULL; + SPI_result = SPI_ERROR_NOATTRIBUTE; + } + + MemoryContextSwitchTo(oldcxt); + + if (slot->tts_shouldFree) + heap_freetuple(slot->tts_tuple); + + slot->tts_tuple = mtuple; + + return slot; +} + int SPI_fnumber(TupleDesc tupdesc, const char *fname) { @@ -801,7 +868,7 @@ SPI_fname(TupleDesc tupdesc, int fnumber) } char * -SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber) +SPI_getvalue(TupleTableSlot *slot, int fnumber) { Datum val; bool isnull; @@ -811,19 +878,19 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber) SPI_result = 0; - if (fnumber > tupdesc->natts || fnumber == 0 || + if (fnumber > slot->tts_tupleDescriptor->natts || fnumber == 0 || fnumber <= FirstLowInvalidHeapAttributeNumber) { SPI_result = SPI_ERROR_NOATTRIBUTE; return NULL; } - val = heap_getattr(tuple, fnumber, tupdesc, &isnull); + val = slot_getattr(slot, fnumber, &isnull); if (isnull) return NULL; if (fnumber > 0) - typoid = tupdesc->attrs[fnumber - 1]->atttypid; + typoid = slot->tts_tupleDescriptor->attrs[fnumber - 1]->atttypid; else typoid = (SystemAttributeDefinition(fnumber, true))->atttypid; @@ -833,11 +900,11 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber) } Datum -SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull) +SPI_getbinval(TupleTableSlot *slot, int fnumber, bool *isnull) { SPI_result = 0; - if (fnumber > tupdesc->natts || fnumber == 0 || + if (fnumber > slot->tts_tupleDescriptor->natts || fnumber == 0 || fnumber <= FirstLowInvalidHeapAttributeNumber) { SPI_result = SPI_ERROR_NOATTRIBUTE; @@ -845,7 +912,7 @@ SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull) return (Datum) NULL; } - return heap_getattr(tuple, fnumber, tupdesc, isnull); + return slot_getattr(slot, fnumber, isnull); } char * @@ -1681,7 +1748,7 @@ spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo) /* set up initial allocations */ tuptable->alloced = tuptable->free = 128; - tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple)); + tuptable->vals = (TupleTableSlot **) palloc(tuptable->alloced * sizeof(TupleTableSlot *)); tuptable->tupdesc = CreateTupleDescCopy(typeinfo); MemoryContextSwitchTo(oldcxt); @@ -1697,6 +1764,7 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self) { SPITupleTable *tuptable; MemoryContext oldcxt; + TupleTableSlot *dstslot; if (_SPI_current == NULL) elog(ERROR, "spi_printtup called while not connected to SPI"); @@ -1712,12 +1780,12 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self) /* Double the size of the pointer array */ tuptable->free = tuptable->alloced; tuptable->alloced += tuptable->free; - tuptable->vals = (HeapTuple *) repalloc_huge(tuptable->vals, - tuptable->alloced * sizeof(HeapTuple)); + tuptable->vals = (TupleTableSlot **) repalloc_huge(tuptable->vals, + tuptable->alloced * sizeof(TupleTableSlot *)); } - tuptable->vals[tuptable->alloced - tuptable->free] = - ExecCopySlotTuple(slot); + dstslot = MakeSingleTupleTableSlot(tuptable->tupdesc); + tuptable->vals[tuptable->alloced - tuptable->free] = ExecCopySlot(dstslot, slot); (tuptable->free)--; MemoryContextSwitchTo(oldcxt); diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index 0d48dfa..4a01fbd 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -726,6 +726,7 @@ apply_handle_update(StringInfo s) /* Process and store remote tuple in the slot */ oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); ExecStoreTuple(localslot->tts_tuple, remoteslot, InvalidBuffer, false); + ItemPointerCopy(&(localslot->tts_tuple->t_self), &(remoteslot->tts_tid)); slot_modify_cstrings(remoteslot, rel, newtup.values, newtup.changed); MemoryContextSwitchTo(oldctx); diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index c2891e6..01714f4 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -194,7 +194,7 @@ static int ri_constraint_cache_valid_count = 0; * ---------- */ static bool ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel, - HeapTuple old_row, + TupleTableSlot *oldslot, const RI_ConstraintInfo *riinfo); static Datum ri_restrict_del(TriggerData *trigdata, bool is_no_action); static Datum ri_restrict_upd(TriggerData *trigdata, bool is_no_action); @@ -207,12 +207,12 @@ static void ri_GenerateQual(StringInfo buf, const char *rightop, Oid rightoptype); static void ri_add_cast_to(StringInfo buf, Oid typid); static void ri_GenerateQualCollation(StringInfo buf, Oid collation); -static int ri_NullCheck(HeapTuple tup, +static int ri_NullCheck(TupleTableSlot *slot, const RI_ConstraintInfo *riinfo, bool rel_is_pk); static void ri_BuildQueryKey(RI_QueryKey *key, const RI_ConstraintInfo *riinfo, int32 constr_queryno); -static bool ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup, +static bool ri_KeysEqual(Relation rel, TupleTableSlot *oldslot, TupleTableSlot *newslot, const RI_ConstraintInfo *riinfo, bool rel_is_pk); static bool ri_AttributesEqual(Oid eq_opr, Oid typeid, Datum oldvalue, Datum newvalue); @@ -234,14 +234,13 @@ static SPIPlanPtr ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes, static bool ri_PerformCheck(const RI_ConstraintInfo *riinfo, RI_QueryKey *qkey, SPIPlanPtr qplan, Relation fk_rel, Relation pk_rel, - HeapTuple old_tuple, HeapTuple new_tuple, + TupleTableSlot *oldslot, TupleTableSlot *newslot, bool detectNewRows, int expect_OK); -static void ri_ExtractValues(Relation rel, HeapTuple tup, - const RI_ConstraintInfo *riinfo, bool rel_is_pk, - Datum *vals, char *nulls); +static void ri_ExtractValues(TupleTableSlot *slot, const RI_ConstraintInfo *riinfo, + bool rel_is_pk, Datum *vals, char *nulls); static void ri_ReportViolation(const RI_ConstraintInfo *riinfo, Relation pk_rel, Relation fk_rel, - HeapTuple violator, TupleDesc tupdesc, + TupleTableSlot* violator, TupleDesc tupdesc, int queryno, bool spi_err); @@ -257,8 +256,7 @@ RI_FKey_check(TriggerData *trigdata) const RI_ConstraintInfo *riinfo; Relation fk_rel; Relation pk_rel; - HeapTuple new_row; - Buffer new_row_buf; + TupleTableSlot *newslot; RI_QueryKey qkey; SPIPlanPtr qplan; int i; @@ -270,15 +268,9 @@ RI_FKey_check(TriggerData *trigdata) trigdata->tg_relation, false); if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) - { - new_row = trigdata->tg_newtuple; - new_row_buf = trigdata->tg_newtuplebuf; - } + newslot = trigdata->tg_newslot; else - { - new_row = trigdata->tg_trigtuple; - new_row_buf = trigdata->tg_trigtuplebuf; - } + newslot = trigdata->tg_trigslot; /* * We should not even consider checking the row if it is no longer valid, @@ -288,13 +280,8 @@ RI_FKey_check(TriggerData *trigdata) * and lock on the buffer to call HeapTupleSatisfiesVisibility. Caller * should be holding pin, but not lock. */ - LockBuffer(new_row_buf, BUFFER_LOCK_SHARE); - if (!HeapTupleSatisfiesVisibility(new_row, SnapshotSelf, new_row_buf)) - { - LockBuffer(new_row_buf, BUFFER_LOCK_UNLOCK); + if (!HeapTupleSatisfiesVisibility(newslot->tts_tuple, SnapshotSelf, InvalidBuffer)) return PointerGetDatum(NULL); - } - LockBuffer(new_row_buf, BUFFER_LOCK_UNLOCK); /* * Get the relation descriptors of the FK and PK tables. @@ -310,7 +297,7 @@ RI_FKey_check(TriggerData *trigdata) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("MATCH PARTIAL not yet implemented"))); - switch (ri_NullCheck(new_row, riinfo, false)) + switch (ri_NullCheck(newslot, riinfo, false)) { case RI_KEYS_ALL_NULL: @@ -440,7 +427,7 @@ RI_FKey_check(TriggerData *trigdata) */ ri_PerformCheck(riinfo, &qkey, qplan, fk_rel, pk_rel, - NULL, new_row, + NULL, newslot, false, SPI_OK_SELECT); @@ -508,7 +495,7 @@ RI_FKey_check_upd(PG_FUNCTION_ARGS) */ static bool ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel, - HeapTuple old_row, + TupleTableSlot *oldslot, const RI_ConstraintInfo *riinfo) { SPIPlanPtr qplan; @@ -517,7 +504,7 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel, bool result; /* Only called for non-null rows */ - Assert(ri_NullCheck(old_row, riinfo, true) == RI_KEYS_NONE_NULL); + Assert(ri_NullCheck(oldslot, riinfo, true) == RI_KEYS_NONE_NULL); if (SPI_connect() != SPI_OK_CONNECT) elog(ERROR, "SPI_connect failed"); @@ -575,8 +562,8 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel, */ result = ri_PerformCheck(riinfo, &qkey, qplan, fk_rel, pk_rel, - old_row, NULL, - true, /* treat like update */ + oldslot, NULL, + true, /* treat like update */ SPI_OK_SELECT); if (SPI_finish() != SPI_OK_FINISH) @@ -645,7 +632,7 @@ ri_restrict_del(TriggerData *trigdata, bool is_no_action) const RI_ConstraintInfo *riinfo; Relation fk_rel; Relation pk_rel; - HeapTuple old_row; + TupleTableSlot *oldslot; RI_QueryKey qkey; SPIPlanPtr qplan; int i; @@ -664,7 +651,7 @@ ri_restrict_del(TriggerData *trigdata, bool is_no_action) */ fk_rel = heap_open(riinfo->fk_relid, RowShareLock); pk_rel = trigdata->tg_relation; - old_row = trigdata->tg_trigtuple; + oldslot = trigdata->tg_trigslot; switch (riinfo->confmatchtype) { @@ -677,7 +664,7 @@ ri_restrict_del(TriggerData *trigdata, bool is_no_action) */ case FKCONSTR_MATCH_SIMPLE: case FKCONSTR_MATCH_FULL: - switch (ri_NullCheck(old_row, riinfo, true)) + switch (ri_NullCheck(oldslot, riinfo, true)) { case RI_KEYS_ALL_NULL: case RI_KEYS_SOME_NULL: @@ -704,7 +691,7 @@ ri_restrict_del(TriggerData *trigdata, bool is_no_action) * allow another row to be substituted. */ if (is_no_action && - ri_Check_Pk_Match(pk_rel, fk_rel, old_row, riinfo)) + ri_Check_Pk_Match(pk_rel, fk_rel, oldslot, riinfo)) { heap_close(fk_rel, RowShareLock); return PointerGetDatum(NULL); @@ -767,8 +754,8 @@ ri_restrict_del(TriggerData *trigdata, bool is_no_action) */ ri_PerformCheck(riinfo, &qkey, qplan, fk_rel, pk_rel, - old_row, NULL, - true, /* must detect new rows */ + oldslot, NULL, + true, /* must detect new rows */ SPI_OK_SELECT); if (SPI_finish() != SPI_OK_FINISH) @@ -857,8 +844,8 @@ ri_restrict_upd(TriggerData *trigdata, bool is_no_action) const RI_ConstraintInfo *riinfo; Relation fk_rel; Relation pk_rel; - HeapTuple new_row; - HeapTuple old_row; + TupleTableSlot *newslot; + TupleTableSlot *oldslot; RI_QueryKey qkey; SPIPlanPtr qplan; int i; @@ -878,8 +865,8 @@ ri_restrict_upd(TriggerData *trigdata, bool is_no_action) */ fk_rel = heap_open(riinfo->fk_relid, RowShareLock); pk_rel = trigdata->tg_relation; - new_row = trigdata->tg_newtuple; - old_row = trigdata->tg_trigtuple; + newslot = trigdata->tg_newslot; + oldslot = trigdata->tg_trigslot; switch (riinfo->confmatchtype) { @@ -892,7 +879,7 @@ ri_restrict_upd(TriggerData *trigdata, bool is_no_action) */ case FKCONSTR_MATCH_SIMPLE: case FKCONSTR_MATCH_FULL: - switch (ri_NullCheck(old_row, riinfo, true)) + switch (ri_NullCheck(oldslot, riinfo, true)) { case RI_KEYS_ALL_NULL: case RI_KEYS_SOME_NULL: @@ -915,7 +902,7 @@ ri_restrict_upd(TriggerData *trigdata, bool is_no_action) /* * No need to check anything if old and new keys are equal */ - if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true)) + if (ri_KeysEqual(pk_rel, oldslot, newslot, riinfo, true)) { heap_close(fk_rel, RowShareLock); return PointerGetDatum(NULL); @@ -928,7 +915,7 @@ ri_restrict_upd(TriggerData *trigdata, bool is_no_action) * allow another row to be substituted. */ if (is_no_action && - ri_Check_Pk_Match(pk_rel, fk_rel, old_row, riinfo)) + ri_Check_Pk_Match(pk_rel, fk_rel, oldslot, riinfo)) { heap_close(fk_rel, RowShareLock); return PointerGetDatum(NULL); @@ -990,8 +977,8 @@ ri_restrict_upd(TriggerData *trigdata, bool is_no_action) */ ri_PerformCheck(riinfo, &qkey, qplan, fk_rel, pk_rel, - old_row, NULL, - true, /* must detect new rows */ + oldslot, NULL, + true, /* must detect new rows */ SPI_OK_SELECT); if (SPI_finish() != SPI_OK_FINISH) @@ -1034,7 +1021,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) const RI_ConstraintInfo *riinfo; Relation fk_rel; Relation pk_rel; - HeapTuple old_row; + TupleTableSlot *oldslot; RI_QueryKey qkey; SPIPlanPtr qplan; int i; @@ -1058,7 +1045,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) */ fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock); pk_rel = trigdata->tg_relation; - old_row = trigdata->tg_trigtuple; + oldslot = trigdata->tg_trigslot; switch (riinfo->confmatchtype) { @@ -1071,7 +1058,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) */ case FKCONSTR_MATCH_SIMPLE: case FKCONSTR_MATCH_FULL: - switch (ri_NullCheck(old_row, riinfo, true)) + switch (ri_NullCheck(oldslot, riinfo, true)) { case RI_KEYS_ALL_NULL: case RI_KEYS_SOME_NULL: @@ -1146,8 +1133,8 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) */ ri_PerformCheck(riinfo, &qkey, qplan, fk_rel, pk_rel, - old_row, NULL, - true, /* must detect new rows */ + oldslot, NULL, + true, /* must detect new rows */ SPI_OK_DELETE); if (SPI_finish() != SPI_OK_FINISH) @@ -1190,8 +1177,8 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) const RI_ConstraintInfo *riinfo; Relation fk_rel; Relation pk_rel; - HeapTuple new_row; - HeapTuple old_row; + TupleTableSlot *newslot; + TupleTableSlot *oldslot; RI_QueryKey qkey; SPIPlanPtr qplan; int i; @@ -1217,8 +1204,8 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) */ fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock); pk_rel = trigdata->tg_relation; - new_row = trigdata->tg_newtuple; - old_row = trigdata->tg_trigtuple; + newslot = trigdata->tg_newslot; + oldslot = trigdata->tg_trigslot; switch (riinfo->confmatchtype) { @@ -1231,7 +1218,7 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) */ case FKCONSTR_MATCH_SIMPLE: case FKCONSTR_MATCH_FULL: - switch (ri_NullCheck(old_row, riinfo, true)) + switch (ri_NullCheck(oldslot, riinfo, true)) { case RI_KEYS_ALL_NULL: case RI_KEYS_SOME_NULL: @@ -1254,7 +1241,7 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) /* * No need to do anything if old and new keys are equal */ - if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true)) + if (ri_KeysEqual(pk_rel, oldslot, newslot, riinfo, true)) { heap_close(fk_rel, RowExclusiveLock); return PointerGetDatum(NULL); @@ -1327,8 +1314,8 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) */ ri_PerformCheck(riinfo, &qkey, qplan, fk_rel, pk_rel, - old_row, new_row, - true, /* must detect new rows */ + oldslot, newslot, + true, /* must detect new rows */ SPI_OK_UPDATE); if (SPI_finish() != SPI_OK_FINISH) @@ -1371,7 +1358,7 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) const RI_ConstraintInfo *riinfo; Relation fk_rel; Relation pk_rel; - HeapTuple old_row; + TupleTableSlot *oldslot; RI_QueryKey qkey; SPIPlanPtr qplan; int i; @@ -1395,7 +1382,7 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) */ fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock); pk_rel = trigdata->tg_relation; - old_row = trigdata->tg_trigtuple; + oldslot = trigdata->tg_trigslot; switch (riinfo->confmatchtype) { @@ -1408,7 +1395,7 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) */ case FKCONSTR_MATCH_SIMPLE: case FKCONSTR_MATCH_FULL: - switch (ri_NullCheck(old_row, riinfo, true)) + switch (ri_NullCheck(oldslot, riinfo, true)) { case RI_KEYS_ALL_NULL: case RI_KEYS_SOME_NULL: @@ -1492,8 +1479,8 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) */ ri_PerformCheck(riinfo, &qkey, qplan, fk_rel, pk_rel, - old_row, NULL, - true, /* must detect new rows */ + oldslot, NULL, + true, /* must detect new rows */ SPI_OK_UPDATE); if (SPI_finish() != SPI_OK_FINISH) @@ -1536,8 +1523,8 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) const RI_ConstraintInfo *riinfo; Relation fk_rel; Relation pk_rel; - HeapTuple new_row; - HeapTuple old_row; + TupleTableSlot *newslot; + TupleTableSlot *oldslot; RI_QueryKey qkey; SPIPlanPtr qplan; int i; @@ -1561,8 +1548,8 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) */ fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock); pk_rel = trigdata->tg_relation; - new_row = trigdata->tg_newtuple; - old_row = trigdata->tg_trigtuple; + newslot = trigdata->tg_newslot; + oldslot = trigdata->tg_trigslot; switch (riinfo->confmatchtype) { @@ -1575,7 +1562,7 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) */ case FKCONSTR_MATCH_SIMPLE: case FKCONSTR_MATCH_FULL: - switch (ri_NullCheck(old_row, riinfo, true)) + switch (ri_NullCheck(oldslot, riinfo, true)) { case RI_KEYS_ALL_NULL: case RI_KEYS_SOME_NULL: @@ -1598,7 +1585,7 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) /* * No need to do anything if old and new keys are equal */ - if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true)) + if (ri_KeysEqual(pk_rel, oldslot, newslot, riinfo, true)) { heap_close(fk_rel, RowExclusiveLock); return PointerGetDatum(NULL); @@ -1668,8 +1655,8 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) */ ri_PerformCheck(riinfo, &qkey, qplan, fk_rel, pk_rel, - old_row, NULL, - true, /* must detect new rows */ + oldslot, NULL, + true, /* must detect new rows */ SPI_OK_UPDATE); if (SPI_finish() != SPI_OK_FINISH) @@ -1712,7 +1699,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) const RI_ConstraintInfo *riinfo; Relation fk_rel; Relation pk_rel; - HeapTuple old_row; + TupleTableSlot *oldslot; RI_QueryKey qkey; SPIPlanPtr qplan; @@ -1735,7 +1722,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) */ fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock); pk_rel = trigdata->tg_relation; - old_row = trigdata->tg_trigtuple; + oldslot = trigdata->tg_trigslot; switch (riinfo->confmatchtype) { @@ -1748,7 +1735,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) */ case FKCONSTR_MATCH_SIMPLE: case FKCONSTR_MATCH_FULL: - switch (ri_NullCheck(old_row, riinfo, true)) + switch (ri_NullCheck(oldslot, riinfo, true)) { case RI_KEYS_ALL_NULL: case RI_KEYS_SOME_NULL: @@ -1834,8 +1821,8 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) */ ri_PerformCheck(riinfo, &qkey, qplan, fk_rel, pk_rel, - old_row, NULL, - true, /* must detect new rows */ + oldslot, NULL, + true, /* must detect new rows */ SPI_OK_UPDATE); if (SPI_finish() != SPI_OK_FINISH) @@ -1892,8 +1879,8 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) const RI_ConstraintInfo *riinfo; Relation fk_rel; Relation pk_rel; - HeapTuple new_row; - HeapTuple old_row; + TupleTableSlot *newslot; + TupleTableSlot *oldslot; RI_QueryKey qkey; SPIPlanPtr qplan; @@ -1916,8 +1903,8 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) */ fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock); pk_rel = trigdata->tg_relation; - new_row = trigdata->tg_newtuple; - old_row = trigdata->tg_trigtuple; + newslot = trigdata->tg_newslot; + oldslot = trigdata->tg_trigslot; switch (riinfo->confmatchtype) { @@ -1930,7 +1917,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) */ case FKCONSTR_MATCH_SIMPLE: case FKCONSTR_MATCH_FULL: - switch (ri_NullCheck(old_row, riinfo, true)) + switch (ri_NullCheck(oldslot, riinfo, true)) { case RI_KEYS_ALL_NULL: case RI_KEYS_SOME_NULL: @@ -1953,7 +1940,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) /* * No need to do anything if old and new keys are equal */ - if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true)) + if (ri_KeysEqual(pk_rel, oldslot, newslot, riinfo, true)) { heap_close(fk_rel, RowExclusiveLock); return PointerGetDatum(NULL); @@ -2025,8 +2012,8 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) */ ri_PerformCheck(riinfo, &qkey, qplan, fk_rel, pk_rel, - old_row, NULL, - true, /* must detect new rows */ + oldslot, NULL, + true, /* must detect new rows */ SPI_OK_UPDATE); if (SPI_finish() != SPI_OK_FINISH) @@ -2082,7 +2069,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) */ bool RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel, - HeapTuple old_row, HeapTuple new_row) + TupleTableSlot *oldslot, TupleTableSlot *newslot) { const RI_ConstraintInfo *riinfo; @@ -2100,11 +2087,11 @@ RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel, * If any old key value is NULL, the row could not have been * referenced by an FK row, so no check is needed. */ - if (ri_NullCheck(old_row, riinfo, true) != RI_KEYS_NONE_NULL) + if (ri_NullCheck(oldslot, riinfo, true) != RI_KEYS_NONE_NULL) return false; /* If all old and new key values are equal, no check is needed */ - if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true)) + if (ri_KeysEqual(pk_rel, oldslot, newslot, riinfo, true)) return false; /* Else we need to fire the trigger. */ @@ -2139,7 +2126,7 @@ RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel, */ bool RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel, - HeapTuple old_row, HeapTuple new_row) + TupleTableSlot *oldslot, TupleTableSlot *newslot) { const RI_ConstraintInfo *riinfo; @@ -2156,7 +2143,7 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel, * If any new key value is NULL, the row must satisfy the * constraint, so no check is needed. */ - if (ri_NullCheck(new_row, riinfo, false) != RI_KEYS_NONE_NULL) + if (ri_NullCheck(newslot, riinfo, false) != RI_KEYS_NONE_NULL) return false; /* @@ -2167,11 +2154,11 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel, * UPDATE check. (We could skip this if we knew the INSERT * trigger already fired, but there is no easy way to know that.) */ - if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(old_row->t_data))) + if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(oldslot->tts_tuple->t_data))) return true; /* If all old and new key values are equal, no check is needed */ - if (ri_KeysEqual(fk_rel, old_row, new_row, riinfo, false)) + if (ri_KeysEqual(fk_rel, oldslot, newslot, riinfo, false)) return false; /* Else we need to fire the trigger. */ @@ -2187,7 +2174,7 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel, * invalidated before the constraint is to be checked, but we * should queue the event to apply the check later. */ - switch (ri_NullCheck(new_row, riinfo, false)) + switch (ri_NullCheck(newslot, riinfo, false)) { case RI_KEYS_ALL_NULL: return false; @@ -2205,11 +2192,11 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel, * UPDATE check. (We could skip this if we knew the INSERT * trigger already fired, but there is no easy way to know that.) */ - if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(old_row->t_data))) + if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(oldslot->tts_tuple->t_data))) return true; /* If all old and new key values are equal, no check is needed */ - if (ri_KeysEqual(fk_rel, old_row, new_row, riinfo, false)) + if (ri_KeysEqual(fk_rel, oldslot, newslot, riinfo, false)) return false; /* Else we need to fire the trigger. */ @@ -2458,7 +2445,7 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) /* Did we find a tuple violating the constraint? */ if (SPI_processed > 0) { - HeapTuple tuple = SPI_tuptable->vals[0]; + TupleTableSlot *slot = SPI_tuptable->vals[0]; TupleDesc tupdesc = SPI_tuptable->tupdesc; RI_ConstraintInfo fake_riinfo; @@ -2481,7 +2468,7 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) * disallows partially-null FK rows. */ if (fake_riinfo.confmatchtype == FKCONSTR_MATCH_FULL && - ri_NullCheck(tuple, &fake_riinfo, false) != RI_KEYS_NONE_NULL) + ri_NullCheck(slot, &fake_riinfo, false) != RI_KEYS_NONE_NULL) ereport(ERROR, (errcode(ERRCODE_FOREIGN_KEY_VIOLATION), errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"", @@ -2498,7 +2485,7 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) */ ri_ReportViolation(&fake_riinfo, pk_rel, fk_rel, - tuple, tupdesc, + slot, tupdesc, RI_PLAN_CHECK_LOOKUPPK, false); } @@ -3038,11 +3025,10 @@ static bool ri_PerformCheck(const RI_ConstraintInfo *riinfo, RI_QueryKey *qkey, SPIPlanPtr qplan, Relation fk_rel, Relation pk_rel, - HeapTuple old_tuple, HeapTuple new_tuple, + TupleTableSlot *oldslot, TupleTableSlot *newslot, bool detectNewRows, int expect_OK) { - Relation query_rel, - source_rel; + Relation query_rel; bool source_is_pk; Snapshot test_snapshot; Snapshot crosscheck_snapshot; @@ -3070,28 +3056,22 @@ ri_PerformCheck(const RI_ConstraintInfo *riinfo, * need some less klugy way to determine this. */ if (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK) - { - source_rel = fk_rel; source_is_pk = false; - } else - { - source_rel = pk_rel; source_is_pk = true; - } /* Extract the parameters to be passed into the query */ - if (new_tuple) + if (newslot) { - ri_ExtractValues(source_rel, new_tuple, riinfo, source_is_pk, + ri_ExtractValues(newslot, riinfo, source_is_pk, vals, nulls); - if (old_tuple) - ri_ExtractValues(source_rel, old_tuple, riinfo, source_is_pk, + if (oldslot) + ri_ExtractValues(oldslot, riinfo, source_is_pk, vals + riinfo->nkeys, nulls + riinfo->nkeys); } else { - ri_ExtractValues(source_rel, old_tuple, riinfo, source_is_pk, + ri_ExtractValues(oldslot, riinfo, source_is_pk, vals, nulls); } @@ -3149,7 +3129,7 @@ ri_PerformCheck(const RI_ConstraintInfo *riinfo, if (expect_OK >= 0 && spi_result != expect_OK) ri_ReportViolation(riinfo, pk_rel, fk_rel, - new_tuple ? new_tuple : old_tuple, + newslot ? newslot : oldslot, NULL, qkey->constr_queryno, true); @@ -3159,7 +3139,7 @@ ri_PerformCheck(const RI_ConstraintInfo *riinfo, (SPI_processed == 0) == (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK)) ri_ReportViolation(riinfo, pk_rel, fk_rel, - new_tuple ? new_tuple : old_tuple, + newslot ? newslot : oldslot, NULL, qkey->constr_queryno, false); @@ -3170,11 +3150,9 @@ ri_PerformCheck(const RI_ConstraintInfo *riinfo, * Extract fields from a tuple into Datum/nulls arrays */ static void -ri_ExtractValues(Relation rel, HeapTuple tup, - const RI_ConstraintInfo *riinfo, bool rel_is_pk, - Datum *vals, char *nulls) +ri_ExtractValues(TupleTableSlot *slot, const RI_ConstraintInfo *riinfo, + bool rel_is_pk, Datum *vals, char *nulls) { - TupleDesc tupdesc = rel->rd_att; const int16 *attnums; int i; bool isnull; @@ -3186,8 +3164,7 @@ ri_ExtractValues(Relation rel, HeapTuple tup, for (i = 0; i < riinfo->nkeys; i++) { - vals[i] = heap_getattr(tup, attnums[i], tupdesc, - &isnull); + vals[i] = slot_getattr(slot, attnums[i], &isnull); nulls[i] = isnull ? 'n' : ' '; } } @@ -3204,7 +3181,7 @@ ri_ExtractValues(Relation rel, HeapTuple tup, static void ri_ReportViolation(const RI_ConstraintInfo *riinfo, Relation pk_rel, Relation fk_rel, - HeapTuple violator, TupleDesc tupdesc, + TupleTableSlot *violator, TupleDesc tupdesc, int queryno, bool spi_err) { StringInfoData key_names; @@ -3292,7 +3269,7 @@ ri_ReportViolation(const RI_ConstraintInfo *riinfo, *val; name = SPI_fname(tupdesc, fnum); - val = SPI_getvalue(violator, tupdesc, fnum); + val = SPI_getvalue(violator, fnum); if (!val) val = "null"; @@ -3345,7 +3322,7 @@ ri_ReportViolation(const RI_ConstraintInfo *riinfo, * ---------- */ static int -ri_NullCheck(HeapTuple tup, +ri_NullCheck(TupleTableSlot *slot, const RI_ConstraintInfo *riinfo, bool rel_is_pk) { const int16 *attnums; @@ -3360,7 +3337,7 @@ ri_NullCheck(HeapTuple tup, for (i = 0; i < riinfo->nkeys; i++) { - if (heap_attisnull(tup, attnums[i])) + if (slot_attisnull(slot, attnums[i])) nonenull = false; else allnull = false; @@ -3511,10 +3488,9 @@ ri_HashPreparedPlan(RI_QueryKey *key, SPIPlanPtr plan) * ---------- */ static bool -ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup, +ri_KeysEqual(Relation rel, TupleTableSlot *oldslot, TupleTableSlot *newslot, const RI_ConstraintInfo *riinfo, bool rel_is_pk) { - TupleDesc tupdesc = RelationGetDescr(rel); const int16 *attnums; const Oid *eq_oprs; int i; @@ -3539,14 +3515,14 @@ ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup, /* * Get one attribute's oldvalue. If it is NULL - they're not equal. */ - oldvalue = heap_getattr(oldtup, attnums[i], tupdesc, &isnull); + oldvalue = slot_getattr(oldslot, attnums[i], &isnull); if (isnull) return false; /* * Get one attribute's newvalue. If it is NULL - they're not equal. */ - newvalue = heap_getattr(newtup, attnums[i], tupdesc, &isnull); + newvalue = slot_getattr(newslot, attnums[i], &isnull); if (isnull) return false; diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 5cfb916..54a31ce 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -362,9 +362,8 @@ static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell, deparse_namespace *save_dpns); static void pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns); -static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, - int prettyFlags); -static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, +static void make_ruledef(StringInfo buf, TupleTableSlot *ruleslot, int prettyFlags); +static void make_viewdef(StringInfo buf, TupleTableSlot *ruleslot, int prettyFlags, int wrapColumn); static void get_query_def(Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, @@ -515,8 +514,7 @@ pg_get_ruledef_worker(Oid ruleoid, int prettyFlags) Datum args[1]; char nulls[1]; int spirc; - HeapTuple ruletup; - TupleDesc rulettc; + TupleTableSlot *ruleslot; StringInfoData buf; /* @@ -568,9 +566,8 @@ pg_get_ruledef_worker(Oid ruleoid, int prettyFlags) /* * Get the rule's definition and put it into executor's memory */ - ruletup = SPI_tuptable->vals[0]; - rulettc = SPI_tuptable->tupdesc; - make_ruledef(&buf, ruletup, rulettc, prettyFlags); + ruleslot = SPI_tuptable->vals[0]; + make_ruledef(&buf, ruleslot, prettyFlags); } /* @@ -708,8 +705,7 @@ pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn) Datum args[2]; char nulls[2]; int spirc; - HeapTuple ruletup; - TupleDesc rulettc; + TupleTableSlot *ruleslot; StringInfoData buf; /* @@ -764,9 +760,8 @@ pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn) /* * Get the rule's definition and put it into executor's memory */ - ruletup = SPI_tuptable->vals[0]; - rulettc = SPI_tuptable->tupdesc; - make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn); + ruleslot = SPI_tuptable->vals[0]; + make_viewdef(&buf, ruleslot, prettyFlags, wrapColumn); } /* @@ -4580,8 +4575,7 @@ pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns) * ---------- */ static void -make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, - int prettyFlags) +make_ruledef(StringInfo buf, TupleTableSlot *ruleslot, int prettyFlags) { char *rulename; char ev_type; @@ -4593,36 +4587,37 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int fno; Datum dat; bool isnull; + TupleDesc rulettc = ruleslot->tts_tupleDescriptor; /* * Get the attribute values from the rules tuple */ fno = SPI_fnumber(rulettc, "rulename"); - dat = SPI_getbinval(ruletup, rulettc, fno, &isnull); + dat = SPI_getbinval(ruleslot, fno, &isnull); Assert(!isnull); rulename = NameStr(*(DatumGetName(dat))); fno = SPI_fnumber(rulettc, "ev_type"); - dat = SPI_getbinval(ruletup, rulettc, fno, &isnull); + dat = SPI_getbinval(ruleslot, fno, &isnull); Assert(!isnull); ev_type = DatumGetChar(dat); fno = SPI_fnumber(rulettc, "ev_class"); - dat = SPI_getbinval(ruletup, rulettc, fno, &isnull); + dat = SPI_getbinval(ruleslot, fno, &isnull); Assert(!isnull); ev_class = DatumGetObjectId(dat); fno = SPI_fnumber(rulettc, "is_instead"); - dat = SPI_getbinval(ruletup, rulettc, fno, &isnull); + dat = SPI_getbinval(ruleslot, fno, &isnull); Assert(!isnull); is_instead = DatumGetBool(dat); /* these could be nulls */ fno = SPI_fnumber(rulettc, "ev_qual"); - ev_qual = SPI_getvalue(ruletup, rulettc, fno); + ev_qual = SPI_getvalue(ruleslot, fno); fno = SPI_fnumber(rulettc, "ev_action"); - ev_action = SPI_getvalue(ruletup, rulettc, fno); + ev_action = SPI_getvalue(ruleslot, fno); if (ev_action != NULL) actions = (List *) stringToNode(ev_action); @@ -4762,7 +4757,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, * ---------- */ static void -make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, +make_viewdef(StringInfo buf, TupleTableSlot *ruleslot, int prettyFlags, int wrapColumn) { Query *query; @@ -4775,24 +4770,25 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, Relation ev_relation; int fno; bool isnull; + TupleDesc rulettc = ruleslot->tts_tupleDescriptor; /* * Get the attribute values from the rules tuple */ fno = SPI_fnumber(rulettc, "ev_type"); - ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull); + ev_type = (char) SPI_getbinval(ruleslot, fno, &isnull); fno = SPI_fnumber(rulettc, "ev_class"); - ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull); + ev_class = (Oid) SPI_getbinval(ruleslot, fno, &isnull); fno = SPI_fnumber(rulettc, "is_instead"); - is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull); + is_instead = (bool) SPI_getbinval(ruleslot, fno, &isnull); fno = SPI_fnumber(rulettc, "ev_qual"); - ev_qual = SPI_getvalue(ruletup, rulettc, fno); + ev_qual = SPI_getvalue(ruleslot, fno); fno = SPI_fnumber(rulettc, "ev_action"); - ev_action = SPI_getvalue(ruletup, rulettc, fno); + ev_action = SPI_getvalue(ruleslot, fno); if (ev_action != NULL) actions = (List *) stringToNode(ev_action); diff --git a/src/backend/utils/adt/trigfuncs.c b/src/backend/utils/adt/trigfuncs.c index 50ea6d9..7709acd 100644 --- a/src/backend/utils/adt/trigfuncs.c +++ b/src/backend/utils/adt/trigfuncs.c @@ -60,8 +60,8 @@ suppress_redundant_updates_trigger(PG_FUNCTION_ARGS) errmsg("suppress_redundant_updates_trigger: must be called for each row"))); /* get tuple data, set default result */ - rettuple = newtuple = trigdata->tg_newtuple; - oldtuple = trigdata->tg_trigtuple; + rettuple = newtuple = trigdata->tg_newslot->tts_tuple; + oldtuple = trigdata->tg_trigslot->tts_tuple; newheader = newtuple->t_data; oldheader = oldtuple->t_data; diff --git a/src/backend/utils/adt/tsquery_rewrite.c b/src/backend/utils/adt/tsquery_rewrite.c index 1bd3dea..e90b702 100644 --- a/src/backend/utils/adt/tsquery_rewrite.c +++ b/src/backend/utils/adt/tsquery_rewrite.c @@ -326,13 +326,13 @@ tsquery_rewrite_query(PG_FUNCTION_ARGS) for (i = 0; i < SPI_processed && tree; i++) { - Datum qdata = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull); + Datum qdata = SPI_getbinval(SPI_tuptable->vals[i], 1, &isnull); Datum sdata; if (isnull) continue; - sdata = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &isnull); + sdata = SPI_getbinval(SPI_tuptable->vals[i], 2, &isnull); if (!isnull) { diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c index 2d7407c..448a2af 100644 --- a/src/backend/utils/adt/tsvector_op.c +++ b/src/backend/utils/adt/tsvector_op.c @@ -2357,7 +2357,7 @@ ts_stat_sql(MemoryContext persistentContext, text *txt, text *ws) for (i = 0; i < SPI_processed; i++) { - Datum data = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull); + Datum data = SPI_getbinval(SPI_tuptable->vals[i], 1, &isnull); if (!isnull) stat = ts_accum(persistentContext, stat, data); @@ -2456,7 +2456,7 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) TriggerData *trigdata; Trigger *trigger; Relation rel; - HeapTuple rettuple = NULL; + TupleTableSlot *retslot = NULL; int tsvector_attr_num, i; ParsedText prs; @@ -2476,9 +2476,9 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) elog(ERROR, "tsvector_update_trigger: must be fired BEFORE event"); if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) - rettuple = trigdata->tg_trigtuple; + retslot = trigdata->tg_trigslot; else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) - rettuple = trigdata->tg_newtuple; + retslot = trigdata->tg_newslot; else elog(ERROR, "tsvector_update_trigger: must be fired for INSERT or UPDATE"); @@ -2521,7 +2521,7 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) errmsg("column \"%s\" is not of regconfig type", trigger->tgargs[1]))); - datum = SPI_getbinval(rettuple, rel->rd_att, config_attr_num, &isnull); + datum = SPI_getbinval(retslot, config_attr_num, &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), @@ -2566,7 +2566,7 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) errmsg("column \"%s\" is not of a character type", trigger->tgargs[i]))); - datum = SPI_getbinval(rettuple, rel->rd_att, numattr, &isnull); + datum = SPI_getbinval(retslot, numattr, &isnull); if (isnull) continue; @@ -2583,9 +2583,11 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) { datum = PointerGetDatum(make_tsvector(&prs)); isnull = false; - rettuple = heap_modify_tuple_by_cols(rettuple, rel->rd_att, - 1, &tsvector_attr_num, - &datum, &isnull); + + Assert(retslot->tts_tupleDescriptor != rel->rd_att); + retslot = heap_modify_slot_by_cols(retslot, + 1, &tsvector_attr_num, + &datum, &isnull); pfree(DatumGetPointer(datum)); } else @@ -2596,11 +2598,13 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) out->size = 0; datum = PointerGetDatum(out); isnull = false; - rettuple = heap_modify_tuple_by_cols(rettuple, rel->rd_att, + + Assert(retslot->tts_tupleDescriptor != rel->rd_att); + retslot = heap_modify_slot_by_cols(retslot, 1, &tsvector_attr_num, &datum, &isnull); pfree(prs.words); } - return PointerGetDatum(rettuple); + return PointerGetDatum(retslot->tts_tuple); } diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 323614c..e0deec1 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -2331,7 +2331,6 @@ query_to_oid_list(const char *query) bool isnull; oid = SPI_getbinval(SPI_tuptable->vals[i], - SPI_tuptable->tupdesc, 1, &isnull); if (!isnull) @@ -3638,7 +3637,6 @@ SPI_sql_row_to_xmlelement(uint64 rownum, StringInfo result, char *tablename, colname = map_sql_identifier_to_xml_name(SPI_fname(SPI_tuptable->tupdesc, i), true, false); colval = SPI_getbinval(SPI_tuptable->vals[rownum], - SPI_tuptable->tupdesc, i, &isnull); if (isnull) diff --git a/src/include/access/htup.h b/src/include/access/htup.h index 61b3e68..cb3f9f0 100644 --- a/src/include/access/htup.h +++ b/src/include/access/htup.h @@ -68,6 +68,7 @@ typedef struct HeapTupleData } HeapTupleData; typedef HeapTupleData *HeapTuple; +typedef void* StorageTuple; #define HEAPTUPLESIZE MAXALIGN(sizeof(HeapTupleData)) diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h index 36c1134..7bf6e41 100644 --- a/src/include/commands/trigger.h +++ b/src/include/commands/trigger.h @@ -32,11 +32,9 @@ typedef struct TriggerData NodeTag type; TriggerEvent tg_event; Relation tg_relation; - HeapTuple tg_trigtuple; - HeapTuple tg_newtuple; + TupleTableSlot* tg_trigslot; + TupleTableSlot* tg_newslot; Trigger *tg_trigger; - Buffer tg_trigtuplebuf; - Buffer tg_newtuplebuf; Tuplestorestate *tg_oldtable; Tuplestorestate *tg_newtable; } TriggerData; @@ -188,7 +186,7 @@ extern TupleTableSlot *ExecBRInsertTriggers(EState *estate, TupleTableSlot *slot); extern void ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, - HeapTuple trigtuple, + TupleTableSlot *slot, List *recheckIndexes, TransitionCaptureState *transition_capture); extern TupleTableSlot *ExecIRInsertTriggers(EState *estate, @@ -203,15 +201,15 @@ extern bool ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, - HeapTuple fdw_trigtuple); + TupleTableSlot *trigslot); extern void ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, - HeapTuple fdw_trigtuple, + TupleTableSlot *slot, TransitionCaptureState *transition_capture); extern bool ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, - HeapTuple trigtuple); + TupleTableSlot *slot); extern void ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo); extern void ExecASUpdateTriggers(EState *estate, @@ -221,18 +219,18 @@ extern TupleTableSlot *ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, - HeapTuple fdw_trigtuple, + TupleTableSlot *trigslot, TupleTableSlot *slot); extern void ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, - HeapTuple fdw_trigtuple, - HeapTuple newtuple, + TupleTableSlot *oldslot, + TupleTableSlot *slot, List *recheckIndexes, TransitionCaptureState *transition_capture); extern TupleTableSlot *ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, - HeapTuple trigtuple, + TupleTableSlot *oldslot, TupleTableSlot *slot); extern void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo); @@ -254,9 +252,9 @@ extern bool AfterTriggerPendingOnRel(Oid relid); * in utils/adt/ri_triggers.c */ extern bool RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel, - HeapTuple old_row, HeapTuple new_row); + TupleTableSlot *oldslot, TupleTableSlot *newslot); extern bool RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel, - HeapTuple old_row, HeapTuple new_row); + TupleTableSlot *oldslot, TupleTableSlot *newslot); extern bool RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel); diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index acade7e..ca93f89 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -25,7 +25,7 @@ typedef struct SPITupleTable uint64 alloced; /* # of alloced vals */ uint64 free; /* # of free vals */ TupleDesc tupdesc; /* tuple descriptor */ - HeapTuple *vals; /* tuples */ + TupleTableSlot **vals; /* tuples */ slist_node next; /* link for internal bookkeeping */ SubTransactionId subid; /* subxact in which tuptable was created */ } SPITupleTable; @@ -121,10 +121,12 @@ extern HeapTuple SPI_copytuple(HeapTuple tuple); extern HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc); extern HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, Datum *Values, const char *Nulls); +extern TupleTableSlot* SPI_modifyslot(TupleTableSlot *slot, int natts, int *attnum, + Datum *Values, const char *Nulls); extern int SPI_fnumber(TupleDesc tupdesc, const char *fname); extern char *SPI_fname(TupleDesc tupdesc, int fnumber); -extern char *SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber); -extern Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull); +extern char *SPI_getvalue(TupleTableSlot *slot, int fnumber); +extern Datum SPI_getbinval(TupleTableSlot *slot, int fnumber, bool *isnull); extern char *SPI_gettype(TupleDesc tupdesc, int fnumber); extern Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber); extern char *SPI_getrelname(Relation rel); diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h index 55f4cce..13706aa 100644 --- a/src/include/executor/tuptable.h +++ b/src/include/executor/tuptable.h @@ -117,6 +117,7 @@ typedef struct TupleTableSlot bool tts_shouldFree; /* should pfree tts_tuple? */ bool tts_shouldFreeMin; /* should pfree tts_mintuple? */ bool tts_slow; /* saved state for slot_deform_tuple */ + ItemPointerData tts_tid; HeapTuple tts_tuple; /* physical tuple, or NULL if virtual */ TupleDesc tts_tupleDescriptor; /* slot's tuple descriptor */ MemoryContext tts_mcxt; /* slot itself is in this context */ @@ -152,6 +153,11 @@ extern TupleTableSlot *ExecStoreTuple(HeapTuple tuple, extern TupleTableSlot *ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree); +TupleTableSlot* heap_modify_slot_by_cols(TupleTableSlot *slot, + int nCols, + int *replCols, + Datum *replValues, + bool *replIsnull); extern TupleTableSlot *ExecClearTuple(TupleTableSlot *slot); extern TupleTableSlot *ExecStoreVirtualTuple(TupleTableSlot *slot); extern TupleTableSlot *ExecStoreAllNullTuple(TupleTableSlot *slot); diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index 5a45e3e..a760a24 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -1584,7 +1584,7 @@ plperl_trigger_build_args(FunctionCallInfo fcinfo) event = "INSERT"; if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event)) hv_store_string(hv, "new", - plperl_hash_from_tuple(tdata->tg_trigtuple, + plperl_hash_from_tuple(tdata->tg_trigslot, tupdesc)); } else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event)) @@ -1592,7 +1592,7 @@ plperl_trigger_build_args(FunctionCallInfo fcinfo) event = "DELETE"; if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event)) hv_store_string(hv, "old", - plperl_hash_from_tuple(tdata->tg_trigtuple, + plperl_hash_from_tuple(tdata->tg_trigslot, tupdesc)); } else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event)) @@ -1601,10 +1601,10 @@ plperl_trigger_build_args(FunctionCallInfo fcinfo) if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event)) { hv_store_string(hv, "old", - plperl_hash_from_tuple(tdata->tg_trigtuple, + plperl_hash_from_tuple(tdata->tg_trigslot, tupdesc)); hv_store_string(hv, "new", - plperl_hash_from_tuple(tdata->tg_newtuple, + plperl_hash_from_tuple(tdata->tg_newslot, tupdesc)); } } @@ -2486,13 +2486,13 @@ plperl_trigger_handler(PG_FUNCTION_ARGS) TriggerData *trigdata = ((TriggerData *) fcinfo->context); if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) - retval = (Datum) trigdata->tg_trigtuple; + retval = (Datum) trigdata->tg_trigslot; else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) - retval = (Datum) trigdata->tg_newtuple; + retval = (Datum) trigdata->tg_newslot; else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) - retval = (Datum) trigdata->tg_trigtuple; + retval = (Datum) trigdata->tg_trigslot; else if (TRIGGER_FIRED_BY_TRUNCATE(trigdata->tg_event)) - retval = (Datum) trigdata->tg_trigtuple; + retval = (Datum) trigdata->tg_trigslot; else retval = (Datum) 0; /* can this happen? */ } @@ -2511,10 +2511,10 @@ plperl_trigger_handler(PG_FUNCTION_ARGS) if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) trv = plperl_modify_tuple(hvTD, trigdata, - trigdata->tg_trigtuple); + trigdata->tg_trigslot); else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) trv = plperl_modify_tuple(hvTD, trigdata, - trigdata->tg_newtuple); + trigdata->tg_newslot); else { ereport(WARNING, diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 662b3c9..019404d 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -1949,7 +1949,7 @@ plpgsql_build_record(const char *refname, int lineno, bool add2namespace) rec->dtype = PLPGSQL_DTYPE_REC; rec->refname = pstrdup(refname); rec->lineno = lineno; - rec->tup = NULL; + rec->slot = NULL; rec->tupdesc = NULL; rec->freetup = false; rec->freetupdesc = false; diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index c98492b..6f50937 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -275,7 +275,7 @@ static void plpgsql_param_fetch(ParamListInfo params, int paramid); static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, PLpgSQL_row *row, - HeapTuple tup, TupleDesc tupdesc); + TupleTableSlot *slot, TupleDesc tupdesc); static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate, PLpgSQL_row *row, TupleDesc tupdesc); @@ -612,7 +612,7 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, * trigger execution. * ---------- */ -HeapTuple +TupleTableSlot * plpgsql_exec_trigger(PLpgSQL_function *func, TriggerData *trigdata) { @@ -668,23 +668,23 @@ plpgsql_exec_trigger(PLpgSQL_function *func, /* * Per-statement triggers don't use OLD/NEW variables */ - rec_new->tup = NULL; - rec_old->tup = NULL; + rec_new->slot = NULL; + rec_old->slot = NULL; } else if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) { - rec_new->tup = trigdata->tg_trigtuple; - rec_old->tup = NULL; + rec_new->slot = trigdata->tg_trigslot; + rec_old->slot = NULL; } else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) { - rec_new->tup = trigdata->tg_newtuple; - rec_old->tup = trigdata->tg_trigtuple; + rec_new->slot = trigdata->tg_newslot; + rec_old->slot = trigdata->tg_trigslot; } else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) { - rec_new->tup = NULL; - rec_old->tup = trigdata->tg_trigtuple; + rec_new->slot = NULL; + rec_old->slot = trigdata->tg_trigslot; } else elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, or UPDATE"); @@ -1054,7 +1054,7 @@ copy_plpgsql_datum(PLpgSQL_datum *datum) memcpy(new, datum, sizeof(PLpgSQL_rec)); /* should be preset to null/non-freeable */ - Assert(new->tup == NULL); + Assert(new->slot == NULL); Assert(new->tupdesc == NULL); Assert(!new->freetup); Assert(!new->freetupdesc); @@ -1240,7 +1240,7 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) if (rec->freetup) { - heap_freetuple(rec->tup); + ExecDropSingleTupleTableSlot(rec->slot); rec->freetup = false; } if (rec->freetupdesc) @@ -1248,7 +1248,7 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) FreeTupleDesc(rec->tupdesc); rec->freetupdesc = false; } - rec->tup = NULL; + rec->slot = NULL; rec->tupdesc = NULL; } break; @@ -2695,11 +2695,11 @@ exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt) PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar; int32 rettypmod; - if (HeapTupleIsValid(rec->tup)) + if (HeapTupleIsValid(rec->slot)) { if (estate->retistuple) { - estate->retval = PointerGetDatum(rec->tup); + estate->retval = PointerGetDatum(rec->slot->tts_tuple); estate->rettupdesc = rec->tupdesc; estate->retisnull = false; } @@ -2872,7 +2872,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar; TupleConversionMap *tupmap; - if (!HeapTupleIsValid(rec->tup)) + if (!HeapTupleIsValid(rec->slot)) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("record \"%s\" is not assigned yet", @@ -2885,7 +2885,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, tupmap = convert_tuples_by_position(rec->tupdesc, tupdesc, gettext_noop("wrong record type supplied in RETURN NEXT")); - tuple = rec->tup; + tuple = rec->slot->tts_tuple; if (tupmap) tuple = do_convert_tuple(tuple, tupmap); tuplestore_puttuple(estate->tuple_store, tuple); @@ -3058,10 +3058,11 @@ exec_stmt_return_query(PLpgSQL_execstate *estate, for (i = 0; i < SPI_processed; i++) { - HeapTuple tuple = SPI_tuptable->vals[i]; + TupleTableSlot *slot = SPI_tuptable->vals[i]; + HeapTuple tuple; if (tupmap) - tuple = do_convert_tuple(tuple, tupmap); + tuple = do_convert_tuple(slot->tts_tuple, tupmap); tuplestore_puttuple(estate->tuple_store, tuple); if (tupmap) heap_freetuple(tuple); @@ -4552,7 +4553,6 @@ exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target; PLpgSQL_rec *rec; int fno; - HeapTuple newtup; int colnums[1]; Datum values[1]; bool nulls[1]; @@ -4566,7 +4566,7 @@ exec_assign_value(PLpgSQL_execstate *estate, * that because records don't have any predefined field * structure. */ - if (!HeapTupleIsValid(rec->tup)) + if (!HeapTupleIsValid(rec->slot)) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("record \"%s\" is not assigned yet", @@ -4600,15 +4600,9 @@ exec_assign_value(PLpgSQL_execstate *estate, atttypmod); nulls[0] = isNull; - newtup = heap_modify_tuple_by_cols(rec->tup, rec->tupdesc, + rec->slot = heap_modify_slot_by_cols(rec->slot, 1, colnums, values, nulls); - - if (rec->freetup) - heap_freetuple(rec->tup); - - rec->tup = newtup; - rec->freetup = true; - + rec->freetup = false; break; } @@ -4874,7 +4868,7 @@ exec_eval_datum(PLpgSQL_execstate *estate, { PLpgSQL_rec *rec = (PLpgSQL_rec *) datum; - if (!HeapTupleIsValid(rec->tup)) + if (!HeapTupleIsValid(rec->slot)) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("record \"%s\" is not assigned yet", @@ -4887,7 +4881,7 @@ exec_eval_datum(PLpgSQL_execstate *estate, oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); *typeid = rec->tupdesc->tdtypeid; *typetypmod = rec->tupdesc->tdtypmod; - *value = heap_copy_tuple_as_datum(rec->tup, rec->tupdesc); + *value = heap_copy_tuple_as_datum(rec->slot->tts_tuple, rec->tupdesc); *isnull = false; MemoryContextSwitchTo(oldcontext); break; @@ -4900,7 +4894,7 @@ exec_eval_datum(PLpgSQL_execstate *estate, int fno; rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]); - if (!HeapTupleIsValid(rec->tup)) + if (!HeapTupleIsValid(rec->slot)) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("record \"%s\" is not assigned yet", @@ -4917,7 +4911,7 @@ exec_eval_datum(PLpgSQL_execstate *estate, *typetypmod = rec->tupdesc->attrs[fno - 1]->atttypmod; else *typetypmod = -1; - *value = SPI_getbinval(rec->tup, rec->tupdesc, fno, isnull); + *value = SPI_getbinval(rec->slot, fno, isnull); break; } @@ -5236,8 +5230,7 @@ exec_eval_expr(PLpgSQL_execstate *estate, /* * Return the single result Datum. */ - return SPI_getbinval(estate->eval_tuptable->vals[0], - estate->eval_tuptable->tupdesc, 1, isNull); + return SPI_getbinval(estate->eval_tuptable->vals[0], 1, isNull); } @@ -5936,7 +5929,7 @@ static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, PLpgSQL_row *row, - HeapTuple tup, TupleDesc tupdesc) + TupleTableSlot *slot, TupleDesc tupdesc) { /* * Record is simple - just copy the tuple and its descriptor into the @@ -5944,30 +5937,13 @@ exec_move_row(PLpgSQL_execstate *estate, */ if (rec != NULL) { - /* - * Copy input first, just in case it is pointing at variable's value - */ - if (HeapTupleIsValid(tup)) - tup = heap_copytuple(tup); - else if (tupdesc) - { - /* If we have a tupdesc but no data, form an all-nulls tuple */ - bool *nulls; - - nulls = (bool *) - eval_mcontext_alloc(estate, tupdesc->natts * sizeof(bool)); - memset(nulls, true, tupdesc->natts * sizeof(bool)); - - tup = heap_form_tuple(tupdesc, NULL, nulls); - } - if (tupdesc) tupdesc = CreateTupleDescCopy(tupdesc); /* Free the old value ... */ if (rec->freetup) { - heap_freetuple(rec->tup); + ExecDropSingleTupleTableSlot(rec->slot); rec->freetup = false; } if (rec->freetupdesc) @@ -5977,13 +5953,13 @@ exec_move_row(PLpgSQL_execstate *estate, } /* ... and install the new */ - if (HeapTupleIsValid(tup)) + if (HeapTupleIsValid(slot)) { - rec->tup = tup; + ExecCopySlot(rec->slot, slot); rec->freetup = true; } else - rec->tup = NULL; + rec->slot = NULL; if (tupdesc) { @@ -6019,8 +5995,8 @@ exec_move_row(PLpgSQL_execstate *estate, int fnum; int anum; - if (HeapTupleIsValid(tup)) - t_natts = HeapTupleHeaderGetNatts(tup->t_data); + if (HeapTupleIsValid(slot)) + t_natts = HeapTupleHeaderGetNatts(slot->tts_tuple->t_data); else t_natts = 0; @@ -6044,7 +6020,7 @@ exec_move_row(PLpgSQL_execstate *estate, if (anum < td_natts) { if (anum < t_natts) - value = SPI_getbinval(tup, tupdesc, anum + 1, &isnull); + value = SPI_getbinval(slot, anum + 1, &isnull); else { value = (Datum) 0; @@ -6188,6 +6164,7 @@ exec_move_row_from_datum(PLpgSQL_execstate *estate, int32 tupTypmod; TupleDesc tupdesc; HeapTupleData tmptup; + TupleTableSlot *slot; /* Extract rowtype info and find a tupdesc */ tupType = HeapTupleHeaderGetTypeId(td); @@ -6200,8 +6177,11 @@ exec_move_row_from_datum(PLpgSQL_execstate *estate, tmptup.t_tableOid = InvalidOid; tmptup.t_data = td; + slot = MakeSingleTupleTableSlot(tupdesc); + slot->tts_tuple = &tmptup; + /* Do the move */ - exec_move_row(estate, rec, row, &tmptup, tupdesc); + exec_move_row(estate, rec, row, slot, tupdesc); /* Release tupdesc usage count */ ReleaseTupleDesc(tupdesc); diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 2b19948..fc46206 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -304,7 +304,7 @@ typedef struct PLpgSQL_rec char *refname; int lineno; - HeapTuple tup; + TupleTableSlot *slot; TupleDesc tupdesc; bool freetup; bool freetupdesc; diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c index c6938d0..63cdc31 100644 --- a/src/pl/plpython/plpy_exec.c +++ b/src/pl/plpython/plpy_exec.c @@ -790,36 +790,36 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r pltevent = PyString_FromString("INSERT"); PyDict_SetItemString(pltdata, "old", Py_None); - pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple, + pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_trigslot, tdata->tg_relation->rd_att); PyDict_SetItemString(pltdata, "new", pytnew); Py_DECREF(pytnew); - *rv = tdata->tg_trigtuple; + *rv = tdata->tg_trigslot; } else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event)) { pltevent = PyString_FromString("DELETE"); PyDict_SetItemString(pltdata, "new", Py_None); - pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple, + pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigslot, tdata->tg_relation->rd_att); PyDict_SetItemString(pltdata, "old", pytold); Py_DECREF(pytold); - *rv = tdata->tg_trigtuple; + *rv = tdata->tg_trigslot; } else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event)) { pltevent = PyString_FromString("UPDATE"); - pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_newtuple, + pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_newslot, tdata->tg_relation->rd_att); PyDict_SetItemString(pltdata, "new", pytnew); Py_DECREF(pytnew); - pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple, + pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigslot, tdata->tg_relation->rd_att); PyDict_SetItemString(pltdata, "old", pytold); Py_DECREF(pytold); - *rv = tdata->tg_newtuple; + *rv = tdata->tg_newslot; } else { diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index ed494e1..c335eef 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -1134,7 +1134,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, Tcl_NewStringObj("ROW", -1)); /* Build the data list for the trigtuple */ - tcl_trigtup = pltcl_build_tuple_argument(trigdata->tg_trigtuple, + tcl_trigtup = pltcl_build_tuple_argument(trigdata->tg_trigslot, tupdesc); /* @@ -1149,7 +1149,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, Tcl_ListObjAppendElement(NULL, tcl_cmd, tcl_trigtup); Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj()); - rettup = trigdata->tg_trigtuple; + rettup = trigdata->tg_trigslot; } else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) { @@ -1159,20 +1159,20 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj()); Tcl_ListObjAppendElement(NULL, tcl_cmd, tcl_trigtup); - rettup = trigdata->tg_trigtuple; + rettup = trigdata->tg_trigslot; } else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) { Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewStringObj("UPDATE", -1)); - tcl_newtup = pltcl_build_tuple_argument(trigdata->tg_newtuple, + tcl_newtup = pltcl_build_tuple_argument(trigdata->tg_newslot, tupdesc); Tcl_ListObjAppendElement(NULL, tcl_cmd, tcl_newtup); Tcl_ListObjAppendElement(NULL, tcl_cmd, tcl_trigtup); - rettup = trigdata->tg_newtuple; + rettup = trigdata->tg_newslot; } else elog(ERROR, "unrecognized OP tg_event: %u", trigdata->tg_event); diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c index 12c8cd5..cb61dcf 100644 --- a/src/test/modules/worker_spi/worker_spi.c +++ b/src/test/modules/worker_spi/worker_spi.c @@ -126,7 +126,6 @@ initialize_worker_spi(worktable *table) elog(FATAL, "not a singleton result"); ntup = DatumGetInt64(SPI_getbinval(SPI_tuptable->vals[0], - SPI_tuptable->tupdesc, 1, &isnull)); if (isnull) elog(FATAL, "null result"); @@ -281,7 +280,6 @@ worker_spi_main(Datum main_arg) int32 val; val = DatumGetInt32(SPI_getbinval(SPI_tuptable->vals[0], - SPI_tuptable->tupdesc, 1, &isnull)); if (!isnull) elog(LOG, "%s: count in %s.%s is now %d", diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index b73bcce..5e0a941 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -347,7 +347,7 @@ funny_dup17(PG_FUNCTION_ARGS) bool *recursion; Relation rel; TupleDesc tupdesc; - HeapTuple tuple; + TupleTableSlot *slot; char *query, *fieldval, *fieldtype; @@ -359,7 +359,7 @@ funny_dup17(PG_FUNCTION_ARGS) if (!CALLED_AS_TRIGGER(fcinfo)) elog(ERROR, "funny_dup17: not fired by trigger manager"); - tuple = trigdata->tg_trigtuple; + slot = trigdata->tg_trigslot; rel = trigdata->tg_relation; tupdesc = rel->rd_att; if (TRIGGER_FIRED_BEFORE(trigdata->tg_event)) @@ -387,17 +387,17 @@ funny_dup17(PG_FUNCTION_ARGS) if (*level == 17) { *recursion = false; - return PointerGetDatum(tuple); + return PointerGetDatum(slot->tts_tuple); } if (!(*recursion)) - return PointerGetDatum(tuple); + return PointerGetDatum(slot->tts_tuple); (*level)++; SPI_connect(); - fieldval = SPI_getvalue(tuple, tupdesc, 1); + fieldval = SPI_getvalue(slot, 1); fieldtype = SPI_gettype(tupdesc, 1); query = (char *) palloc(100 + NAMEDATALEN * 3 + @@ -426,11 +426,9 @@ funny_dup17(PG_FUNCTION_ARGS) if (SPI_processed > 0) { selected = DatumGetInt32(DirectFunctionCall1(int4in, - CStringGetDatum(SPI_getvalue( - SPI_tuptable->vals[0], - SPI_tuptable->tupdesc, - 1 - )))); + CStringGetDatum(SPI_getvalue( + SPI_tuptable->vals[0], + 1)))); } elog(DEBUG4, "funny_dup17 (fired %s) on level %3d: " UINT64_FORMAT "/%d tuples inserted/selected", @@ -443,7 +441,7 @@ funny_dup17(PG_FUNCTION_ARGS) if (*level == 0) *xid = InvalidTransactionId; - return PointerGetDatum(tuple); + return PointerGetDatum(slot->tts_tuple); } #define TTDUMMY_INFINITY 999999 @@ -468,8 +466,8 @@ ttdummy(PG_FUNCTION_ARGS) char *cnulls; /* column nulls */ char *relname; /* triggered relation name */ Relation rel; /* triggered relation */ - HeapTuple trigtuple; - HeapTuple newtuple = NULL; + TupleTableSlot *trigslot; + TupleTableSlot *newslot = NULL; HeapTuple rettuple; TupleDesc tupdesc; /* tuple description */ int natts; /* # of attributes */ @@ -486,9 +484,9 @@ ttdummy(PG_FUNCTION_ARGS) if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) elog(ERROR, "ttdummy: cannot process INSERT event"); if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) - newtuple = trigdata->tg_newtuple; + newslot = trigdata->tg_newslot; - trigtuple = trigdata->tg_trigtuple; + trigslot = trigdata->tg_trigslot; rel = trigdata->tg_relation; relname = SPI_getrelname(rel); @@ -497,7 +495,8 @@ ttdummy(PG_FUNCTION_ARGS) if (ttoff) /* OFF - nothing to do */ { pfree(relname); - return PointerGetDatum((newtuple != NULL) ? newtuple : trigtuple); + return PointerGetDatum((newslot != NULL) ? + newslot->tts_tuple : trigslot->tts_tuple); } trigger = trigdata->tg_trigger; @@ -521,20 +520,20 @@ ttdummy(PG_FUNCTION_ARGS) relname, args[i]); } - oldon = SPI_getbinval(trigtuple, tupdesc, attnum[0], &isnull); + oldon = SPI_getbinval(trigslot, attnum[0], &isnull); if (isnull) elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[0]); - oldoff = SPI_getbinval(trigtuple, tupdesc, attnum[1], &isnull); + oldoff = SPI_getbinval(trigslot, attnum[1], &isnull); if (isnull) elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[1]); - if (newtuple != NULL) /* UPDATE */ + if (newslot != NULL) /* UPDATE */ { - newon = SPI_getbinval(newtuple, tupdesc, attnum[0], &isnull); + newon = SPI_getbinval(newslot, attnum[0], &isnull); if (isnull) elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[0]); - newoff = SPI_getbinval(newtuple, tupdesc, attnum[1], &isnull); + newoff = SPI_getbinval(newslot, attnum[1], &isnull); if (isnull) elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[1]); @@ -569,13 +568,13 @@ ttdummy(PG_FUNCTION_ARGS) cnulls = (char *) palloc(natts * sizeof(char)); for (i = 0; i < natts; i++) { - cvals[i] = SPI_getbinval((newtuple != NULL) ? newtuple : trigtuple, - tupdesc, i + 1, &isnull); + cvals[i] = SPI_getbinval((newslot != NULL) ? newslot : trigslot, + i + 1, &isnull); cnulls[i] = (isnull) ? 'n' : ' '; } /* change date column(s) */ - if (newtuple) /* UPDATE */ + if (newslot) /* UPDATE */ { cvals[attnum[0] - 1] = newoff; /* start_date eq current date */ cnulls[attnum[0] - 1] = ' '; @@ -628,10 +627,10 @@ ttdummy(PG_FUNCTION_ARGS) elog(ERROR, "ttdummy (%s): SPI_execp returned %d", relname, ret); /* Tuple to return to upper Executor ... */ - if (newtuple) /* UPDATE */ - rettuple = SPI_modifytuple(rel, trigtuple, 1, &(attnum[1]), &newoff, NULL); - else /* DELETE */ - rettuple = trigtuple; + if (newslot) /* UPDATE */ + trigslot = SPI_modifyslot(trigslot, 1, &(attnum[1]), &newoff, NULL); + + rettuple = trigslot->tts_tuple; SPI_finish(); /* don't forget say Bye to SPI mgr */ -- 1.8.3.1