Re: noupcol code cleanup - Mailing list pgsql-sql
| From | Ron Peterson |
|---|---|
| Subject | Re: noupcol code cleanup |
| Date | |
| Msg-id | 20030110184631.GA14535@mtholyoke.edu Whole thread Raw |
| In response to | Re: insert rule doesn't see id field (Ron Peterson <rpeterso@mtholyoke.edu>) |
| List | pgsql-sql |
Well, I went through this again myself, and fixed a lot of stuff. I'm
going to drop this thread, but didn't want the last chunk of code I
posted to be so crappy. This is what I have come up with, FWIW:
#include "executor/spi.h" /* this is what you need to work with SPI */
#include "commands/trigger.h" /* and triggers */
#include "utils/lsyscache.h" /* for get_typlenbyval */
extern Datum noupcols (PG_FUNCTION_ARGS);
/*
noupcols () -- revoke permission on column(s)
e.g.
CREATE FUNCTION noupcols () RETURNS opaque AS '/usr/lib/postgresql/lib/noupcols.so' LANGUAGE 'C';
CREATE TRIGGER person_noupcols BEFORE UPDATE ON person FOR EACH ROW EXECUTE PROCEDURE noupcols( 'name_last', 'id'
);
Based on code from contrib/noup.c
The approach adopted here is to set the values of all of the columns
specified by noupcols to their old values.
*/
PG_FUNCTION_INFO_V1 (noupcols);
Datum
noupcols (PG_FUNCTION_ARGS)
{ TriggerData *trigdata = (TriggerData *) fcinfo->context; Trigger *trigger; /* to get trigger name
*/ Relation rel; /* triggered relation */ char **args; /* arguments: column
names*/ int ncols; /* # of args specified in CREATE TRIGGER */ int *colindices;
/*array of column indices to modify */ Datum *oldcolvals; /* old column values */ Datum
*newcolval; /* new column value */ HeapTuple oldtuple = NULL; /* tuple before being modified */
HeapTuple newtuple = NULL; /* new tuple after user-specified update */ HeapTuple newnewtuple = NULL; /* tuple
toreturn, after restoring newtuple's protected columns to their old values */ TupleDesc tupdesc; /*
tupledescription */ bool isnull; /* to know is some column NULL or not */ Oid oid;
/* is Datum of type ByVal? */ bool typByVal; /* is Datum of type ByVal? */ int16
typLen; /* Datum size */ int ret; int i;
if (!CALLED_AS_TRIGGER (fcinfo)) elog(ERROR, "noup: not fired by trigger manager");
if (TRIGGER_FIRED_FOR_STATEMENT (trigdata->tg_event)) elog (ERROR, "noup: can't process STATEMENT events");
if (TRIGGER_FIRED_BY_INSERT (trigdata->tg_event)) elog (ERROR, "noup: can't process INSERT events");
else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) elog (ERROR, "noup: can't process DELETE events");
oldtuple = trigdata->tg_trigtuple; newtuple = trigdata->tg_newtuple;
trigger = trigdata->tg_trigger; rel = trigdata->tg_relation;
tupdesc = rel->rd_att;
ncols = trigger->tgnargs; args = trigger->tgargs;
colindices = (int *) palloc (ncols * sizeof (int));
/* Connect to SPI manager */ if ((ret = SPI_connect()) < 0) elog (ERROR, "noupcol: SPI_connect returned %d",
ret);
/* Allocate space to place column values */ oldcolvals = (Datum*) palloc (ncols * sizeof (Datum)); newcolval =
(Datum*)palloc (sizeof (Datum));
/* For each column ... */ for (i = 0; i < ncols; i++) { /* get index of column in tuple */
colindices[i]= SPI_fnumber (tupdesc, args[i]);
/* Bad guys may give us un-existing column in CREATE TRIGGER */ if (colindices[i] ==
SPI_ERROR_NOATTRIBUTE){ elog (ERROR, "noupcols: there is no attribute '%s' in relation '%s'",
args[i], SPI_getrelname (rel)); }
/* Get previous value of column */ oldcolvals[i] = SPI_getbinval (oldtuple, tupdesc, colindices[i],
&isnull); *newcolval = SPI_getbinval (newtuple, tupdesc, colindices[i], &isnull);
/* need this for datumIsEqual, below */ oid = SPI_gettypeid (tupdesc, colindices[i]);
get_typlenbyval(oid, &typLen, &typByVal );
/* if an update is attempted on a locked column, post a notification that it isn't allowed */ if (!
datumIsEqual(oldcolvals[i], *newcolval, typByVal, typLen)) { elog (NOTICE, "noupcols: attribute '%s' in
relation'%s' is locked", args[i], SPI_getrelname (rel)); } }
/* Restore protected columns to their old values */ newnewtuple = SPI_modifytuple (rel, newtuple, ncols,
colindices,oldcolvals, NULL);
if (SPI_result == SPI_ERROR_ARGUMENT) { elog (ERROR, "noupcols: bad argument to SPI_modifytuple\n"); }
if (SPI_result == SPI_ERROR_NOATTRIBUTE) { elog (ERROR, "noupcols: bad attribute value passed to
SPI_modifytuple\n"); }
pfree (oldcolvals); pfree (newcolval); pfree (colindices); SPI_finish ();
return PointerGetDatum (newnewtuple);
}
--
Ron Peterson -o)
Network & Systems Manager /\\
Mount Holyoke College _\_v
http://www.mtholyoke.edu/~rpeterso ----