1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Second round of fmgr changes: triggers are now invoked in new style,

CurrentTriggerData is history.
This commit is contained in:
Tom Lane
2000-05-29 01:59:17 +00:00
parent 147ccf5c80
commit 18952f6744
41 changed files with 666 additions and 674 deletions

View File

@ -2,13 +2,13 @@
#include "executor/spi.h" /* this is what you need to work with SPI */
#include "commands/trigger.h" /* -"- and triggers */
HeapTuple autoinc(void);
extern Datum autoinc(PG_FUNCTION_ARGS);
extern int4 nextval(struct varlena * seqin);
HeapTuple
autoinc()
Datum
autoinc(PG_FUNCTION_ARGS)
{
TriggerData *trigdata = (TriggerData *) fcinfo->context;
Trigger *trigger; /* to get trigger name */
int nargs; /* # of arguments */
int *chattrs; /* attnums of attributes to change */
@ -22,24 +22,24 @@ autoinc()
bool isnull;
int i;
if (!CurrentTriggerData)
elog(ERROR, "autoinc: triggers are not initialized");
if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
if (!CALLED_AS_TRIGGER(fcinfo))
elog(ERROR, "autoinc: not fired by trigger manager");
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
elog(ERROR, "autoinc: can't process STATEMENT events");
if (TRIGGER_FIRED_AFTER(CurrentTriggerData->tg_event))
if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
elog(ERROR, "autoinc: must be fired before event");
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
rettuple = CurrentTriggerData->tg_trigtuple;
else if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
rettuple = CurrentTriggerData->tg_newtuple;
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
rettuple = trigdata->tg_trigtuple;
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
rettuple = trigdata->tg_newtuple;
else
elog(ERROR, "autoinc: can't process DELETE events");
rel = CurrentTriggerData->tg_relation;
rel = trigdata->tg_relation;
relname = SPI_getrelname(rel);
trigger = CurrentTriggerData->tg_trigger;
trigger = trigdata->tg_trigger;
nargs = trigger->tgnargs;
if (nargs <= 0 || nargs % 2 != 0)
@ -48,8 +48,6 @@ autoinc()
args = trigger->tgargs;
tupdesc = rel->rd_att;
CurrentTriggerData = NULL;
chattrs = (int *) palloc(nargs / 2 * sizeof(int));
newvals = (Datum *) palloc(nargs / 2 * sizeof(Datum));
@ -96,5 +94,5 @@ autoinc()
pfree(chattrs);
pfree(newvals);
return (rettuple);
return PointerGetDatum(rettuple);
}

View File

@ -3,4 +3,4 @@ DROP FUNCTION autoinc();
CREATE FUNCTION autoinc()
RETURNS opaque
AS '_OBJWD_/autoinc_DLSUFFIX_'
LANGUAGE 'c';
LANGUAGE 'newC';

View File

@ -10,11 +10,12 @@
#include "commands/trigger.h" /* -"- and triggers */
#include "miscadmin.h" /* for GetPgUserName() */
HeapTuple insert_username(void);
extern Datum insert_username(PG_FUNCTION_ARGS);
HeapTuple
insert_username()
Datum
insert_username(PG_FUNCTION_ARGS)
{
TriggerData *trigdata = (TriggerData *) fcinfo->context;
Trigger *trigger; /* to get trigger name */
int nargs; /* # of arguments */
Datum newval; /* new value of column */
@ -26,24 +27,24 @@ insert_username()
int attnum;
/* sanity checks from autoinc.c */
if (!CurrentTriggerData)
elog(ERROR, "insert_username: triggers are not initialized");
if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
if (!CALLED_AS_TRIGGER(fcinfo))
elog(ERROR, "insert_username: not fired by trigger manager");
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
elog(ERROR, "insert_username: can't process STATEMENT events");
if (TRIGGER_FIRED_AFTER(CurrentTriggerData->tg_event))
if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
elog(ERROR, "insert_username: must be fired before event");
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
rettuple = CurrentTriggerData->tg_trigtuple;
else if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
rettuple = CurrentTriggerData->tg_newtuple;
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
rettuple = trigdata->tg_trigtuple;
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
rettuple = trigdata->tg_newtuple;
else
elog(ERROR, "insert_username: can't process DELETE events");
rel = CurrentTriggerData->tg_relation;
rel = trigdata->tg_relation;
relname = SPI_getrelname(rel);
trigger = CurrentTriggerData->tg_trigger;
trigger = trigdata->tg_trigger;
nargs = trigger->tgnargs;
if (nargs != 1)
@ -52,8 +53,6 @@ insert_username()
args = trigger->tgargs;
tupdesc = rel->rd_att;
CurrentTriggerData = NULL;
attnum = SPI_fnumber(tupdesc, args[0]);
if (attnum < 0)
@ -73,5 +72,5 @@ insert_username()
pfree(relname);
return (rettuple);
return PointerGetDatum(rettuple);
}

View File

@ -3,4 +3,4 @@ DROP FUNCTION insert_username();
CREATE FUNCTION insert_username()
RETURNS opaque
AS '_OBJWD_/insert_username_DLSUFFIX_'
LANGUAGE 'c';
LANGUAGE 'newC';

View File

@ -8,18 +8,19 @@ a modification datetime stamp in a record when that record is UPDATEd.
Credits
This is 95%+ based on autoinc.c, which I used as a starting point as I do
not really know what I am doing. I also had help from
Jan Wieck <jwieck@debis.com> who told me about the datetime_in("now") function.
Jan Wieck <jwieck@debis.com> who told me about the timestamp_in("now") function.
OH, me, I'm Terry Mackintosh <terry@terrym.com>
*/
#include "executor/spi.h" /* this is what you need to work with SPI */
#include "commands/trigger.h" /* -"- and triggers */
HeapTuple moddatetime(void);
extern Datum moddatetime(PG_FUNCTION_ARGS);
HeapTuple
moddatetime()
Datum
moddatetime(PG_FUNCTION_ARGS)
{
TriggerData *trigdata = (TriggerData *) fcinfo->context;
Trigger *trigger; /* to get trigger name */
int nargs; /* # of arguments */
int attnum; /* positional number of field to change */
@ -30,26 +31,26 @@ moddatetime()
HeapTuple rettuple = NULL;
TupleDesc tupdesc; /* tuple description */
if (!CurrentTriggerData)
elog(ERROR, "moddatetime: triggers are not initialized.");
if (!CALLED_AS_TRIGGER(fcinfo))
elog(ERROR, "moddatetime: not fired by trigger manager.");
if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
elog(ERROR, "moddatetime: can't process STATEMENT events.");
if (TRIGGER_FIRED_AFTER(CurrentTriggerData->tg_event))
if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
elog(ERROR, "moddatetime: must be fired before event.");
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
elog(ERROR, "moddatetime: must be fired before event.");
else if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
rettuple = CurrentTriggerData->tg_newtuple;
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
rettuple = trigdata->tg_newtuple;
else
elog(ERROR, "moddatetime: can't process DELETE events.");
rel = CurrentTriggerData->tg_relation;
rel = trigdata->tg_relation;
relname = SPI_getrelname(rel);
trigger = CurrentTriggerData->tg_trigger;
trigger = trigdata->tg_trigger;
nargs = trigger->tgnargs;
@ -60,11 +61,8 @@ moddatetime()
/* must be the field layout? */
tupdesc = rel->rd_att;
/* Why do this? */
CurrentTriggerData = NULL;
/* Get the current datetime. */
newdt = datetime_in("now");
newdt = (Datum) timestamp_in("now");
/*
* This gets the position in the turple of the field we want. args[0]
@ -82,12 +80,12 @@ moddatetime()
args[0]);
/*
* OK, this is where we make sure the datetime field that we are
* modifying is really a datetime field. Hay, error checking, what a
* OK, this is where we make sure the timestamp field that we are
* modifying is really a timestamp field. Hay, error checking, what a
* novel idea !-)
*/
if (SPI_gettypeid(tupdesc, attnum) != DATETIMEOID)
elog(ERROR, "moddatetime (%s): attribute %s must be of DATETIME type",
if (SPI_gettypeid(tupdesc, attnum) != TIMESTAMPOID)
elog(ERROR, "moddatetime (%s): attribute %s must be of TIMESTAMP type",
relname, args[0]);
/* 1 is the number of items in the arrays attnum and newdt.
@ -106,5 +104,5 @@ moddatetime()
/* Clean up */
pfree(relname);
return (rettuple);
return PointerGetDatum(rettuple);
}

View File

@ -3,4 +3,4 @@ DROP FUNCTION moddatetime();
CREATE FUNCTION moddatetime()
RETURNS opaque
AS '_OBJWD_/moddatetime_DLSUFFIX_'
LANGUAGE 'c';
LANGUAGE 'newC';

View File

@ -8,10 +8,8 @@
#include <ctype.h> /* tolower () */
HeapTuple check_primary_key(void);
HeapTuple check_foreign_key(void);
extern Datum check_primary_key(PG_FUNCTION_ARGS);
extern Datum check_foreign_key(PG_FUNCTION_ARGS);
typedef struct
@ -38,9 +36,10 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
* check_primary_key ('Fkey1', 'Fkey2', 'Ptable', 'Pkey1', 'Pkey2').
*/
HeapTuple /* have to return HeapTuple to Executor */
check_primary_key()
Datum
check_primary_key(PG_FUNCTION_ARGS)
{
TriggerData *trigdata = (TriggerData *) fcinfo->context;
Trigger *trigger; /* to get trigger name */
int nargs; /* # of args specified in CREATE TRIGGER */
char **args; /* arguments: column names and table name */
@ -57,33 +56,35 @@ check_primary_key()
int ret;
int i;
/*
* Some checks first...
*/
#ifdef DEBUG_QUERY
elog(NOTICE, "Check_primary_key Enter Function");
#endif
/*
* Some checks first...
*/
/* Called by trigger manager ? */
if (!CurrentTriggerData)
elog(ERROR, "check_primary_key: triggers are not initialized");
if (!CALLED_AS_TRIGGER(fcinfo))
elog(ERROR, "check_primary_key: not fired by trigger manager");
/* Should be called for ROW trigger */
if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
elog(ERROR, "check_primary_key: can't process STATEMENT events");
/* If INSERTion then must check Tuple to being inserted */
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
tuple = CurrentTriggerData->tg_trigtuple;
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
tuple = trigdata->tg_trigtuple;
/* Not should be called for DELETE */
else if (TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event))
else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
elog(ERROR, "check_primary_key: can't process DELETE events");
/* If UPDATion the must check new Tuple, not old one */
else
tuple = CurrentTriggerData->tg_newtuple;
tuple = trigdata->tg_newtuple;
trigger = CurrentTriggerData->tg_trigger;
trigger = trigdata->tg_trigger;
nargs = trigger->tgnargs;
args = trigger->tgargs;
@ -92,16 +93,9 @@ check_primary_key()
nkeys = nargs / 2;
relname = args[nkeys];
rel = CurrentTriggerData->tg_relation;
rel = trigdata->tg_relation;
tupdesc = rel->rd_att;
/*
* Setting CurrentTriggerData to NULL prevents direct calls to trigger
* functions in queries. Normally, trigger functions have to be called
* by trigger manager code only.
*/
CurrentTriggerData = NULL;
/* Connect to SPI manager */
if ((ret = SPI_connect()) < 0)
elog(ERROR, "check_primary_key: SPI_connect returned %d", ret);
@ -145,7 +139,7 @@ check_primary_key()
if (isnull)
{
SPI_finish();
return (tuple);
return PointerGetDatum(tuple);
}
if (plan->nplans <= 0) /* Get typeId of column */
@ -207,7 +201,7 @@ check_primary_key()
SPI_finish();
return (tuple);
return PointerGetDatum(tuple);
}
/*
@ -222,9 +216,10 @@ check_primary_key()
* 'Ftable1', 'Fkey11', 'Fkey12', 'Ftable2', 'Fkey21', 'Fkey22').
*/
HeapTuple /* have to return HeapTuple to Executor */
check_foreign_key()
Datum
check_foreign_key(PG_FUNCTION_ARGS)
{
TriggerData *trigdata = (TriggerData *) fcinfo->context;
Trigger *trigger; /* to get trigger name */
int nargs; /* # of args specified in CREATE TRIGGER */
char **args; /* arguments: as described above */
@ -258,19 +253,19 @@ check_foreign_key()
*/
/* Called by trigger manager ? */
if (!CurrentTriggerData)
elog(ERROR, "check_foreign_key: triggers are not initialized");
if (!CALLED_AS_TRIGGER(fcinfo))
elog(ERROR, "check_foreign_key: not fired by trigger manager");
/* Should be called for ROW trigger */
if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
elog(ERROR, "check_foreign_key: can't process STATEMENT events");
/* Not should be called for INSERT */
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
elog(ERROR, "check_foreign_key: can't process INSERT events");
/* Have to check tg_trigtuple - tuple being deleted */
trigtuple = CurrentTriggerData->tg_trigtuple;
trigtuple = trigdata->tg_trigtuple;
/*
* But if this is UPDATE then we have to return tg_newtuple. Also, if
@ -278,12 +273,12 @@ check_foreign_key()
* do.
*/
is_update = 0;
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
{
newtuple = CurrentTriggerData->tg_newtuple;
newtuple = trigdata->tg_newtuple;
is_update = 1;
}
trigger = CurrentTriggerData->tg_trigger;
trigger = trigdata->tg_trigger;
nargs = trigger->tgnargs;
args = trigger->tgargs;
@ -304,16 +299,9 @@ check_foreign_key()
elog(ERROR, "check_foreign_key: invalid number of arguments %d for %d references",
nargs + 2, nrefs);
rel = CurrentTriggerData->tg_relation;
rel = trigdata->tg_relation;
tupdesc = rel->rd_att;
/*
* Setting CurrentTriggerData to NULL prevents direct calls to trigger
* functions in queries. Normally, trigger functions have to be called
* by trigger manager code only.
*/
CurrentTriggerData = NULL;
/* Connect to SPI manager */
if ((ret = SPI_connect()) < 0)
elog(ERROR, "check_foreign_key: SPI_connect returned %d", ret);
@ -364,7 +352,7 @@ check_foreign_key()
if (isnull)
{
SPI_finish();
return ((newtuple == NULL) ? trigtuple : newtuple);
return PointerGetDatum((newtuple == NULL) ? trigtuple : newtuple);
}
/*
@ -527,7 +515,7 @@ check_foreign_key()
if (newtuple != NULL && isequal)
{
SPI_finish();
return (newtuple);
return PointerGetDatum(newtuple);
}
/*
@ -571,7 +559,7 @@ check_foreign_key()
SPI_finish();
return ((newtuple == NULL) ? trigtuple : newtuple);
return PointerGetDatum((newtuple == NULL) ? trigtuple : newtuple);
}
static EPlan *

View File

@ -4,11 +4,11 @@ DROP FUNCTION check_foreign_key ();
CREATE FUNCTION check_primary_key ()
RETURNS opaque
AS '_OBJWD_/refint_DLSUFFIX_'
LANGUAGE 'c'
LANGUAGE 'newC'
;
CREATE FUNCTION check_foreign_key ()
RETURNS opaque
AS '_OBJWD_/refint_DLSUFFIX_'
LANGUAGE 'c'
LANGUAGE 'newC'
;

View File

@ -10,8 +10,8 @@
#define ABSTIMEOID 702 /* it should be in pg_type.h */
AbsoluteTime currabstime(void);
HeapTuple timetravel(void);
int32 set_timetravel(Name relname, int32 on);
Datum timetravel(PG_FUNCTION_ARGS);
Datum set_timetravel(PG_FUNCTION_ARGS);
typedef struct
{
@ -47,9 +47,10 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
* timetravel ('date_on', 'date_off').
*/
HeapTuple /* have to return HeapTuple to Executor */
timetravel()
Datum
timetravel(PG_FUNCTION_ARGS)
{
TriggerData *trigdata = (TriggerData *) fcinfo->context;
Trigger *trigger; /* to get trigger name */
char **args; /* arguments */
int attnum[2]; /* fnumbers of start/stop columns */
@ -78,27 +79,27 @@ timetravel()
*/
/* Called by trigger manager ? */
if (!CurrentTriggerData)
elog(ERROR, "timetravel: triggers are not initialized");
if (!CALLED_AS_TRIGGER(fcinfo))
elog(ERROR, "timetravel: not fired by trigger manager");
/* Should be called for ROW trigger */
if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
elog(ERROR, "timetravel: can't process STATEMENT events");
/* Should be called BEFORE */
if (TRIGGER_FIRED_AFTER(CurrentTriggerData->tg_event))
if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
elog(ERROR, "timetravel: must be fired before event");
/* INSERT ? */
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
isinsert = true;
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
newtuple = CurrentTriggerData->tg_newtuple;
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
newtuple = trigdata->tg_newtuple;
trigtuple = CurrentTriggerData->tg_trigtuple;
trigtuple = trigdata->tg_trigtuple;
rel = CurrentTriggerData->tg_relation;
rel = trigdata->tg_relation;
relname = SPI_getrelname(rel);
/* check if TT is OFF for this relation */
@ -108,10 +109,10 @@ timetravel()
if (i < nTTOff) /* OFF - nothing to do */
{
pfree(relname);
return ((newtuple != NULL) ? newtuple : trigtuple);
return PointerGetDatum((newtuple != NULL) ? newtuple : trigtuple);
}
trigger = CurrentTriggerData->tg_trigger;
trigger = trigdata->tg_trigger;
if (trigger->tgnargs != 2)
elog(ERROR, "timetravel (%s): invalid (!= 2) number of arguments %d",
@ -121,13 +122,6 @@ timetravel()
tupdesc = rel->rd_att;
natts = tupdesc->natts;
/*
* Setting CurrentTriggerData to NULL prevents direct calls to trigger
* functions in queries. Normally, trigger functions have to be called
* by trigger manager code only.
*/
CurrentTriggerData = NULL;
for (i = 0; i < 2; i++)
{
attnum[i] = SPI_fnumber(tupdesc, args[i]);
@ -175,11 +169,11 @@ timetravel()
pfree(relname);
if (chnattrs <= 0)
return (trigtuple);
return PointerGetDatum(trigtuple);
rettuple = SPI_modifytuple(rel, trigtuple, chnattrs,
chattrs, newvals, NULL);
return (rettuple);
return PointerGetDatum(rettuple);
}
oldon = SPI_getbinval(trigtuple, tupdesc, attnum[0], &isnull);
@ -210,13 +204,13 @@ timetravel()
if (newoff != NOEND_ABSTIME)
{
pfree(relname); /* allocated in upper executor context */
return (NULL);
return PointerGetDatum(NULL);
}
}
else if (oldoff != NOEND_ABSTIME) /* DELETE */
{
pfree(relname);
return (NULL);
return PointerGetDatum(NULL);
}
newoff = GetCurrentAbsoluteTime();
@ -325,16 +319,18 @@ timetravel()
pfree(relname);
return (rettuple);
return PointerGetDatum(rettuple);
}
/*
* set_timetravel () --
* set_timetravel (relname, on) --
* turn timetravel for specified relation ON/OFF
*/
int32
set_timetravel(Name relname, int32 on)
Datum
set_timetravel(PG_FUNCTION_ARGS)
{
Name relname = PG_GETARG_NAME(0);
int32 on = PG_GETARG_INT32(1);
char *rname;
char *d;
char *s;
@ -347,7 +343,7 @@ set_timetravel(Name relname, int32 on)
if (i < nTTOff) /* OFF currently */
{
if (on == 0)
return (0);
PG_RETURN_INT32(0);
/* turn ON */
free(TTOff[i]);
@ -360,12 +356,12 @@ set_timetravel(Name relname, int32 on)
TTOff = realloc(TTOff, (nTTOff - 1) * sizeof(char *));
}
nTTOff--;
return (0);
PG_RETURN_INT32(0);
}
/* ON currently */
if (on != 0)
return (1);
PG_RETURN_INT32(1);
/* turn OFF */
if (nTTOff == 0)
@ -380,8 +376,7 @@ set_timetravel(Name relname, int32 on)
pfree(rname);
nTTOff++;
return (1);
PG_RETURN_INT32(1);
}
AbsoluteTime

View File

@ -4,9 +4,9 @@ DROP FUNCTION set_timetravel(name, int4);
CREATE FUNCTION timetravel()
RETURNS opaque
AS '_OBJWD_/timetravel_DLSUFFIX_'
LANGUAGE 'c';
LANGUAGE 'newC';
CREATE FUNCTION set_timetravel(name, int4)
RETURNS int4
AS '_OBJWD_/timetravel_DLSUFFIX_'
LANGUAGE 'c';
LANGUAGE 'newC' WITH (isStrict);