1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Replace uses of SPI_modifytuple that intend to allocate in current context.

Invent a new function heap_modify_tuple_by_cols() that is functionally
equivalent to SPI_modifytuple except that it always allocates its result
by simple palloc.  I chose however to make the API details a bit more
like heap_modify_tuple: pass a tupdesc rather than a Relation, and use
bool convention for the isnull array.

Use this function in place of SPI_modifytuple at all call sites where the
intended behavior is to allocate in current context.  (There actually are
only two call sites left that depend on the old behavior, which makes me
wonder if we should just drop this function rather than keep it.)

This new function is easier to use than heap_modify_tuple() for purposes
of replacing a single column (or, really, any fixed number of columns).
There are a number of places where it would simplify the code to change
over, but I resisted that temptation for the moment ... everywhere except
in plpgsql's exec_assign_value(); changing that might offer some small
performance benefit, so I did it.

This is on the way to removing SPI_push/SPI_pop, but it seems like
good code cleanup in its own right.

Discussion: <9633.1478552022@sss.pgh.pa.us>
This commit is contained in:
Tom Lane
2016-11-08 15:36:36 -05:00
parent dce429b117
commit 9257f07872
10 changed files with 136 additions and 94 deletions

View File

@ -3,6 +3,7 @@
*/
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "commands/sequence.h"
#include "commands/trigger.h"
@ -23,6 +24,7 @@ autoinc(PG_FUNCTION_ARGS)
int *chattrs; /* attnums of attributes to change */
int chnattrs = 0; /* # of above */
Datum *newvals; /* vals of above */
bool *newnulls; /* null flags for above */
char **args; /* arguments */
char *relname; /* triggered relation name */
Relation rel; /* triggered relation */
@ -64,6 +66,7 @@ autoinc(PG_FUNCTION_ARGS)
chattrs = (int *) palloc(nargs / 2 * sizeof(int));
newvals = (Datum *) palloc(nargs / 2 * sizeof(Datum));
newnulls = (bool *) palloc(nargs / 2 * sizeof(bool));
for (i = 0; i < nargs;)
{
@ -102,6 +105,7 @@ autoinc(PG_FUNCTION_ARGS)
newvals[chnattrs] = DirectFunctionCall1(nextval, seqname);
newvals[chnattrs] = Int32GetDatum((int32) DatumGetInt64(newvals[chnattrs]));
}
newnulls[chnattrs] = false;
pfree(DatumGetTextP(seqname));
chnattrs++;
i++;
@ -109,16 +113,15 @@ autoinc(PG_FUNCTION_ARGS)
if (chnattrs > 0)
{
rettuple = SPI_modifytuple(rel, rettuple, chnattrs, chattrs, newvals, NULL);
if (rettuple == NULL)
/* internal error */
elog(ERROR, "autoinc (%s): %d returned by SPI_modifytuple",
relname, SPI_result);
rettuple = heap_modify_tuple_by_cols(rettuple, tupdesc,
chnattrs, chattrs,
newvals, newnulls);
}
pfree(relname);
pfree(chattrs);
pfree(newvals);
pfree(newnulls);
return PointerGetDatum(rettuple);
}

View File

@ -1,6 +1,4 @@
/*
* insert_username.c
* $Modified: Thu Oct 16 08:13:42 1997 by brook $
* contrib/spi/insert_username.c
*
* insert user name in response to a trigger
@ -8,6 +6,7 @@
*/
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "executor/spi.h"
@ -26,6 +25,7 @@ insert_username(PG_FUNCTION_ARGS)
Trigger *trigger; /* to get trigger name */
int nargs; /* # of arguments */
Datum newval; /* new value of column */
bool newnull; /* null flag */
char **args; /* arguments */
char *relname; /* triggered relation name */
Relation rel; /* triggered relation */
@ -80,13 +80,11 @@ insert_username(PG_FUNCTION_ARGS)
/* create fields containing name */
newval = CStringGetTextDatum(GetUserNameFromId(GetUserId(), false));
newnull = false;
/* construct new tuple */
rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newval, NULL);
if (rettuple == NULL)
/* internal error */
elog(ERROR, "insert_username (\"%s\"): %d returned by SPI_modifytuple",
relname, SPI_result);
rettuple = heap_modify_tuple_by_cols(rettuple, tupdesc,
1, &attnum, &newval, &newnull);
pfree(relname);

View File

@ -15,6 +15,7 @@ OH, me, I'm Terry Mackintosh <terry@terrym.com>
*/
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "executor/spi.h"
#include "commands/trigger.h"
@ -34,6 +35,7 @@ moddatetime(PG_FUNCTION_ARGS)
int attnum; /* positional number of field to change */
Oid atttypid; /* type OID of field to change */
Datum newdt; /* The current datetime. */
bool newdtnull; /* null flag for it */
char **args; /* arguments */
char *relname; /* triggered relation name */
Relation rel; /* triggered relation */
@ -115,22 +117,13 @@ moddatetime(PG_FUNCTION_ARGS)
args[0], relname)));
newdt = (Datum) 0; /* keep compiler quiet */
}
newdtnull = false;
/* 1 is the number of items in the arrays attnum and newdt.
attnum is the positional number of the field to be updated.
newdt is the new datetime stamp.
NOTE that attnum and newdt are not arrays, but then a 1 element array
is not an array any more then they are. Thus, they can be considered a
one element array.
*/
rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newdt, NULL);
/* Replace the attnum'th column with newdt */
rettuple = heap_modify_tuple_by_cols(rettuple, tupdesc,
1, &attnum, &newdt, &newdtnull);
if (rettuple == NULL)
/* internal error */
elog(ERROR, "moddatetime (%s): %d returned by SPI_modifytuple",
relname, SPI_result);
/* Clean up */
/* Clean up */
pfree(relname);
return PointerGetDatum(rettuple);

View File

@ -11,6 +11,7 @@
#include <ctype.h>
#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "executor/spi.h"
@ -183,13 +184,13 @@ timetravel(PG_FUNCTION_ARGS)
int chnattrs = 0;
int chattrs[MaxAttrNum];
Datum newvals[MaxAttrNum];
char newnulls[MaxAttrNum];
bool newnulls[MaxAttrNum];
oldtimeon = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_on], &isnull);
if (isnull)
{
newvals[chnattrs] = GetCurrentAbsoluteTime();
newnulls[chnattrs] = ' ';
newnulls[chnattrs] = false;
chattrs[chnattrs] = attnum[a_time_on];
chnattrs++;
}
@ -201,7 +202,7 @@ timetravel(PG_FUNCTION_ARGS)
(chnattrs > 0 && DatumGetInt32(newvals[a_time_on]) >= NOEND_ABSTIME))
elog(ERROR, "timetravel (%s): %s is infinity", relname, args[a_time_on]);
newvals[chnattrs] = NOEND_ABSTIME;
newnulls[chnattrs] = ' ';
newnulls[chnattrs] = false;
chattrs[chnattrs] = attnum[a_time_off];
chnattrs++;
}
@ -220,21 +221,23 @@ timetravel(PG_FUNCTION_ARGS)
{
/* clear update_user value */
newvals[chnattrs] = nulltext;
newnulls[chnattrs] = 'n';
newnulls[chnattrs] = true;
chattrs[chnattrs] = attnum[a_upd_user];
chnattrs++;
/* clear delete_user value */
newvals[chnattrs] = nulltext;
newnulls[chnattrs] = 'n';
newnulls[chnattrs] = true;
chattrs[chnattrs] = attnum[a_del_user];
chnattrs++;
/* set insert_user value */
newvals[chnattrs] = newuser;
newnulls[chnattrs] = ' ';
newnulls[chnattrs] = false;
chattrs[chnattrs] = attnum[a_ins_user];
chnattrs++;
}
rettuple = SPI_modifytuple(rel, trigtuple, chnattrs, chattrs, newvals, newnulls);
rettuple = heap_modify_tuple_by_cols(trigtuple, tupdesc,
chnattrs, chattrs,
newvals, newnulls);
return PointerGetDatum(rettuple);
/* end of INSERT */
}
@ -395,13 +398,11 @@ timetravel(PG_FUNCTION_ARGS)
chnattrs++;
}
rettuple = SPI_modifytuple(rel, newtuple, chnattrs, chattrs, newvals, newnulls);
/*
* SPI_copytuple allocates tmptuple in upper executor context - have
* to free allocation using SPI_pfree
* Use SPI_modifytuple() here because we are inside SPI environment
* but rettuple must be allocated in caller's context.
*/
/* SPI_pfree(tmptuple); */
rettuple = SPI_modifytuple(rel, newtuple, chnattrs, chattrs, newvals, newnulls);
}
else
/* DELETE case */