Second round of fmgr changes: triggers are now invoked in new style,
CurrentTriggerData is history.
This commit is contained in:
parent
147ccf5c80
commit
18952f6744
|
@ -56,7 +56,8 @@ sub-string will fit.
|
||||||
|
|
||||||
The create the function that contains the trigger::
|
The create the function that contains the trigger::
|
||||||
|
|
||||||
create function fti() returns opaque as '/path/to/fti.so' language 'C';
|
create function fti() returns opaque as
|
||||||
|
'/path/to/fti.so' language 'newC';
|
||||||
|
|
||||||
And finally define the trigger on the 'cds' table:
|
And finally define the trigger on the 'cds' table:
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
create function fti() returns opaque as
|
create function fti() returns opaque as
|
||||||
'/home/boekhold/src/postgresql-6.2/contrib/fti/fti.so' language 'c';
|
'/home/boekhold/src/postgresql-6.2/contrib/fti/fti.so' language 'newC';
|
||||||
|
|
||||||
create table title_fti (string varchar(25), id oid);
|
create table title_fti (string varchar(25), id oid);
|
||||||
create index title_fti_idx on title_fti (string);
|
create index title_fti_idx on title_fti (string);
|
||||||
|
@ -61,11 +61,11 @@ select p.* from product p, title_fti f1, title_fti f2 where
|
||||||
that can build the final query automatigally?
|
that can build the final query automatigally?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HeapTuple fti(void);
|
extern Datum fti(PG_FUNCTION_ARGS);
|
||||||
char *breakup(char *, char *);
|
static char *breakup(char *, char *);
|
||||||
bool is_stopword(char *);
|
static bool is_stopword(char *);
|
||||||
|
|
||||||
bool new_tuple = false;
|
static bool new_tuple = false;
|
||||||
|
|
||||||
|
|
||||||
/* THIS LIST MUST BE IN SORTED ORDER, A BINARY SEARCH IS USED!!!! */
|
/* THIS LIST MUST BE IN SORTED ORDER, A BINARY SEARCH IS USED!!!! */
|
||||||
|
@ -93,9 +93,10 @@ static int nDeletePlans = 0;
|
||||||
static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
|
static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
HeapTuple
|
Datum
|
||||||
fti()
|
fti(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
Trigger *trigger; /* to get trigger name */
|
Trigger *trigger; /* to get trigger name */
|
||||||
int nargs; /* # of arguments */
|
int nargs; /* # of arguments */
|
||||||
char **args; /* arguments */
|
char **args; /* arguments */
|
||||||
|
@ -119,32 +120,29 @@ fti()
|
||||||
* function\n"); fflush(debug);
|
* function\n"); fflush(debug);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!CurrentTriggerData)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "Full Text Indexing: triggers are not initialized");
|
elog(ERROR, "Full Text Indexing: not fired by trigger manager");
|
||||||
if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
|
||||||
elog(ERROR, "Full Text Indexing: can't process STATEMENT events");
|
elog(ERROR, "Full Text Indexing: can't process STATEMENT events");
|
||||||
if (TRIGGER_FIRED_BEFORE(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
|
||||||
elog(ERROR, "Full Text Indexing: must be fired AFTER event");
|
elog(ERROR, "Full Text Indexing: must be fired AFTER event");
|
||||||
|
|
||||||
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
|
||||||
isinsert = true;
|
isinsert = true;
|
||||||
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||||
{
|
{
|
||||||
isdelete = true;
|
isdelete = true;
|
||||||
isinsert = true;
|
isinsert = true;
|
||||||
}
|
}
|
||||||
if (TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
|
||||||
isdelete = true;
|
isdelete = true;
|
||||||
|
|
||||||
trigger = CurrentTriggerData->tg_trigger;
|
trigger = trigdata->tg_trigger;
|
||||||
rel = CurrentTriggerData->tg_relation;
|
rel = trigdata->tg_relation;
|
||||||
relname = SPI_getrelname(rel);
|
relname = SPI_getrelname(rel);
|
||||||
rettuple = CurrentTriggerData->tg_trigtuple;
|
rettuple = trigdata->tg_trigtuple;
|
||||||
if (isdelete && isinsert) /* is an UPDATE */
|
if (isdelete && isinsert) /* is an UPDATE */
|
||||||
rettuple = CurrentTriggerData->tg_newtuple;
|
rettuple = trigdata->tg_newtuple;
|
||||||
|
|
||||||
CurrentTriggerData = NULL; /* invalidate 'normal' calls to this
|
|
||||||
* function */
|
|
||||||
|
|
||||||
if ((ret = SPI_connect()) < 0)
|
if ((ret = SPI_connect()) < 0)
|
||||||
elog(ERROR, "Full Text Indexing: SPI_connect failed, returned %d\n", ret);
|
elog(ERROR, "Full Text Indexing: SPI_connect failed, returned %d\n", ret);
|
||||||
|
@ -289,10 +287,10 @@ fti()
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_finish();
|
SPI_finish();
|
||||||
return (rettuple);
|
return PointerGetDatum(rettuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
static char *
|
||||||
breakup(char *string, char *substring)
|
breakup(char *string, char *substring)
|
||||||
{
|
{
|
||||||
static char *last_start;
|
static char *last_start;
|
||||||
|
@ -342,7 +340,7 @@ breakup(char *string, char *substring)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copied from src/backend/parser/keywords.c and adjusted for our situation*/
|
/* copied from src/backend/parser/keywords.c and adjusted for our situation*/
|
||||||
bool
|
static bool
|
||||||
is_stopword(char *text)
|
is_stopword(char *text)
|
||||||
{
|
{
|
||||||
char **StopLow; /* for list of stop-words */
|
char **StopLow; /* for list of stop-words */
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#
|
#
|
||||||
# create function fti() returns opaque as
|
# create function fti() returns opaque as
|
||||||
# '/path/to/fti/file/fti.so'
|
# '/path/to/fti/file/fti.so'
|
||||||
# language 'C';
|
# language 'newC';
|
||||||
#
|
#
|
||||||
# create trigger my_fti_trigger after update or insert or delete
|
# create trigger my_fti_trigger after update or insert or delete
|
||||||
# on mytable
|
# on mytable
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* PostgreSQL type definitions for managed LargeObjects.
|
* PostgreSQL type definitions for managed LargeObjects.
|
||||||
*
|
*
|
||||||
* $Id: lo.c,v 1.2 1999/05/25 16:05:45 momjian Exp $
|
* $Id: lo.c,v 1.3 2000/05/29 01:59:02 tgl Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ Blob *lo_in(char *str); /* Create from String */
|
||||||
char *lo_out(Blob * addr);/* Output oid as String */
|
char *lo_out(Blob * addr);/* Output oid as String */
|
||||||
Oid lo_oid(Blob * addr);/* Return oid as an oid */
|
Oid lo_oid(Blob * addr);/* Return oid as an oid */
|
||||||
Blob *lo(Oid oid); /* Return Blob based on oid */
|
Blob *lo(Oid oid); /* Return Blob based on oid */
|
||||||
HeapTuple lo_manage(void); /* Trigger handler */
|
Datum lo_manage(PG_FUNCTION_ARGS); /* Trigger handler */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This creates a large object, and set's its OID to the value in the
|
* This creates a large object, and set's its OID to the value in the
|
||||||
|
@ -139,9 +139,10 @@ lo(Oid oid)
|
||||||
/*
|
/*
|
||||||
* This handles the trigger that protects us from orphaned large objects
|
* This handles the trigger that protects us from orphaned large objects
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
Datum
|
||||||
lo_manage(void)
|
lo_manage(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
int attnum; /* attribute number to monitor */
|
int attnum; /* attribute number to monitor */
|
||||||
char **args; /* Args containing attr name */
|
char **args; /* Args containing attr name */
|
||||||
TupleDesc tupdesc; /* Tuple Descriptor */
|
TupleDesc tupdesc; /* Tuple Descriptor */
|
||||||
|
@ -150,28 +151,25 @@ lo_manage(void)
|
||||||
HeapTuple newtuple = NULL;/* The new value for tuple */
|
HeapTuple newtuple = NULL;/* The new value for tuple */
|
||||||
HeapTuple trigtuple; /* The original value of tuple */
|
HeapTuple trigtuple; /* The original value of tuple */
|
||||||
|
|
||||||
if (!CurrentTriggerData)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "lo: triggers are not initialized");
|
elog(ERROR, "lo: not fired by trigger manager");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fetch some values from CurrentTriggerData
|
* Fetch some values from trigdata
|
||||||
*/
|
*/
|
||||||
newtuple = CurrentTriggerData->tg_newtuple;
|
newtuple = trigdata->tg_newtuple;
|
||||||
trigtuple = CurrentTriggerData->tg_trigtuple;
|
trigtuple = trigdata->tg_trigtuple;
|
||||||
tupdesc = CurrentTriggerData->tg_relation->rd_att;
|
tupdesc = trigdata->tg_relation->rd_att;
|
||||||
args = CurrentTriggerData->tg_trigger->tgargs;
|
args = trigdata->tg_trigger->tgargs;
|
||||||
|
|
||||||
/* tuple to return to Executor */
|
/* tuple to return to Executor */
|
||||||
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||||
rettuple = newtuple;
|
rettuple = newtuple;
|
||||||
else
|
else
|
||||||
rettuple = trigtuple;
|
rettuple = trigtuple;
|
||||||
|
|
||||||
/* Are we deleting the row? */
|
/* Are we deleting the row? */
|
||||||
isdelete = TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event);
|
isdelete = TRIGGER_FIRED_BY_DELETE(trigdata->tg_event);
|
||||||
|
|
||||||
/* Were done with it */
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
|
|
||||||
/* Get the column were interested in */
|
/* Get the column were interested in */
|
||||||
attnum = SPI_fnumber(tupdesc, args[0]);
|
attnum = SPI_fnumber(tupdesc, args[0]);
|
||||||
|
@ -214,5 +212,5 @@ lo_manage(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (rettuple);
|
return PointerGetDatum(rettuple);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
--
|
--
|
||||||
-- PostgreSQL code for LargeObjects
|
-- PostgreSQL code for LargeObjects
|
||||||
--
|
--
|
||||||
-- $Id: lo.sql.in,v 1.1 1998/06/16 07:07:11 momjian Exp $
|
-- $Id: lo.sql.in,v 1.2 2000/05/29 01:59:02 tgl Exp $
|
||||||
--
|
--
|
||||||
|
|
||||||
load '_OBJWD_/lo_DLSUFFIX_';
|
load '_OBJWD_/lo_DLSUFFIX_';
|
||||||
|
@ -47,7 +47,7 @@ create function lo(oid)
|
||||||
create function lo_manage()
|
create function lo_manage()
|
||||||
returns opaque
|
returns opaque
|
||||||
as '_OBJWD_/lo_DLSUFFIX_'
|
as '_OBJWD_/lo_DLSUFFIX_'
|
||||||
language 'c';
|
language 'newC';
|
||||||
|
|
||||||
-- This allows us to map lo to oid
|
-- This allows us to map lo to oid
|
||||||
--
|
--
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include "commands/trigger.h" /* -"- and triggers */
|
#include "commands/trigger.h" /* -"- and triggers */
|
||||||
#include <ctype.h> /* tolower () */
|
#include <ctype.h> /* tolower () */
|
||||||
|
|
||||||
HeapTuple noup(void);
|
extern Datum noup(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* noup () -- revoke permission on column
|
* noup () -- revoke permission on column
|
||||||
|
@ -16,9 +16,10 @@ HeapTuple noup(void);
|
||||||
* EXECUTE PROCEDURE noup ('col').
|
* EXECUTE PROCEDURE noup ('col').
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HeapTuple /* have to return HeapTuple to Executor */
|
Datum
|
||||||
noup()
|
noup(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
Trigger *trigger; /* to get trigger name */
|
Trigger *trigger; /* to get trigger name */
|
||||||
int nargs; /* # of args specified in CREATE TRIGGER */
|
int nargs; /* # of args specified in CREATE TRIGGER */
|
||||||
char **args; /* arguments: column names and table name */
|
char **args; /* arguments: column names and table name */
|
||||||
|
@ -36,42 +37,35 @@ noup()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Called by trigger manager ? */
|
/* Called by trigger manager ? */
|
||||||
if (!CurrentTriggerData)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(WARN, "noup: triggers are not initialized");
|
elog(ERROR, "noup: not fired by trigger manager");
|
||||||
|
|
||||||
/* Should be called for ROW trigger */
|
/* Should be called for ROW trigger */
|
||||||
if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
|
||||||
elog(WARN, "noup: can't process STATEMENT events");
|
elog(ERROR, "noup: can't process STATEMENT events");
|
||||||
|
|
||||||
/* Not should be called for INSERT */
|
/* Not should be called for INSERT */
|
||||||
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
|
||||||
elog(WARN, "noup: can't process INSERT events");
|
elog(ERROR, "noup: can't process INSERT events");
|
||||||
|
|
||||||
/* Not should be called for DELETE */
|
/* 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(WARN, "noup: can't process DELETE events");
|
elog(ERROR, "noup: can't process DELETE events");
|
||||||
|
|
||||||
/* check new Tuple */
|
/* check new Tuple */
|
||||||
tuple = CurrentTriggerData->tg_newtuple;
|
tuple = trigdata->tg_newtuple;
|
||||||
|
|
||||||
trigger = CurrentTriggerData->tg_trigger;
|
trigger = trigdata->tg_trigger;
|
||||||
nargs = trigger->tgnargs;
|
nargs = trigger->tgnargs;
|
||||||
args = trigger->tgargs;
|
args = trigger->tgargs;
|
||||||
|
|
||||||
nkeys = nargs;
|
nkeys = nargs;
|
||||||
rel = CurrentTriggerData->tg_relation;
|
rel = trigdata->tg_relation;
|
||||||
tupdesc = rel->rd_att;
|
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 */
|
/* Connect to SPI manager */
|
||||||
if ((ret = SPI_connect()) < 0)
|
if ((ret = SPI_connect()) < 0)
|
||||||
elog(WARN, "noup: SPI_connect returned %d", ret);
|
elog(ERROR, "noup: SPI_connect returned %d", ret);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We use SPI plan preparation feature, so allocate space to place key
|
* We use SPI plan preparation feature, so allocate space to place key
|
||||||
|
@ -87,7 +81,7 @@ noup()
|
||||||
|
|
||||||
/* Bad guys may give us un-existing column in CREATE TRIGGER */
|
/* Bad guys may give us un-existing column in CREATE TRIGGER */
|
||||||
if (fnumber < 0)
|
if (fnumber < 0)
|
||||||
elog(WARN, "noup: there is no attribute %s in relation %s",
|
elog(ERROR, "noup: there is no attribute %s in relation %s",
|
||||||
args[i], SPI_getrelname(rel));
|
args[i], SPI_getrelname(rel));
|
||||||
|
|
||||||
/* Well, get binary (in internal format) value of column */
|
/* Well, get binary (in internal format) value of column */
|
||||||
|
@ -99,13 +93,13 @@ noup()
|
||||||
if (!isnull)
|
if (!isnull)
|
||||||
{
|
{
|
||||||
|
|
||||||
elog(WARN, "%s: update not allowed", args[i]);
|
elog(NOTICE, "%s: update not allowed", args[i]);
|
||||||
SPI_finish();
|
SPI_finish();
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_finish();
|
SPI_finish();
|
||||||
return (tuple);
|
return PointerGetDatum(tuple);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,5 +3,5 @@ DROP FUNCTION noup ();
|
||||||
CREATE FUNCTION noup ()
|
CREATE FUNCTION noup ()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/noup_DLSUFFIX_'
|
AS '_OBJWD_/noup_DLSUFFIX_'
|
||||||
LANGUAGE 'c'
|
LANGUAGE 'newC'
|
||||||
;
|
;
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
#include "executor/spi.h" /* this is what you need to work with SPI */
|
#include "executor/spi.h" /* this is what you need to work with SPI */
|
||||||
#include "commands/trigger.h" /* -"- and triggers */
|
#include "commands/trigger.h" /* -"- and triggers */
|
||||||
|
|
||||||
HeapTuple autoinc(void);
|
extern Datum autoinc(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
extern int4 nextval(struct varlena * seqin);
|
extern int4 nextval(struct varlena * seqin);
|
||||||
|
|
||||||
HeapTuple
|
Datum
|
||||||
autoinc()
|
autoinc(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
Trigger *trigger; /* to get trigger name */
|
Trigger *trigger; /* to get trigger name */
|
||||||
int nargs; /* # of arguments */
|
int nargs; /* # of arguments */
|
||||||
int *chattrs; /* attnums of attributes to change */
|
int *chattrs; /* attnums of attributes to change */
|
||||||
|
@ -22,24 +22,24 @@ autoinc()
|
||||||
bool isnull;
|
bool isnull;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!CurrentTriggerData)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "autoinc: triggers are not initialized");
|
elog(ERROR, "autoinc: not fired by trigger manager");
|
||||||
if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
|
||||||
elog(ERROR, "autoinc: can't process STATEMENT events");
|
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");
|
elog(ERROR, "autoinc: must be fired before event");
|
||||||
|
|
||||||
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
|
||||||
rettuple = CurrentTriggerData->tg_trigtuple;
|
rettuple = trigdata->tg_trigtuple;
|
||||||
else if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||||
rettuple = CurrentTriggerData->tg_newtuple;
|
rettuple = trigdata->tg_newtuple;
|
||||||
else
|
else
|
||||||
elog(ERROR, "autoinc: can't process DELETE events");
|
elog(ERROR, "autoinc: can't process DELETE events");
|
||||||
|
|
||||||
rel = CurrentTriggerData->tg_relation;
|
rel = trigdata->tg_relation;
|
||||||
relname = SPI_getrelname(rel);
|
relname = SPI_getrelname(rel);
|
||||||
|
|
||||||
trigger = CurrentTriggerData->tg_trigger;
|
trigger = trigdata->tg_trigger;
|
||||||
|
|
||||||
nargs = trigger->tgnargs;
|
nargs = trigger->tgnargs;
|
||||||
if (nargs <= 0 || nargs % 2 != 0)
|
if (nargs <= 0 || nargs % 2 != 0)
|
||||||
|
@ -48,8 +48,6 @@ autoinc()
|
||||||
args = trigger->tgargs;
|
args = trigger->tgargs;
|
||||||
tupdesc = rel->rd_att;
|
tupdesc = rel->rd_att;
|
||||||
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
|
|
||||||
chattrs = (int *) palloc(nargs / 2 * sizeof(int));
|
chattrs = (int *) palloc(nargs / 2 * sizeof(int));
|
||||||
newvals = (Datum *) palloc(nargs / 2 * sizeof(Datum));
|
newvals = (Datum *) palloc(nargs / 2 * sizeof(Datum));
|
||||||
|
|
||||||
|
@ -96,5 +94,5 @@ autoinc()
|
||||||
pfree(chattrs);
|
pfree(chattrs);
|
||||||
pfree(newvals);
|
pfree(newvals);
|
||||||
|
|
||||||
return (rettuple);
|
return PointerGetDatum(rettuple);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,4 @@ DROP FUNCTION autoinc();
|
||||||
CREATE FUNCTION autoinc()
|
CREATE FUNCTION autoinc()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/autoinc_DLSUFFIX_'
|
AS '_OBJWD_/autoinc_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
|
|
|
@ -10,11 +10,12 @@
|
||||||
#include "commands/trigger.h" /* -"- and triggers */
|
#include "commands/trigger.h" /* -"- and triggers */
|
||||||
#include "miscadmin.h" /* for GetPgUserName() */
|
#include "miscadmin.h" /* for GetPgUserName() */
|
||||||
|
|
||||||
HeapTuple insert_username(void);
|
extern Datum insert_username(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
HeapTuple
|
Datum
|
||||||
insert_username()
|
insert_username(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
Trigger *trigger; /* to get trigger name */
|
Trigger *trigger; /* to get trigger name */
|
||||||
int nargs; /* # of arguments */
|
int nargs; /* # of arguments */
|
||||||
Datum newval; /* new value of column */
|
Datum newval; /* new value of column */
|
||||||
|
@ -26,24 +27,24 @@ insert_username()
|
||||||
int attnum;
|
int attnum;
|
||||||
|
|
||||||
/* sanity checks from autoinc.c */
|
/* sanity checks from autoinc.c */
|
||||||
if (!CurrentTriggerData)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "insert_username: triggers are not initialized");
|
elog(ERROR, "insert_username: not fired by trigger manager");
|
||||||
if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
|
||||||
elog(ERROR, "insert_username: can't process STATEMENT events");
|
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");
|
elog(ERROR, "insert_username: must be fired before event");
|
||||||
|
|
||||||
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
|
||||||
rettuple = CurrentTriggerData->tg_trigtuple;
|
rettuple = trigdata->tg_trigtuple;
|
||||||
else if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||||
rettuple = CurrentTriggerData->tg_newtuple;
|
rettuple = trigdata->tg_newtuple;
|
||||||
else
|
else
|
||||||
elog(ERROR, "insert_username: can't process DELETE events");
|
elog(ERROR, "insert_username: can't process DELETE events");
|
||||||
|
|
||||||
rel = CurrentTriggerData->tg_relation;
|
rel = trigdata->tg_relation;
|
||||||
relname = SPI_getrelname(rel);
|
relname = SPI_getrelname(rel);
|
||||||
|
|
||||||
trigger = CurrentTriggerData->tg_trigger;
|
trigger = trigdata->tg_trigger;
|
||||||
|
|
||||||
nargs = trigger->tgnargs;
|
nargs = trigger->tgnargs;
|
||||||
if (nargs != 1)
|
if (nargs != 1)
|
||||||
|
@ -52,8 +53,6 @@ insert_username()
|
||||||
args = trigger->tgargs;
|
args = trigger->tgargs;
|
||||||
tupdesc = rel->rd_att;
|
tupdesc = rel->rd_att;
|
||||||
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
|
|
||||||
attnum = SPI_fnumber(tupdesc, args[0]);
|
attnum = SPI_fnumber(tupdesc, args[0]);
|
||||||
|
|
||||||
if (attnum < 0)
|
if (attnum < 0)
|
||||||
|
@ -73,5 +72,5 @@ insert_username()
|
||||||
|
|
||||||
pfree(relname);
|
pfree(relname);
|
||||||
|
|
||||||
return (rettuple);
|
return PointerGetDatum(rettuple);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,4 @@ DROP FUNCTION insert_username();
|
||||||
CREATE FUNCTION insert_username()
|
CREATE FUNCTION insert_username()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/insert_username_DLSUFFIX_'
|
AS '_OBJWD_/insert_username_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
|
|
|
@ -8,18 +8,19 @@ a modification datetime stamp in a record when that record is UPDATEd.
|
||||||
Credits
|
Credits
|
||||||
This is 95%+ based on autoinc.c, which I used as a starting point as I do
|
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
|
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>
|
OH, me, I'm Terry Mackintosh <terry@terrym.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "executor/spi.h" /* this is what you need to work with SPI */
|
#include "executor/spi.h" /* this is what you need to work with SPI */
|
||||||
#include "commands/trigger.h" /* -"- and triggers */
|
#include "commands/trigger.h" /* -"- and triggers */
|
||||||
|
|
||||||
HeapTuple moddatetime(void);
|
extern Datum moddatetime(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
HeapTuple
|
Datum
|
||||||
moddatetime()
|
moddatetime(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
Trigger *trigger; /* to get trigger name */
|
Trigger *trigger; /* to get trigger name */
|
||||||
int nargs; /* # of arguments */
|
int nargs; /* # of arguments */
|
||||||
int attnum; /* positional number of field to change */
|
int attnum; /* positional number of field to change */
|
||||||
|
@ -30,26 +31,26 @@ moddatetime()
|
||||||
HeapTuple rettuple = NULL;
|
HeapTuple rettuple = NULL;
|
||||||
TupleDesc tupdesc; /* tuple description */
|
TupleDesc tupdesc; /* tuple description */
|
||||||
|
|
||||||
if (!CurrentTriggerData)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "moddatetime: triggers are not initialized.");
|
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.");
|
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.");
|
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.");
|
elog(ERROR, "moddatetime: must be fired before event.");
|
||||||
else if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||||
rettuple = CurrentTriggerData->tg_newtuple;
|
rettuple = trigdata->tg_newtuple;
|
||||||
else
|
else
|
||||||
elog(ERROR, "moddatetime: can't process DELETE events.");
|
elog(ERROR, "moddatetime: can't process DELETE events.");
|
||||||
|
|
||||||
rel = CurrentTriggerData->tg_relation;
|
rel = trigdata->tg_relation;
|
||||||
relname = SPI_getrelname(rel);
|
relname = SPI_getrelname(rel);
|
||||||
|
|
||||||
trigger = CurrentTriggerData->tg_trigger;
|
trigger = trigdata->tg_trigger;
|
||||||
|
|
||||||
nargs = trigger->tgnargs;
|
nargs = trigger->tgnargs;
|
||||||
|
|
||||||
|
@ -60,11 +61,8 @@ moddatetime()
|
||||||
/* must be the field layout? */
|
/* must be the field layout? */
|
||||||
tupdesc = rel->rd_att;
|
tupdesc = rel->rd_att;
|
||||||
|
|
||||||
/* Why do this? */
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
|
|
||||||
/* Get the current datetime. */
|
/* 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]
|
* This gets the position in the turple of the field we want. args[0]
|
||||||
|
@ -82,12 +80,12 @@ moddatetime()
|
||||||
args[0]);
|
args[0]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OK, this is where we make sure the datetime field that we are
|
* OK, this is where we make sure the timestamp field that we are
|
||||||
* modifying is really a datetime field. Hay, error checking, what a
|
* modifying is really a timestamp field. Hay, error checking, what a
|
||||||
* novel idea !-)
|
* novel idea !-)
|
||||||
*/
|
*/
|
||||||
if (SPI_gettypeid(tupdesc, attnum) != DATETIMEOID)
|
if (SPI_gettypeid(tupdesc, attnum) != TIMESTAMPOID)
|
||||||
elog(ERROR, "moddatetime (%s): attribute %s must be of DATETIME type",
|
elog(ERROR, "moddatetime (%s): attribute %s must be of TIMESTAMP type",
|
||||||
relname, args[0]);
|
relname, args[0]);
|
||||||
|
|
||||||
/* 1 is the number of items in the arrays attnum and newdt.
|
/* 1 is the number of items in the arrays attnum and newdt.
|
||||||
|
@ -106,5 +104,5 @@ moddatetime()
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
pfree(relname);
|
pfree(relname);
|
||||||
|
|
||||||
return (rettuple);
|
return PointerGetDatum(rettuple);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,4 @@ DROP FUNCTION moddatetime();
|
||||||
CREATE FUNCTION moddatetime()
|
CREATE FUNCTION moddatetime()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/moddatetime_DLSUFFIX_'
|
AS '_OBJWD_/moddatetime_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
|
|
|
@ -8,10 +8,8 @@
|
||||||
#include <ctype.h> /* tolower () */
|
#include <ctype.h> /* tolower () */
|
||||||
|
|
||||||
|
|
||||||
|
extern Datum check_primary_key(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum check_foreign_key(PG_FUNCTION_ARGS);
|
||||||
HeapTuple check_primary_key(void);
|
|
||||||
HeapTuple check_foreign_key(void);
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -38,9 +36,10 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
|
||||||
* check_primary_key ('Fkey1', 'Fkey2', 'Ptable', 'Pkey1', 'Pkey2').
|
* check_primary_key ('Fkey1', 'Fkey2', 'Ptable', 'Pkey1', 'Pkey2').
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HeapTuple /* have to return HeapTuple to Executor */
|
Datum
|
||||||
check_primary_key()
|
check_primary_key(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
Trigger *trigger; /* to get trigger name */
|
Trigger *trigger; /* to get trigger name */
|
||||||
int nargs; /* # of args specified in CREATE TRIGGER */
|
int nargs; /* # of args specified in CREATE TRIGGER */
|
||||||
char **args; /* arguments: column names and table name */
|
char **args; /* arguments: column names and table name */
|
||||||
|
@ -57,33 +56,35 @@ check_primary_key()
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
|
||||||
* Some checks first...
|
|
||||||
*/
|
|
||||||
#ifdef DEBUG_QUERY
|
#ifdef DEBUG_QUERY
|
||||||
elog(NOTICE, "Check_primary_key Enter Function");
|
elog(NOTICE, "Check_primary_key Enter Function");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some checks first...
|
||||||
|
*/
|
||||||
|
|
||||||
/* Called by trigger manager ? */
|
/* Called by trigger manager ? */
|
||||||
if (!CurrentTriggerData)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "check_primary_key: triggers are not initialized");
|
elog(ERROR, "check_primary_key: not fired by trigger manager");
|
||||||
|
|
||||||
/* Should be called for ROW trigger */
|
/* 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");
|
elog(ERROR, "check_primary_key: can't process STATEMENT events");
|
||||||
|
|
||||||
/* If INSERTion then must check Tuple to being inserted */
|
/* If INSERTion then must check Tuple to being inserted */
|
||||||
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
|
||||||
tuple = CurrentTriggerData->tg_trigtuple;
|
tuple = trigdata->tg_trigtuple;
|
||||||
|
|
||||||
/* Not should be called for DELETE */
|
/* 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");
|
elog(ERROR, "check_primary_key: can't process DELETE events");
|
||||||
|
|
||||||
/* If UPDATion the must check new Tuple, not old one */
|
/* If UPDATion the must check new Tuple, not old one */
|
||||||
else
|
else
|
||||||
tuple = CurrentTriggerData->tg_newtuple;
|
tuple = trigdata->tg_newtuple;
|
||||||
|
|
||||||
trigger = CurrentTriggerData->tg_trigger;
|
trigger = trigdata->tg_trigger;
|
||||||
nargs = trigger->tgnargs;
|
nargs = trigger->tgnargs;
|
||||||
args = trigger->tgargs;
|
args = trigger->tgargs;
|
||||||
|
|
||||||
|
@ -92,16 +93,9 @@ check_primary_key()
|
||||||
|
|
||||||
nkeys = nargs / 2;
|
nkeys = nargs / 2;
|
||||||
relname = args[nkeys];
|
relname = args[nkeys];
|
||||||
rel = CurrentTriggerData->tg_relation;
|
rel = trigdata->tg_relation;
|
||||||
tupdesc = rel->rd_att;
|
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 */
|
/* Connect to SPI manager */
|
||||||
if ((ret = SPI_connect()) < 0)
|
if ((ret = SPI_connect()) < 0)
|
||||||
elog(ERROR, "check_primary_key: SPI_connect returned %d", ret);
|
elog(ERROR, "check_primary_key: SPI_connect returned %d", ret);
|
||||||
|
@ -145,7 +139,7 @@ check_primary_key()
|
||||||
if (isnull)
|
if (isnull)
|
||||||
{
|
{
|
||||||
SPI_finish();
|
SPI_finish();
|
||||||
return (tuple);
|
return PointerGetDatum(tuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plan->nplans <= 0) /* Get typeId of column */
|
if (plan->nplans <= 0) /* Get typeId of column */
|
||||||
|
@ -207,7 +201,7 @@ check_primary_key()
|
||||||
|
|
||||||
SPI_finish();
|
SPI_finish();
|
||||||
|
|
||||||
return (tuple);
|
return PointerGetDatum(tuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -222,9 +216,10 @@ check_primary_key()
|
||||||
* 'Ftable1', 'Fkey11', 'Fkey12', 'Ftable2', 'Fkey21', 'Fkey22').
|
* 'Ftable1', 'Fkey11', 'Fkey12', 'Ftable2', 'Fkey21', 'Fkey22').
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HeapTuple /* have to return HeapTuple to Executor */
|
Datum
|
||||||
check_foreign_key()
|
check_foreign_key(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
Trigger *trigger; /* to get trigger name */
|
Trigger *trigger; /* to get trigger name */
|
||||||
int nargs; /* # of args specified in CREATE TRIGGER */
|
int nargs; /* # of args specified in CREATE TRIGGER */
|
||||||
char **args; /* arguments: as described above */
|
char **args; /* arguments: as described above */
|
||||||
|
@ -258,19 +253,19 @@ check_foreign_key()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Called by trigger manager ? */
|
/* Called by trigger manager ? */
|
||||||
if (!CurrentTriggerData)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "check_foreign_key: triggers are not initialized");
|
elog(ERROR, "check_foreign_key: not fired by trigger manager");
|
||||||
|
|
||||||
/* Should be called for ROW trigger */
|
/* 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");
|
elog(ERROR, "check_foreign_key: can't process STATEMENT events");
|
||||||
|
|
||||||
/* Not should be called for INSERT */
|
/* 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");
|
elog(ERROR, "check_foreign_key: can't process INSERT events");
|
||||||
|
|
||||||
/* Have to check tg_trigtuple - tuple being deleted */
|
/* 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
|
* But if this is UPDATE then we have to return tg_newtuple. Also, if
|
||||||
|
@ -278,12 +273,12 @@ check_foreign_key()
|
||||||
* do.
|
* do.
|
||||||
*/
|
*/
|
||||||
is_update = 0;
|
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;
|
is_update = 1;
|
||||||
}
|
}
|
||||||
trigger = CurrentTriggerData->tg_trigger;
|
trigger = trigdata->tg_trigger;
|
||||||
nargs = trigger->tgnargs;
|
nargs = trigger->tgnargs;
|
||||||
args = trigger->tgargs;
|
args = trigger->tgargs;
|
||||||
|
|
||||||
|
@ -304,16 +299,9 @@ check_foreign_key()
|
||||||
elog(ERROR, "check_foreign_key: invalid number of arguments %d for %d references",
|
elog(ERROR, "check_foreign_key: invalid number of arguments %d for %d references",
|
||||||
nargs + 2, nrefs);
|
nargs + 2, nrefs);
|
||||||
|
|
||||||
rel = CurrentTriggerData->tg_relation;
|
rel = trigdata->tg_relation;
|
||||||
tupdesc = rel->rd_att;
|
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 */
|
/* Connect to SPI manager */
|
||||||
if ((ret = SPI_connect()) < 0)
|
if ((ret = SPI_connect()) < 0)
|
||||||
elog(ERROR, "check_foreign_key: SPI_connect returned %d", ret);
|
elog(ERROR, "check_foreign_key: SPI_connect returned %d", ret);
|
||||||
|
@ -364,7 +352,7 @@ check_foreign_key()
|
||||||
if (isnull)
|
if (isnull)
|
||||||
{
|
{
|
||||||
SPI_finish();
|
SPI_finish();
|
||||||
return ((newtuple == NULL) ? trigtuple : newtuple);
|
return PointerGetDatum((newtuple == NULL) ? trigtuple : newtuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -527,7 +515,7 @@ check_foreign_key()
|
||||||
if (newtuple != NULL && isequal)
|
if (newtuple != NULL && isequal)
|
||||||
{
|
{
|
||||||
SPI_finish();
|
SPI_finish();
|
||||||
return (newtuple);
|
return PointerGetDatum(newtuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -571,7 +559,7 @@ check_foreign_key()
|
||||||
|
|
||||||
SPI_finish();
|
SPI_finish();
|
||||||
|
|
||||||
return ((newtuple == NULL) ? trigtuple : newtuple);
|
return PointerGetDatum((newtuple == NULL) ? trigtuple : newtuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
static EPlan *
|
static EPlan *
|
||||||
|
|
|
@ -4,11 +4,11 @@ DROP FUNCTION check_foreign_key ();
|
||||||
CREATE FUNCTION check_primary_key ()
|
CREATE FUNCTION check_primary_key ()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/refint_DLSUFFIX_'
|
AS '_OBJWD_/refint_DLSUFFIX_'
|
||||||
LANGUAGE 'c'
|
LANGUAGE 'newC'
|
||||||
;
|
;
|
||||||
|
|
||||||
CREATE FUNCTION check_foreign_key ()
|
CREATE FUNCTION check_foreign_key ()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/refint_DLSUFFIX_'
|
AS '_OBJWD_/refint_DLSUFFIX_'
|
||||||
LANGUAGE 'c'
|
LANGUAGE 'newC'
|
||||||
;
|
;
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#define ABSTIMEOID 702 /* it should be in pg_type.h */
|
#define ABSTIMEOID 702 /* it should be in pg_type.h */
|
||||||
|
|
||||||
AbsoluteTime currabstime(void);
|
AbsoluteTime currabstime(void);
|
||||||
HeapTuple timetravel(void);
|
Datum timetravel(PG_FUNCTION_ARGS);
|
||||||
int32 set_timetravel(Name relname, int32 on);
|
Datum set_timetravel(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -47,9 +47,10 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
|
||||||
* timetravel ('date_on', 'date_off').
|
* timetravel ('date_on', 'date_off').
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HeapTuple /* have to return HeapTuple to Executor */
|
Datum
|
||||||
timetravel()
|
timetravel(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
Trigger *trigger; /* to get trigger name */
|
Trigger *trigger; /* to get trigger name */
|
||||||
char **args; /* arguments */
|
char **args; /* arguments */
|
||||||
int attnum[2]; /* fnumbers of start/stop columns */
|
int attnum[2]; /* fnumbers of start/stop columns */
|
||||||
|
@ -78,27 +79,27 @@ timetravel()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Called by trigger manager ? */
|
/* Called by trigger manager ? */
|
||||||
if (!CurrentTriggerData)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "timetravel: triggers are not initialized");
|
elog(ERROR, "timetravel: not fired by trigger manager");
|
||||||
|
|
||||||
/* Should be called for ROW trigger */
|
/* 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");
|
elog(ERROR, "timetravel: can't process STATEMENT events");
|
||||||
|
|
||||||
/* Should be called BEFORE */
|
/* 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");
|
elog(ERROR, "timetravel: must be fired before event");
|
||||||
|
|
||||||
/* INSERT ? */
|
/* INSERT ? */
|
||||||
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
|
||||||
isinsert = true;
|
isinsert = true;
|
||||||
|
|
||||||
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||||
newtuple = CurrentTriggerData->tg_newtuple;
|
newtuple = trigdata->tg_newtuple;
|
||||||
|
|
||||||
trigtuple = CurrentTriggerData->tg_trigtuple;
|
trigtuple = trigdata->tg_trigtuple;
|
||||||
|
|
||||||
rel = CurrentTriggerData->tg_relation;
|
rel = trigdata->tg_relation;
|
||||||
relname = SPI_getrelname(rel);
|
relname = SPI_getrelname(rel);
|
||||||
|
|
||||||
/* check if TT is OFF for this relation */
|
/* check if TT is OFF for this relation */
|
||||||
|
@ -108,10 +109,10 @@ timetravel()
|
||||||
if (i < nTTOff) /* OFF - nothing to do */
|
if (i < nTTOff) /* OFF - nothing to do */
|
||||||
{
|
{
|
||||||
pfree(relname);
|
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)
|
if (trigger->tgnargs != 2)
|
||||||
elog(ERROR, "timetravel (%s): invalid (!= 2) number of arguments %d",
|
elog(ERROR, "timetravel (%s): invalid (!= 2) number of arguments %d",
|
||||||
|
@ -121,13 +122,6 @@ timetravel()
|
||||||
tupdesc = rel->rd_att;
|
tupdesc = rel->rd_att;
|
||||||
natts = tupdesc->natts;
|
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++)
|
for (i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
attnum[i] = SPI_fnumber(tupdesc, args[i]);
|
attnum[i] = SPI_fnumber(tupdesc, args[i]);
|
||||||
|
@ -175,11 +169,11 @@ timetravel()
|
||||||
|
|
||||||
pfree(relname);
|
pfree(relname);
|
||||||
if (chnattrs <= 0)
|
if (chnattrs <= 0)
|
||||||
return (trigtuple);
|
return PointerGetDatum(trigtuple);
|
||||||
|
|
||||||
rettuple = SPI_modifytuple(rel, trigtuple, chnattrs,
|
rettuple = SPI_modifytuple(rel, trigtuple, chnattrs,
|
||||||
chattrs, newvals, NULL);
|
chattrs, newvals, NULL);
|
||||||
return (rettuple);
|
return PointerGetDatum(rettuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
oldon = SPI_getbinval(trigtuple, tupdesc, attnum[0], &isnull);
|
oldon = SPI_getbinval(trigtuple, tupdesc, attnum[0], &isnull);
|
||||||
|
@ -210,13 +204,13 @@ timetravel()
|
||||||
if (newoff != NOEND_ABSTIME)
|
if (newoff != NOEND_ABSTIME)
|
||||||
{
|
{
|
||||||
pfree(relname); /* allocated in upper executor context */
|
pfree(relname); /* allocated in upper executor context */
|
||||||
return (NULL);
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (oldoff != NOEND_ABSTIME) /* DELETE */
|
else if (oldoff != NOEND_ABSTIME) /* DELETE */
|
||||||
{
|
{
|
||||||
pfree(relname);
|
pfree(relname);
|
||||||
return (NULL);
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
newoff = GetCurrentAbsoluteTime();
|
newoff = GetCurrentAbsoluteTime();
|
||||||
|
@ -325,16 +319,18 @@ timetravel()
|
||||||
|
|
||||||
pfree(relname);
|
pfree(relname);
|
||||||
|
|
||||||
return (rettuple);
|
return PointerGetDatum(rettuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set_timetravel () --
|
* set_timetravel (relname, on) --
|
||||||
* turn timetravel for specified relation ON/OFF
|
* turn timetravel for specified relation ON/OFF
|
||||||
*/
|
*/
|
||||||
int32
|
Datum
|
||||||
set_timetravel(Name relname, int32 on)
|
set_timetravel(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
Name relname = PG_GETARG_NAME(0);
|
||||||
|
int32 on = PG_GETARG_INT32(1);
|
||||||
char *rname;
|
char *rname;
|
||||||
char *d;
|
char *d;
|
||||||
char *s;
|
char *s;
|
||||||
|
@ -347,7 +343,7 @@ set_timetravel(Name relname, int32 on)
|
||||||
if (i < nTTOff) /* OFF currently */
|
if (i < nTTOff) /* OFF currently */
|
||||||
{
|
{
|
||||||
if (on == 0)
|
if (on == 0)
|
||||||
return (0);
|
PG_RETURN_INT32(0);
|
||||||
|
|
||||||
/* turn ON */
|
/* turn ON */
|
||||||
free(TTOff[i]);
|
free(TTOff[i]);
|
||||||
|
@ -360,12 +356,12 @@ set_timetravel(Name relname, int32 on)
|
||||||
TTOff = realloc(TTOff, (nTTOff - 1) * sizeof(char *));
|
TTOff = realloc(TTOff, (nTTOff - 1) * sizeof(char *));
|
||||||
}
|
}
|
||||||
nTTOff--;
|
nTTOff--;
|
||||||
return (0);
|
PG_RETURN_INT32(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ON currently */
|
/* ON currently */
|
||||||
if (on != 0)
|
if (on != 0)
|
||||||
return (1);
|
PG_RETURN_INT32(1);
|
||||||
|
|
||||||
/* turn OFF */
|
/* turn OFF */
|
||||||
if (nTTOff == 0)
|
if (nTTOff == 0)
|
||||||
|
@ -380,8 +376,7 @@ set_timetravel(Name relname, int32 on)
|
||||||
pfree(rname);
|
pfree(rname);
|
||||||
nTTOff++;
|
nTTOff++;
|
||||||
|
|
||||||
return (1);
|
PG_RETURN_INT32(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AbsoluteTime
|
AbsoluteTime
|
||||||
|
|
|
@ -4,9 +4,9 @@ DROP FUNCTION set_timetravel(name, int4);
|
||||||
CREATE FUNCTION timetravel()
|
CREATE FUNCTION timetravel()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/timetravel_DLSUFFIX_'
|
AS '_OBJWD_/timetravel_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
|
|
||||||
CREATE FUNCTION set_timetravel(name, int4)
|
CREATE FUNCTION set_timetravel(name, int4)
|
||||||
RETURNS int4
|
RETURNS int4
|
||||||
AS '_OBJWD_/timetravel_DLSUFFIX_'
|
AS '_OBJWD_/timetravel_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC' WITH (isStrict);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_language.sgml,v 1.9 2000/03/26 18:32:27 petere Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_language.sgml,v 1.10 2000/05/29 01:59:06 tgl Exp $
|
||||||
Postgres documentation
|
Postgres documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
@ -160,44 +160,42 @@ ERROR: PL handler function <replaceable class="parameter">funcname</replaceable
|
||||||
<title>
|
<title>
|
||||||
Writing PL handlers
|
Writing PL handlers
|
||||||
</title>
|
</title>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
In <productname>Postgres</productname> 7.1 and later, call handlers
|
||||||
|
must adhere to the "new style" function manager interface.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The call handler for a procedural language must be written
|
The call handler for a procedural language must be written
|
||||||
in a compiler language such as 'C' and registered with
|
in a compiled language such as 'C' and registered with
|
||||||
<productname>Postgres</productname> as a function taking
|
<productname>Postgres</productname> as a function taking
|
||||||
no arguments and returning the
|
no arguments and returning the
|
||||||
<type>opaque</type> type, a placeholder for unspecified or undefined types..
|
<type>opaque</type> type, a placeholder for unspecified or undefined types.
|
||||||
This prevents the call handler from being
|
This prevents the call handler from being
|
||||||
called directly as a function from queries.
|
called directly as a function from queries.
|
||||||
|
(However, arguments may be supplied in the actual call when a
|
||||||
|
PL function in the language offered by the handler is to be executed.)
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
However, arguments must be supplied on the actual call when a
|
The call handler is called in the same way as any other new-style
|
||||||
PL function or trigger
|
function: it receives a pointer to a FunctionCallInfoData struct
|
||||||
procedure in the language offered by the handler is to be
|
containing argument values and information about the called function,
|
||||||
executed.
|
and it is expected to return a Datum result (and possibly set the
|
||||||
<itemizedlist>
|
<literal>isnull</literal> field of the FunctionCallInfoData struct,
|
||||||
<listitem>
|
if it wishes to return an SQL NULL result). The difference between
|
||||||
<para>
|
a call handler and an ordinary callee function is that the
|
||||||
When called from the trigger manager, the only argument is
|
<literal>flinfo->fn_oid</literal> field of the FunctionCallInfoData
|
||||||
the object ID from the procedure's <filename>pg_proc</filename>
|
struct will contain the OID of the PL function to be called, not of
|
||||||
entry. All other
|
the call handler itself. The call handler must use this field to
|
||||||
information from the trigger manager is found in the
|
determine which function to execute. Also, the passed argument list
|
||||||
global <structname>CurrentTriggerData</structname> pointer.
|
has been set up according to the declaration of the target PL function,
|
||||||
</para>
|
not of the call handler.
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
When called from the function manager, the arguments are
|
|
||||||
the object ID of the procedure's <filename>pg_proc</filename>
|
|
||||||
entry, the number
|
|
||||||
of arguments given to the PL function, the arguments in a
|
|
||||||
<structname>FmgrValues</structname> structure and a pointer
|
|
||||||
to a boolean where the
|
|
||||||
function tells the caller if the return value is the SQL
|
|
||||||
NULL value.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
It's up to the call handler to fetch the
|
It's up to the call handler to fetch the
|
||||||
<filename>pg_proc</filename> entry and
|
<filename>pg_proc</filename> entry and
|
||||||
|
@ -212,6 +210,28 @@ ERROR: PL handler function <replaceable class="parameter">funcname</replaceable
|
||||||
file or anything else that tells the call handler what to
|
file or anything else that tells the call handler what to
|
||||||
do in detail.
|
do in detail.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Often, the same function is called many times per SQL statement.
|
||||||
|
A call handler can avoid repeated lookups of information about the
|
||||||
|
called function by using the <literal>flinfo->fn_extra</literal> field.
|
||||||
|
This will initially be NULL, but can be set by the call handler to
|
||||||
|
point at information about the PL function. On subsequent calls,
|
||||||
|
if <literal>flinfo->fn_extra</literal> is already non-NULL then it
|
||||||
|
can be used and the information lookup step skipped. The call handler
|
||||||
|
must be careful that <literal>flinfo->fn_extra</literal> is made to
|
||||||
|
point at memory that will live at least until the end of the current
|
||||||
|
query, since an FmgrInfo data structure could be kept that long.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When a PL function is invoked as a trigger, no explicit arguments
|
||||||
|
are passed, but the FunctionCallInfoData's
|
||||||
|
<literal>context</literal> field points at a TriggerData node,
|
||||||
|
rather than being NULL as it is in a plain function call.
|
||||||
|
A PL handler should provide mechanisms for PL functions to get
|
||||||
|
at the trigger information.
|
||||||
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2 id="R2-SQL-CREATELANGUAGE-4">
|
<refsect2 id="R2-SQL-CREATELANGUAGE-4">
|
||||||
|
@ -275,39 +295,33 @@ ERROR: PL handler function <replaceable class="parameter">funcname</replaceable
|
||||||
#include "executor/spi.h"
|
#include "executor/spi.h"
|
||||||
#include "commands/trigger.h"
|
#include "commands/trigger.h"
|
||||||
#include "utils/elog.h"
|
#include "utils/elog.h"
|
||||||
#include "fmgr.h" /* for FmgrValues struct */
|
#include "fmgr.h"
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "catalog/pg_proc.h"
|
#include "catalog/pg_proc.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
plsample_call_handler(
|
plsample_call_handler(PG_FUNCTION_ARGS)
|
||||||
Oid prooid,
|
|
||||||
int pronargs,
|
|
||||||
FmgrValues *proargs,
|
|
||||||
bool *isNull)
|
|
||||||
{
|
{
|
||||||
Datum retval;
|
Datum retval;
|
||||||
TriggerData *trigdata;
|
|
||||||
|
|
||||||
if (CurrentTriggerData == NULL) {
|
if (CALLED_AS_TRIGGER(fcinfo))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Called as a trigger procedure
|
||||||
|
*/
|
||||||
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
|
|
||||||
|
retval = ...
|
||||||
|
} else {
|
||||||
/*
|
/*
|
||||||
* Called as a function
|
* Called as a function
|
||||||
*/
|
*/
|
||||||
|
|
||||||
retval = ...
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Called as a trigger procedure
|
|
||||||
*/
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
|
|
||||||
retval = ...
|
retval = ...
|
||||||
}
|
}
|
||||||
|
|
||||||
*isNull = false;
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
@ -325,7 +339,7 @@ plsample_call_handler(
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE FUNCTION plsample_call_handler () RETURNS opaque
|
CREATE FUNCTION plsample_call_handler () RETURNS opaque
|
||||||
AS '/usr/local/pgsql/lib/plsample.so'
|
AS '/usr/local/pgsql/lib/plsample.so'
|
||||||
LANGUAGE 'C';
|
LANGUAGE 'newC';
|
||||||
CREATE PROCEDURAL LANGUAGE 'plsample'
|
CREATE PROCEDURAL LANGUAGE 'plsample'
|
||||||
HANDLER plsample_call_handler
|
HANDLER plsample_call_handler
|
||||||
LANCOMPILER 'PL/Sample';
|
LANCOMPILER 'PL/Sample';
|
||||||
|
|
|
@ -15,13 +15,14 @@
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If a trigger event occurs, the trigger manager (called by the Executor)
|
If a trigger event occurs, the trigger manager (called by the Executor)
|
||||||
initializes the global structure TriggerData *CurrentTriggerData (described
|
sets up a TriggerData information structure (described below) and calls
|
||||||
below) and calls the trigger function to handle the event.
|
the trigger function to handle the event.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The trigger function must be created before the trigger is created as a
|
The trigger function must be created before the trigger is created as a
|
||||||
function taking no arguments and returns opaque.
|
function taking no arguments and returning opaque. If the function is
|
||||||
|
written in C, it must follow the "new style" function manager interface.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -106,7 +107,7 @@ CREATE TRIGGER <replaceable>trigger</replaceable> [ BEFORE | AFTER ] [ INSERT |
|
||||||
<term><replaceable>args</replaceable></term>
|
<term><replaceable>args</replaceable></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The arguments passed to the function in the CurrentTriggerData structure.
|
The arguments passed to the function in the TriggerData structure.
|
||||||
The purpose of passing arguments to the function is to allow different
|
The purpose of passing arguments to the function is to allow different
|
||||||
triggers with similar requirements to call the same function.
|
triggers with similar requirements to call the same function.
|
||||||
</para>
|
</para>
|
||||||
|
@ -179,11 +180,35 @@ CREATE TRIGGER <replaceable>trigger</replaceable> [ BEFORE | AFTER ] [ INSERT |
|
||||||
<title>Interaction with the Trigger Manager</title>
|
<title>Interaction with the Trigger Manager</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
As mentioned above, when function is called by the trigger manager,
|
This section describes the low-level details of the interface to a
|
||||||
structure TriggerData *CurrentTriggerData is NOT NULL and initialized. So
|
trigger function. This information is only needed when writing a
|
||||||
it is better to check CurrentTriggerData against being NULL at the start
|
trigger function in C. If you are using a higher-level function
|
||||||
and set it to NULL just after fetching the information to prevent calls to
|
language then these details are handled for you.
|
||||||
a trigger function not from the trigger manager.
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
The interface described here applies for
|
||||||
|
<productname>Postgres</productname> 7.1 and later.
|
||||||
|
Earlier versions passed the TriggerData pointer in a global
|
||||||
|
variable CurrentTriggerData.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When a function is called by the trigger manager, it is not passed any
|
||||||
|
normal parameters, but it is passed a "context" pointer pointing to a
|
||||||
|
TriggerData structure. C functions can check whether they were called
|
||||||
|
from the trigger manager or not by executing the macro
|
||||||
|
<literal>CALLED_AS_TRIGGER(fcinfo)</literal>, which expands to
|
||||||
|
<programlisting>
|
||||||
|
((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))
|
||||||
|
</programlisting>
|
||||||
|
If this returns TRUE, then it is safe to cast fcinfo->context to type
|
||||||
|
<literal>TriggerData *</literal> and make use of the pointed-to
|
||||||
|
TriggerData structure.
|
||||||
|
The function must <emphasis>not</emphasis> alter the TriggerData
|
||||||
|
structure or any of the data it points to.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -192,6 +217,7 @@ CREATE TRIGGER <replaceable>trigger</replaceable> [ BEFORE | AFTER ] [ INSERT |
|
||||||
<programlisting>
|
<programlisting>
|
||||||
typedef struct TriggerData
|
typedef struct TriggerData
|
||||||
{
|
{
|
||||||
|
NodeTag type;
|
||||||
TriggerEvent tg_event;
|
TriggerEvent tg_event;
|
||||||
Relation tg_relation;
|
Relation tg_relation;
|
||||||
HeapTuple tg_trigtuple;
|
HeapTuple tg_trigtuple;
|
||||||
|
@ -203,6 +229,15 @@ typedef struct TriggerData
|
||||||
where the members are defined as follows:
|
where the members are defined as follows:
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>type</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Always <literal>T_TriggerData</literal> if this is a trigger event.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>tg_event</term>
|
<term>tg_event</term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -410,11 +445,12 @@ execution of Q) or after Q is done.
|
||||||
#include "executor/spi.h" /* this is what you need to work with SPI */
|
#include "executor/spi.h" /* this is what you need to work with SPI */
|
||||||
#include "commands/trigger.h" /* -"- and triggers */
|
#include "commands/trigger.h" /* -"- and triggers */
|
||||||
|
|
||||||
HeapTuple trigf(void);
|
extern Datum trigf(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
HeapTuple
|
Datum
|
||||||
trigf()
|
trigf(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
HeapTuple rettuple;
|
HeapTuple rettuple;
|
||||||
char *when;
|
char *when;
|
||||||
|
@ -422,27 +458,27 @@ trigf()
|
||||||
bool isnull;
|
bool isnull;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
if (!CurrentTriggerData)
|
/* Make sure trigdata is pointing at what I expect */
|
||||||
elog(NOTICE, "trigf: triggers are not initialized");
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
|
elog(ERROR, "trigf: not fired by trigger manager");
|
||||||
|
|
||||||
/* tuple to return to Executor */
|
/* tuple to return to Executor */
|
||||||
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||||
rettuple = CurrentTriggerData->tg_newtuple;
|
rettuple = trigdata->tg_newtuple;
|
||||||
else
|
else
|
||||||
rettuple = CurrentTriggerData->tg_trigtuple;
|
rettuple = trigdata->tg_trigtuple;
|
||||||
|
|
||||||
/* check for NULLs ? */
|
/* check for NULLs ? */
|
||||||
if (!TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event) &&
|
if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event) &&
|
||||||
TRIGGER_FIRED_BEFORE(CurrentTriggerData->tg_event))
|
TRIGGER_FIRED_BEFORE(trigdata->tg_event))
|
||||||
checknull = true;
|
checknull = true;
|
||||||
|
|
||||||
if (TRIGGER_FIRED_BEFORE(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
|
||||||
when = "before";
|
when = "before";
|
||||||
else
|
else
|
||||||
when = "after ";
|
when = "after ";
|
||||||
|
|
||||||
tupdesc = CurrentTriggerData->tg_relation->rd_att;
|
tupdesc = trigdata->tg_relation->rd_att;
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
|
|
||||||
/* Connect to SPI manager */
|
/* Connect to SPI manager */
|
||||||
if ((ret = SPI_connect()) < 0)
|
if ((ret = SPI_connect()) < 0)
|
||||||
|
@ -467,7 +503,7 @@ trigf()
|
||||||
rettuple = NULL;
|
rettuple = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (rettuple);
|
return PointerGetDatum(rettuple);
|
||||||
}
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.72 2000/05/28 17:55:54 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.73 2000/05/29 01:59:06 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The PortalExecutorHeapMemory crap needs to be eliminated
|
* The PortalExecutorHeapMemory crap needs to be eliminated
|
||||||
|
@ -1159,19 +1159,24 @@ AlterTableAddConstraint(const char *relationName,
|
||||||
|
|
||||||
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||||
{
|
{
|
||||||
TriggerData newtrigdata;
|
|
||||||
|
|
||||||
newtrigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
|
|
||||||
newtrigdata.tg_relation = rel;
|
|
||||||
newtrigdata.tg_trigtuple = tuple;
|
|
||||||
newtrigdata.tg_newtuple = NULL;
|
|
||||||
newtrigdata.tg_trigger = &trig;
|
|
||||||
|
|
||||||
CurrentTriggerData = &newtrigdata;
|
|
||||||
|
|
||||||
RI_FKey_check_ins(NULL);
|
|
||||||
|
|
||||||
/* Make a call to the check function */
|
/* Make a call to the check function */
|
||||||
|
/* No parameters are passed, but we do set a context */
|
||||||
|
FunctionCallInfoData fcinfo;
|
||||||
|
TriggerData trigdata;
|
||||||
|
|
||||||
|
MemSet(&fcinfo, 0, sizeof(fcinfo));
|
||||||
|
/* We assume RI_FKey_check_ins won't look at flinfo... */
|
||||||
|
|
||||||
|
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_trigger = &trig;
|
||||||
|
|
||||||
|
fcinfo.context = (Node *) &trigdata;
|
||||||
|
|
||||||
|
RI_FKey_check_ins(&fcinfo);
|
||||||
}
|
}
|
||||||
heap_endscan(scan);
|
heap_endscan(scan);
|
||||||
heap_close(rel, NoLock); /* close rel but keep
|
heap_close(rel, NoLock); /* close rel but keep
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.66 2000/05/28 20:34:50 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.67 2000/05/29 01:59:06 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -32,14 +32,12 @@
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "utils/tqual.h"
|
#include "utils/tqual.h"
|
||||||
|
|
||||||
DLLIMPORT TriggerData *CurrentTriggerData = NULL;
|
|
||||||
|
|
||||||
/* XXX no points for style */
|
|
||||||
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid);
|
|
||||||
|
|
||||||
static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
|
static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
|
||||||
static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid,
|
static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid,
|
||||||
TupleTableSlot **newSlot);
|
TupleTableSlot **newSlot);
|
||||||
|
static HeapTuple ExecCallTriggerFunc(Trigger *trigger,
|
||||||
|
TriggerData *trigdata);
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -507,7 +505,7 @@ RelationBuildTriggers(Relation relation)
|
||||||
build->tgoid = htup->t_data->t_oid;
|
build->tgoid = htup->t_data->t_oid;
|
||||||
build->tgname = nameout(&pg_trigger->tgname);
|
build->tgname = nameout(&pg_trigger->tgname);
|
||||||
build->tgfoid = pg_trigger->tgfoid;
|
build->tgfoid = pg_trigger->tgfoid;
|
||||||
build->tgfunc.fn_addr = NULL;
|
build->tgfunc.fn_oid = InvalidOid; /* mark FmgrInfo as uninitialized */
|
||||||
build->tgtype = pg_trigger->tgtype;
|
build->tgtype = pg_trigger->tgtype;
|
||||||
build->tgenabled = pg_trigger->tgenabled;
|
build->tgenabled = pg_trigger->tgenabled;
|
||||||
build->tgisconstraint = pg_trigger->tgisconstraint;
|
build->tgisconstraint = pg_trigger->tgisconstraint;
|
||||||
|
@ -757,45 +755,66 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static HeapTuple
|
static HeapTuple
|
||||||
ExecCallTriggerFunc(Trigger *trigger)
|
ExecCallTriggerFunc(Trigger *trigger, TriggerData *trigdata)
|
||||||
{
|
{
|
||||||
if (trigger->tgfunc.fn_addr == NULL)
|
FunctionCallInfoData fcinfo;
|
||||||
|
Datum result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fmgr lookup info is cached in the Trigger structure,
|
||||||
|
* so that we need not repeat the lookup on every call.
|
||||||
|
*/
|
||||||
|
if (trigger->tgfunc.fn_oid == InvalidOid)
|
||||||
fmgr_info(trigger->tgfoid, &trigger->tgfunc);
|
fmgr_info(trigger->tgfoid, &trigger->tgfunc);
|
||||||
|
|
||||||
return (HeapTuple) ((*fmgr_faddr(&trigger->tgfunc)) ());
|
/*
|
||||||
|
* Call the function, passing no arguments but setting a context.
|
||||||
|
*/
|
||||||
|
MemSet(&fcinfo, 0, sizeof(fcinfo));
|
||||||
|
|
||||||
|
fcinfo.flinfo = &trigger->tgfunc;
|
||||||
|
fcinfo.context = (Node *) trigdata;
|
||||||
|
|
||||||
|
result = FunctionCallInvoke(&fcinfo);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trigger protocol allows function to return a null pointer,
|
||||||
|
* but NOT to set the isnull result flag.
|
||||||
|
*/
|
||||||
|
if (fcinfo.isnull)
|
||||||
|
elog(ERROR, "ExecCallTriggerFunc: function %u returned NULL",
|
||||||
|
fcinfo.flinfo->fn_oid);
|
||||||
|
|
||||||
|
return (HeapTuple) DatumGetPointer(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
HeapTuple
|
HeapTuple
|
||||||
ExecBRInsertTriggers(Relation rel, HeapTuple trigtuple)
|
ExecBRInsertTriggers(Relation rel, HeapTuple trigtuple)
|
||||||
{
|
{
|
||||||
TriggerData *SaveTriggerData;
|
|
||||||
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
|
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
|
||||||
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
|
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
|
||||||
HeapTuple newtuple = trigtuple;
|
HeapTuple newtuple = trigtuple;
|
||||||
HeapTuple oldtuple;
|
HeapTuple oldtuple;
|
||||||
|
TriggerData LocTriggerData;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
|
LocTriggerData.type = T_TriggerData;
|
||||||
SaveTriggerData->tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
|
LocTriggerData.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
|
||||||
SaveTriggerData->tg_relation = rel;
|
LocTriggerData.tg_relation = rel;
|
||||||
SaveTriggerData->tg_newtuple = NULL;
|
LocTriggerData.tg_newtuple = NULL;
|
||||||
for (i = 0; i < ntrigs; i++)
|
for (i = 0; i < ntrigs; i++)
|
||||||
{
|
{
|
||||||
if (!trigger[i]->tgenabled)
|
if (!trigger[i]->tgenabled)
|
||||||
continue;
|
continue;
|
||||||
CurrentTriggerData = SaveTriggerData;
|
LocTriggerData.tg_trigtuple = oldtuple = newtuple;
|
||||||
CurrentTriggerData->tg_trigtuple = oldtuple = newtuple;
|
LocTriggerData.tg_trigger = trigger[i];
|
||||||
CurrentTriggerData->tg_trigger = trigger[i];
|
newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData);
|
||||||
newtuple = ExecCallTriggerFunc(trigger[i]);
|
|
||||||
if (newtuple == NULL)
|
if (newtuple == NULL)
|
||||||
break;
|
break;
|
||||||
else if (oldtuple != newtuple && oldtuple != trigtuple)
|
else if (oldtuple != newtuple && oldtuple != trigtuple)
|
||||||
heap_freetuple(oldtuple);
|
heap_freetuple(oldtuple);
|
||||||
}
|
}
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
pfree(SaveTriggerData);
|
|
||||||
return newtuple;
|
return newtuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -810,9 +829,9 @@ bool
|
||||||
ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
|
ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
|
||||||
{
|
{
|
||||||
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
|
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
|
||||||
TriggerData *SaveTriggerData;
|
|
||||||
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
|
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
|
||||||
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
|
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
|
||||||
|
TriggerData LocTriggerData;
|
||||||
HeapTuple trigtuple;
|
HeapTuple trigtuple;
|
||||||
HeapTuple newtuple = NULL;
|
HeapTuple newtuple = NULL;
|
||||||
TupleTableSlot *newSlot;
|
TupleTableSlot *newSlot;
|
||||||
|
@ -822,25 +841,22 @@ ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
|
||||||
if (trigtuple == NULL)
|
if (trigtuple == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
|
LocTriggerData.type = T_TriggerData;
|
||||||
SaveTriggerData->tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
|
LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
|
||||||
SaveTriggerData->tg_relation = rel;
|
LocTriggerData.tg_relation = rel;
|
||||||
SaveTriggerData->tg_newtuple = NULL;
|
LocTriggerData.tg_newtuple = NULL;
|
||||||
for (i = 0; i < ntrigs; i++)
|
for (i = 0; i < ntrigs; i++)
|
||||||
{
|
{
|
||||||
if (!trigger[i]->tgenabled)
|
if (!trigger[i]->tgenabled)
|
||||||
continue;
|
continue;
|
||||||
CurrentTriggerData = SaveTriggerData;
|
LocTriggerData.tg_trigtuple = trigtuple;
|
||||||
CurrentTriggerData->tg_trigtuple = trigtuple;
|
LocTriggerData.tg_trigger = trigger[i];
|
||||||
CurrentTriggerData->tg_trigger = trigger[i];
|
newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData);
|
||||||
newtuple = ExecCallTriggerFunc(trigger[i]);
|
|
||||||
if (newtuple == NULL)
|
if (newtuple == NULL)
|
||||||
break;
|
break;
|
||||||
if (newtuple != trigtuple)
|
if (newtuple != trigtuple)
|
||||||
heap_freetuple(newtuple);
|
heap_freetuple(newtuple);
|
||||||
}
|
}
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
pfree(SaveTriggerData);
|
|
||||||
heap_freetuple(trigtuple);
|
heap_freetuple(trigtuple);
|
||||||
|
|
||||||
return (newtuple == NULL) ? false : true;
|
return (newtuple == NULL) ? false : true;
|
||||||
|
@ -860,9 +876,9 @@ HeapTuple
|
||||||
ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
|
ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
|
||||||
{
|
{
|
||||||
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
|
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
|
||||||
TriggerData *SaveTriggerData;
|
|
||||||
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
|
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
|
||||||
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
|
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
|
||||||
|
TriggerData LocTriggerData;
|
||||||
HeapTuple trigtuple;
|
HeapTuple trigtuple;
|
||||||
HeapTuple oldtuple;
|
HeapTuple oldtuple;
|
||||||
HeapTuple intuple = newtuple;
|
HeapTuple intuple = newtuple;
|
||||||
|
@ -880,25 +896,22 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
|
||||||
if (newSlot != NULL)
|
if (newSlot != NULL)
|
||||||
intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
|
intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
|
||||||
|
|
||||||
SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
|
LocTriggerData.type = T_TriggerData;
|
||||||
SaveTriggerData->tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
|
LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
|
||||||
SaveTriggerData->tg_relation = rel;
|
LocTriggerData.tg_relation = rel;
|
||||||
for (i = 0; i < ntrigs; i++)
|
for (i = 0; i < ntrigs; i++)
|
||||||
{
|
{
|
||||||
if (!trigger[i]->tgenabled)
|
if (!trigger[i]->tgenabled)
|
||||||
continue;
|
continue;
|
||||||
CurrentTriggerData = SaveTriggerData;
|
LocTriggerData.tg_trigtuple = trigtuple;
|
||||||
CurrentTriggerData->tg_trigtuple = trigtuple;
|
LocTriggerData.tg_newtuple = oldtuple = newtuple;
|
||||||
CurrentTriggerData->tg_newtuple = oldtuple = newtuple;
|
LocTriggerData.tg_trigger = trigger[i];
|
||||||
CurrentTriggerData->tg_trigger = trigger[i];
|
newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData);
|
||||||
newtuple = ExecCallTriggerFunc(trigger[i]);
|
|
||||||
if (newtuple == NULL)
|
if (newtuple == NULL)
|
||||||
break;
|
break;
|
||||||
else if (oldtuple != newtuple && oldtuple != intuple)
|
else if (oldtuple != newtuple && oldtuple != intuple)
|
||||||
heap_freetuple(oldtuple);
|
heap_freetuple(oldtuple);
|
||||||
}
|
}
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
pfree(SaveTriggerData);
|
|
||||||
heap_freetuple(trigtuple);
|
heap_freetuple(trigtuple);
|
||||||
return newtuple;
|
return newtuple;
|
||||||
}
|
}
|
||||||
|
@ -1167,7 +1180,7 @@ static void
|
||||||
deferredTriggerExecute(DeferredTriggerEvent event, int itemno)
|
deferredTriggerExecute(DeferredTriggerEvent event, int itemno)
|
||||||
{
|
{
|
||||||
Relation rel;
|
Relation rel;
|
||||||
TriggerData SaveTriggerData;
|
TriggerData LocTriggerData;
|
||||||
HeapTupleData oldtuple;
|
HeapTupleData oldtuple;
|
||||||
HeapTupleData newtuple;
|
HeapTupleData newtuple;
|
||||||
HeapTuple rettuple;
|
HeapTuple rettuple;
|
||||||
|
@ -1200,30 +1213,31 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno)
|
||||||
* Setup the trigger information
|
* Setup the trigger information
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
SaveTriggerData.tg_event = (event->dte_event & TRIGGER_EVENT_OPMASK) |
|
LocTriggerData.type = T_TriggerData;
|
||||||
|
LocTriggerData.tg_event = (event->dte_event & TRIGGER_EVENT_OPMASK) |
|
||||||
TRIGGER_EVENT_ROW;
|
TRIGGER_EVENT_ROW;
|
||||||
SaveTriggerData.tg_relation = rel;
|
LocTriggerData.tg_relation = rel;
|
||||||
|
|
||||||
switch (event->dte_event & TRIGGER_EVENT_OPMASK)
|
switch (event->dte_event & TRIGGER_EVENT_OPMASK)
|
||||||
{
|
{
|
||||||
case TRIGGER_EVENT_INSERT:
|
case TRIGGER_EVENT_INSERT:
|
||||||
SaveTriggerData.tg_trigtuple = &newtuple;
|
LocTriggerData.tg_trigtuple = &newtuple;
|
||||||
SaveTriggerData.tg_newtuple = NULL;
|
LocTriggerData.tg_newtuple = NULL;
|
||||||
SaveTriggerData.tg_trigger =
|
LocTriggerData.tg_trigger =
|
||||||
rel->trigdesc->tg_after_row[TRIGGER_EVENT_INSERT][itemno];
|
rel->trigdesc->tg_after_row[TRIGGER_EVENT_INSERT][itemno];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TRIGGER_EVENT_UPDATE:
|
case TRIGGER_EVENT_UPDATE:
|
||||||
SaveTriggerData.tg_trigtuple = &oldtuple;
|
LocTriggerData.tg_trigtuple = &oldtuple;
|
||||||
SaveTriggerData.tg_newtuple = &newtuple;
|
LocTriggerData.tg_newtuple = &newtuple;
|
||||||
SaveTriggerData.tg_trigger =
|
LocTriggerData.tg_trigger =
|
||||||
rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE][itemno];
|
rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE][itemno];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TRIGGER_EVENT_DELETE:
|
case TRIGGER_EVENT_DELETE:
|
||||||
SaveTriggerData.tg_trigtuple = &oldtuple;
|
LocTriggerData.tg_trigtuple = &oldtuple;
|
||||||
SaveTriggerData.tg_newtuple = NULL;
|
LocTriggerData.tg_newtuple = NULL;
|
||||||
SaveTriggerData.tg_trigger =
|
LocTriggerData.tg_trigger =
|
||||||
rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE][itemno];
|
rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE][itemno];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1233,9 +1247,7 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno)
|
||||||
* updated tuple.
|
* updated tuple.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
CurrentTriggerData = &SaveTriggerData;
|
rettuple = ExecCallTriggerFunc(LocTriggerData.tg_trigger, &LocTriggerData);
|
||||||
rettuple = ExecCallTriggerFunc(SaveTriggerData.tg_trigger);
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple)
|
if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple)
|
||||||
heap_freetuple(rettuple);
|
heap_freetuple(rettuple);
|
||||||
|
|
||||||
|
@ -1778,7 +1790,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
||||||
Trigger **triggers;
|
Trigger **triggers;
|
||||||
ItemPointerData oldctid;
|
ItemPointerData oldctid;
|
||||||
ItemPointerData newctid;
|
ItemPointerData newctid;
|
||||||
TriggerData SaveTriggerData;
|
TriggerData LocTriggerData;
|
||||||
|
|
||||||
if (deftrig_cxt == NULL)
|
if (deftrig_cxt == NULL)
|
||||||
elog(ERROR,
|
elog(ERROR,
|
||||||
|
@ -1891,15 +1903,14 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
||||||
if (!is_ri_trigger)
|
if (!is_ri_trigger)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SaveTriggerData.tg_event = TRIGGER_EVENT_UPDATE;
|
LocTriggerData.type = T_TriggerData;
|
||||||
SaveTriggerData.tg_relation = rel;
|
LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE;
|
||||||
SaveTriggerData.tg_trigtuple = oldtup;
|
LocTriggerData.tg_relation = rel;
|
||||||
SaveTriggerData.tg_newtuple = newtup;
|
LocTriggerData.tg_trigtuple = oldtup;
|
||||||
SaveTriggerData.tg_trigger = triggers[i];
|
LocTriggerData.tg_newtuple = newtup;
|
||||||
|
LocTriggerData.tg_trigger = triggers[i];
|
||||||
|
|
||||||
CurrentTriggerData = &SaveTriggerData;
|
key_unchanged = RI_FKey_keyequal_upd(&LocTriggerData);
|
||||||
key_unchanged = RI_FKey_keyequal_upd();
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
|
|
||||||
if (key_unchanged)
|
if (key_unchanged)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: user.c,v 1.54 2000/05/28 17:55:55 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.55 2000/05/29 01:59:07 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -168,20 +168,14 @@ write_password_file(Relation rel)
|
||||||
|
|
||||||
|
|
||||||
/* This is the wrapper for triggers. */
|
/* This is the wrapper for triggers. */
|
||||||
HeapTuple
|
Datum
|
||||||
update_pg_pwd(void)
|
update_pg_pwd(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Relation rel = heap_openr(ShadowRelationName, AccessExclusiveLock);
|
Relation rel = heap_openr(ShadowRelationName, AccessExclusiveLock);
|
||||||
|
|
||||||
write_password_file(rel);
|
write_password_file(rel);
|
||||||
heap_close(rel, AccessExclusiveLock);
|
heap_close(rel, AccessExclusiveLock);
|
||||||
|
return PointerGetDatum(NULL);
|
||||||
/*
|
|
||||||
* This is a trigger, so clean out the information provided by the
|
|
||||||
* trigger manager.
|
|
||||||
*/
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.113 2000/04/12 17:15:08 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.114 2000/05/29 01:59:07 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -46,9 +46,6 @@
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
/* XXX no points for style */
|
|
||||||
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
|
|
||||||
ItemPointer tid);
|
|
||||||
|
|
||||||
/* decls for local routines only used within this module */
|
/* decls for local routines only used within this module */
|
||||||
static TupleDesc InitPlan(CmdType operation,
|
static TupleDesc InitPlan(CmdType operation,
|
||||||
|
@ -1974,7 +1971,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
||||||
*/
|
*/
|
||||||
*tid = tuple.t_self;
|
*tid = tuple.t_self;
|
||||||
|
|
||||||
return (EvalPlanQualNext(estate));
|
return EvalPlanQualNext(estate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*
|
*
|
||||||
* 1999 Jan Wieck
|
* 1999 Jan Wieck
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.14 2000/04/12 17:15:51 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.15 2000/05/29 01:59:08 tgl Exp $
|
||||||
*
|
*
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
|
@ -20,7 +20,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "fmgr.h"
|
|
||||||
|
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "catalog/pg_operator.h"
|
#include "catalog/pg_operator.h"
|
||||||
|
@ -28,10 +27,11 @@
|
||||||
#include "commands/trigger.h"
|
#include "commands/trigger.h"
|
||||||
#include "executor/spi.h"
|
#include "executor/spi.h"
|
||||||
#include "executor/spi_priv.h"
|
#include "executor/spi_priv.h"
|
||||||
|
#include "fmgr.h"
|
||||||
|
#include "lib/hasht.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/mcxt.h"
|
#include "utils/mcxt.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "lib/hasht.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -105,7 +105,6 @@ typedef struct RI_QueryHashEntry
|
||||||
typedef struct RI_OpreqHashEntry
|
typedef struct RI_OpreqHashEntry
|
||||||
{
|
{
|
||||||
Oid typeid;
|
Oid typeid;
|
||||||
Oid oprfnid;
|
|
||||||
FmgrInfo oprfmgrinfo;
|
FmgrInfo oprfmgrinfo;
|
||||||
} RI_OpreqHashEntry;
|
} RI_OpreqHashEntry;
|
||||||
|
|
||||||
|
@ -147,13 +146,13 @@ static void ri_HashPreparedPlan(RI_QueryKey *key, void *plan);
|
||||||
/* ----------
|
/* ----------
|
||||||
* RI_FKey_check -
|
* RI_FKey_check -
|
||||||
*
|
*
|
||||||
* Check foreign key existance (combined for INSERT and UPDATE).
|
* Check foreign key existence (combined for INSERT and UPDATE).
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
static HeapTuple
|
static Datum
|
||||||
RI_FKey_check(FmgrInfo *proinfo)
|
RI_FKey_check(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
int tgnargs;
|
int tgnargs;
|
||||||
char **tgargs;
|
char **tgargs;
|
||||||
Relation fk_rel;
|
Relation fk_rel;
|
||||||
|
@ -168,15 +167,13 @@ RI_FKey_check(FmgrInfo *proinfo)
|
||||||
int i;
|
int i;
|
||||||
int match_type;
|
int match_type;
|
||||||
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
ReferentialIntegritySnapshotOverride = true;
|
ReferentialIntegritySnapshotOverride = true;
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Check that this is a valid trigger call on the right time and event.
|
* Check that this is a valid trigger call on the right time and event.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (trigdata == NULL)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "RI_FKey_check() not fired by trigger manager");
|
elog(ERROR, "RI_FKey_check() not fired by trigger manager");
|
||||||
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
||||||
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
||||||
|
@ -275,7 +272,7 @@ RI_FKey_check(FmgrInfo *proinfo)
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(NOTICE, "SPI_finish() failed in RI_FKey_check()");
|
elog(NOTICE, "SPI_finish() failed in RI_FKey_check()");
|
||||||
|
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,7 +281,7 @@ RI_FKey_check(FmgrInfo *proinfo)
|
||||||
if (match_type == RI_MATCH_TYPE_PARTIAL)
|
if (match_type == RI_MATCH_TYPE_PARTIAL)
|
||||||
{
|
{
|
||||||
elog(ERROR, "MATCH PARTIAL not yet supported");
|
elog(ERROR, "MATCH PARTIAL not yet supported");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
ri_BuildQueryKeyFull(&qkey, trigdata->tg_trigger->tgoid,
|
ri_BuildQueryKeyFull(&qkey, trigdata->tg_trigger->tgoid,
|
||||||
|
@ -303,7 +300,7 @@ RI_FKey_check(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
heap_close(pk_rel, NoLock);
|
heap_close(pk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
case RI_KEYS_SOME_NULL:
|
case RI_KEYS_SOME_NULL:
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -324,7 +321,7 @@ RI_FKey_check(FmgrInfo *proinfo)
|
||||||
"and NON-NULL key values",
|
"and NON-NULL key values",
|
||||||
tgargs[RI_CONSTRAINT_NAME_ARGNO]);
|
tgargs[RI_CONSTRAINT_NAME_ARGNO]);
|
||||||
heap_close(pk_rel, NoLock);
|
heap_close(pk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
case RI_MATCH_TYPE_UNSPECIFIED:
|
case RI_MATCH_TYPE_UNSPECIFIED:
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -333,7 +330,7 @@ RI_FKey_check(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
heap_close(pk_rel, NoLock);
|
heap_close(pk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
case RI_MATCH_TYPE_PARTIAL:
|
case RI_MATCH_TYPE_PARTIAL:
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -345,7 +342,7 @@ RI_FKey_check(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "MATCH PARTIAL not yet implemented");
|
elog(ERROR, "MATCH PARTIAL not yet implemented");
|
||||||
heap_close(pk_rel, NoLock);
|
heap_close(pk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
case RI_KEYS_NONE_NULL:
|
case RI_KEYS_NONE_NULL:
|
||||||
|
@ -459,40 +456,40 @@ RI_FKey_check(FmgrInfo *proinfo)
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(NOTICE, "SPI_finish() failed in RI_FKey_check()");
|
elog(NOTICE, "SPI_finish() failed in RI_FKey_check()");
|
||||||
|
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Never reached
|
* Never reached
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "internal error #1 in ri_triggers.c");
|
elog(ERROR, "internal error #1 in ri_triggers.c");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* RI_FKey_check_ins -
|
* RI_FKey_check_ins -
|
||||||
*
|
*
|
||||||
* Check foreign key existance at insert event on FK table.
|
* Check foreign key existence at insert event on FK table.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
Datum
|
||||||
RI_FKey_check_ins(FmgrInfo *proinfo)
|
RI_FKey_check_ins(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
return RI_FKey_check(proinfo);
|
return RI_FKey_check(fcinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* RI_FKey_check_upd -
|
* RI_FKey_check_upd -
|
||||||
*
|
*
|
||||||
* Check foreign key existance at update event on FK table.
|
* Check foreign key existence at update event on FK table.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
Datum
|
||||||
RI_FKey_check_upd(FmgrInfo *proinfo)
|
RI_FKey_check_upd(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
return RI_FKey_check(proinfo);
|
return RI_FKey_check(fcinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -504,10 +501,10 @@ RI_FKey_check_upd(FmgrInfo *proinfo)
|
||||||
* integrity constraint.
|
* integrity constraint.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
Datum
|
||||||
RI_FKey_noaction_del(FmgrInfo *proinfo)
|
RI_FKey_noaction_del(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
int tgnargs;
|
int tgnargs;
|
||||||
char **tgargs;
|
char **tgargs;
|
||||||
Relation fk_rel;
|
Relation fk_rel;
|
||||||
|
@ -520,15 +517,13 @@ RI_FKey_noaction_del(FmgrInfo *proinfo)
|
||||||
bool isnull;
|
bool isnull;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
ReferentialIntegritySnapshotOverride = true;
|
ReferentialIntegritySnapshotOverride = true;
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Check that this is a valid trigger call on the right time and event.
|
* Check that this is a valid trigger call on the right time and event.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (trigdata == NULL)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "RI_FKey_noaction_del() not fired by trigger manager");
|
elog(ERROR, "RI_FKey_noaction_del() not fired by trigger manager");
|
||||||
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
||||||
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
||||||
|
@ -553,7 +548,7 @@ RI_FKey_noaction_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (tgnargs == 4)
|
if (tgnargs == 4)
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Get the relation descriptors of the FK and PK tables and
|
* Get the relation descriptors of the FK and PK tables and
|
||||||
|
@ -590,7 +585,7 @@ RI_FKey_noaction_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
heap_close(fk_rel, NoLock);
|
heap_close(fk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
case RI_KEYS_NONE_NULL:
|
case RI_KEYS_NONE_NULL:
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -685,7 +680,7 @@ RI_FKey_noaction_del(FmgrInfo *proinfo)
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(NOTICE, "SPI_finish() failed in RI_FKey_noaction_del()");
|
elog(NOTICE, "SPI_finish() failed in RI_FKey_noaction_del()");
|
||||||
|
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Handle MATCH PARTIAL restrict delete.
|
* Handle MATCH PARTIAL restrict delete.
|
||||||
|
@ -693,7 +688,7 @@ RI_FKey_noaction_del(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
case RI_MATCH_TYPE_PARTIAL:
|
case RI_MATCH_TYPE_PARTIAL:
|
||||||
elog(ERROR, "MATCH PARTIAL not yet supported");
|
elog(ERROR, "MATCH PARTIAL not yet supported");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -701,7 +696,7 @@ RI_FKey_noaction_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "internal error #2 in ri_triggers.c");
|
elog(ERROR, "internal error #2 in ri_triggers.c");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -713,10 +708,10 @@ RI_FKey_noaction_del(FmgrInfo *proinfo)
|
||||||
* integrity constraint.
|
* integrity constraint.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
Datum
|
||||||
RI_FKey_noaction_upd(FmgrInfo *proinfo)
|
RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
int tgnargs;
|
int tgnargs;
|
||||||
char **tgargs;
|
char **tgargs;
|
||||||
Relation fk_rel;
|
Relation fk_rel;
|
||||||
|
@ -730,15 +725,13 @@ RI_FKey_noaction_upd(FmgrInfo *proinfo)
|
||||||
bool isnull;
|
bool isnull;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
ReferentialIntegritySnapshotOverride = true;
|
ReferentialIntegritySnapshotOverride = true;
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Check that this is a valid trigger call on the right time and event.
|
* Check that this is a valid trigger call on the right time and event.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (trigdata == NULL)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "RI_FKey_noaction_upd() not fired by trigger manager");
|
elog(ERROR, "RI_FKey_noaction_upd() not fired by trigger manager");
|
||||||
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
||||||
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
||||||
|
@ -763,7 +756,7 @@ RI_FKey_noaction_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (tgnargs == 4)
|
if (tgnargs == 4)
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Get the relation descriptors of the FK and PK tables and
|
* Get the relation descriptors of the FK and PK tables and
|
||||||
|
@ -801,7 +794,7 @@ RI_FKey_noaction_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
heap_close(fk_rel, NoLock);
|
heap_close(fk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
case RI_KEYS_NONE_NULL:
|
case RI_KEYS_NONE_NULL:
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -818,7 +811,7 @@ RI_FKey_noaction_upd(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
|
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
|
||||||
RI_KEYPAIR_PK_IDX))
|
RI_KEYPAIR_PK_IDX))
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
if (SPI_connect() != SPI_OK_CONNECT)
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
elog(NOTICE, "SPI_connect() failed in RI_FKey_noaction_upd()");
|
elog(NOTICE, "SPI_connect() failed in RI_FKey_noaction_upd()");
|
||||||
|
@ -904,7 +897,7 @@ RI_FKey_noaction_upd(FmgrInfo *proinfo)
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(NOTICE, "SPI_finish() failed in RI_FKey_noaction_upd()");
|
elog(NOTICE, "SPI_finish() failed in RI_FKey_noaction_upd()");
|
||||||
|
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Handle MATCH PARTIAL noaction update.
|
* Handle MATCH PARTIAL noaction update.
|
||||||
|
@ -912,7 +905,7 @@ RI_FKey_noaction_upd(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
case RI_MATCH_TYPE_PARTIAL:
|
case RI_MATCH_TYPE_PARTIAL:
|
||||||
elog(ERROR, "MATCH PARTIAL not yet supported");
|
elog(ERROR, "MATCH PARTIAL not yet supported");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -920,7 +913,7 @@ RI_FKey_noaction_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "internal error #3 in ri_triggers.c");
|
elog(ERROR, "internal error #3 in ri_triggers.c");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -930,10 +923,10 @@ RI_FKey_noaction_upd(FmgrInfo *proinfo)
|
||||||
* Cascaded delete foreign key references at delete event on PK table.
|
* Cascaded delete foreign key references at delete event on PK table.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
Datum
|
||||||
RI_FKey_cascade_del(FmgrInfo *proinfo)
|
RI_FKey_cascade_del(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
int tgnargs;
|
int tgnargs;
|
||||||
char **tgargs;
|
char **tgargs;
|
||||||
Relation fk_rel;
|
Relation fk_rel;
|
||||||
|
@ -946,15 +939,13 @@ RI_FKey_cascade_del(FmgrInfo *proinfo)
|
||||||
bool isnull;
|
bool isnull;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
ReferentialIntegritySnapshotOverride = true;
|
ReferentialIntegritySnapshotOverride = true;
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Check that this is a valid trigger call on the right time and event.
|
* Check that this is a valid trigger call on the right time and event.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (trigdata == NULL)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "RI_FKey_cascade_del() not fired by trigger manager");
|
elog(ERROR, "RI_FKey_cascade_del() not fired by trigger manager");
|
||||||
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
||||||
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
||||||
|
@ -979,7 +970,7 @@ RI_FKey_cascade_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (tgnargs == 4)
|
if (tgnargs == 4)
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Get the relation descriptors of the FK and PK tables and
|
* Get the relation descriptors of the FK and PK tables and
|
||||||
|
@ -1016,7 +1007,7 @@ RI_FKey_cascade_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
heap_close(fk_rel, NoLock);
|
heap_close(fk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
case RI_KEYS_NONE_NULL:
|
case RI_KEYS_NONE_NULL:
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -1100,7 +1091,7 @@ RI_FKey_cascade_del(FmgrInfo *proinfo)
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(NOTICE, "SPI_finish() failed in RI_FKey_cascade_del()");
|
elog(NOTICE, "SPI_finish() failed in RI_FKey_cascade_del()");
|
||||||
|
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Handle MATCH PARTIAL cascaded delete.
|
* Handle MATCH PARTIAL cascaded delete.
|
||||||
|
@ -1108,7 +1099,7 @@ RI_FKey_cascade_del(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
case RI_MATCH_TYPE_PARTIAL:
|
case RI_MATCH_TYPE_PARTIAL:
|
||||||
elog(ERROR, "MATCH PARTIAL not yet supported");
|
elog(ERROR, "MATCH PARTIAL not yet supported");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -1116,7 +1107,7 @@ RI_FKey_cascade_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "internal error #4 in ri_triggers.c");
|
elog(ERROR, "internal error #4 in ri_triggers.c");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1126,10 +1117,10 @@ RI_FKey_cascade_del(FmgrInfo *proinfo)
|
||||||
* Cascaded update/delete foreign key references at update event on PK table.
|
* Cascaded update/delete foreign key references at update event on PK table.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
Datum
|
||||||
RI_FKey_cascade_upd(FmgrInfo *proinfo)
|
RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
int tgnargs;
|
int tgnargs;
|
||||||
char **tgargs;
|
char **tgargs;
|
||||||
Relation fk_rel;
|
Relation fk_rel;
|
||||||
|
@ -1144,15 +1135,13 @@ RI_FKey_cascade_upd(FmgrInfo *proinfo)
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
ReferentialIntegritySnapshotOverride = true;
|
ReferentialIntegritySnapshotOverride = true;
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Check that this is a valid trigger call on the right time and event.
|
* Check that this is a valid trigger call on the right time and event.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (trigdata == NULL)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "RI_FKey_cascade_upd() not fired by trigger manager");
|
elog(ERROR, "RI_FKey_cascade_upd() not fired by trigger manager");
|
||||||
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
||||||
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
||||||
|
@ -1177,7 +1166,7 @@ RI_FKey_cascade_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (tgnargs == 4)
|
if (tgnargs == 4)
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Get the relation descriptors of the FK and PK tables and
|
* Get the relation descriptors of the FK and PK tables and
|
||||||
|
@ -1215,7 +1204,7 @@ RI_FKey_cascade_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
heap_close(fk_rel, NoLock);
|
heap_close(fk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
case RI_KEYS_NONE_NULL:
|
case RI_KEYS_NONE_NULL:
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -1232,7 +1221,7 @@ RI_FKey_cascade_upd(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
|
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
|
||||||
RI_KEYPAIR_PK_IDX))
|
RI_KEYPAIR_PK_IDX))
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
if (SPI_connect() != SPI_OK_CONNECT)
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
elog(NOTICE, "SPI_connect() failed in RI_FKey_cascade_upd()");
|
elog(NOTICE, "SPI_connect() failed in RI_FKey_cascade_upd()");
|
||||||
|
@ -1328,7 +1317,7 @@ RI_FKey_cascade_upd(FmgrInfo *proinfo)
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(NOTICE, "SPI_finish() failed in RI_FKey_cascade_upd()");
|
elog(NOTICE, "SPI_finish() failed in RI_FKey_cascade_upd()");
|
||||||
|
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Handle MATCH PARTIAL cascade update.
|
* Handle MATCH PARTIAL cascade update.
|
||||||
|
@ -1336,7 +1325,7 @@ RI_FKey_cascade_upd(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
case RI_MATCH_TYPE_PARTIAL:
|
case RI_MATCH_TYPE_PARTIAL:
|
||||||
elog(ERROR, "MATCH PARTIAL not yet supported");
|
elog(ERROR, "MATCH PARTIAL not yet supported");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -1344,7 +1333,7 @@ RI_FKey_cascade_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "internal error #5 in ri_triggers.c");
|
elog(ERROR, "internal error #5 in ri_triggers.c");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1361,10 +1350,10 @@ RI_FKey_cascade_upd(FmgrInfo *proinfo)
|
||||||
* equivalent.
|
* equivalent.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
Datum
|
||||||
RI_FKey_restrict_del(FmgrInfo *proinfo)
|
RI_FKey_restrict_del(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
int tgnargs;
|
int tgnargs;
|
||||||
char **tgargs;
|
char **tgargs;
|
||||||
Relation fk_rel;
|
Relation fk_rel;
|
||||||
|
@ -1377,15 +1366,13 @@ RI_FKey_restrict_del(FmgrInfo *proinfo)
|
||||||
bool isnull;
|
bool isnull;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
ReferentialIntegritySnapshotOverride = true;
|
ReferentialIntegritySnapshotOverride = true;
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Check that this is a valid trigger call on the right time and event.
|
* Check that this is a valid trigger call on the right time and event.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (trigdata == NULL)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "RI_FKey_restrict_del() not fired by trigger manager");
|
elog(ERROR, "RI_FKey_restrict_del() not fired by trigger manager");
|
||||||
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
||||||
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
||||||
|
@ -1410,7 +1397,7 @@ RI_FKey_restrict_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (tgnargs == 4)
|
if (tgnargs == 4)
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Get the relation descriptors of the FK and PK tables and
|
* Get the relation descriptors of the FK and PK tables and
|
||||||
|
@ -1447,7 +1434,7 @@ RI_FKey_restrict_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
heap_close(fk_rel, NoLock);
|
heap_close(fk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
case RI_KEYS_NONE_NULL:
|
case RI_KEYS_NONE_NULL:
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -1542,7 +1529,7 @@ RI_FKey_restrict_del(FmgrInfo *proinfo)
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(NOTICE, "SPI_finish() failed in RI_FKey_restrict_del()");
|
elog(NOTICE, "SPI_finish() failed in RI_FKey_restrict_del()");
|
||||||
|
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Handle MATCH PARTIAL restrict delete.
|
* Handle MATCH PARTIAL restrict delete.
|
||||||
|
@ -1550,7 +1537,7 @@ RI_FKey_restrict_del(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
case RI_MATCH_TYPE_PARTIAL:
|
case RI_MATCH_TYPE_PARTIAL:
|
||||||
elog(ERROR, "MATCH PARTIAL not yet supported");
|
elog(ERROR, "MATCH PARTIAL not yet supported");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -1558,7 +1545,7 @@ RI_FKey_restrict_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "internal error #6 in ri_triggers.c");
|
elog(ERROR, "internal error #6 in ri_triggers.c");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1575,10 +1562,10 @@ RI_FKey_restrict_del(FmgrInfo *proinfo)
|
||||||
* equivalent.
|
* equivalent.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
Datum
|
||||||
RI_FKey_restrict_upd(FmgrInfo *proinfo)
|
RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
int tgnargs;
|
int tgnargs;
|
||||||
char **tgargs;
|
char **tgargs;
|
||||||
Relation fk_rel;
|
Relation fk_rel;
|
||||||
|
@ -1592,15 +1579,13 @@ RI_FKey_restrict_upd(FmgrInfo *proinfo)
|
||||||
bool isnull;
|
bool isnull;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
ReferentialIntegritySnapshotOverride = true;
|
ReferentialIntegritySnapshotOverride = true;
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Check that this is a valid trigger call on the right time and event.
|
* Check that this is a valid trigger call on the right time and event.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (trigdata == NULL)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "RI_FKey_restrict_upd() not fired by trigger manager");
|
elog(ERROR, "RI_FKey_restrict_upd() not fired by trigger manager");
|
||||||
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
||||||
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
||||||
|
@ -1625,7 +1610,7 @@ RI_FKey_restrict_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (tgnargs == 4)
|
if (tgnargs == 4)
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Get the relation descriptors of the FK and PK tables and
|
* Get the relation descriptors of the FK and PK tables and
|
||||||
|
@ -1663,7 +1648,7 @@ RI_FKey_restrict_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
heap_close(fk_rel, NoLock);
|
heap_close(fk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
case RI_KEYS_NONE_NULL:
|
case RI_KEYS_NONE_NULL:
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -1680,7 +1665,7 @@ RI_FKey_restrict_upd(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
|
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
|
||||||
RI_KEYPAIR_PK_IDX))
|
RI_KEYPAIR_PK_IDX))
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
if (SPI_connect() != SPI_OK_CONNECT)
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
elog(NOTICE, "SPI_connect() failed in RI_FKey_restrict_upd()");
|
elog(NOTICE, "SPI_connect() failed in RI_FKey_restrict_upd()");
|
||||||
|
@ -1766,7 +1751,7 @@ RI_FKey_restrict_upd(FmgrInfo *proinfo)
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(NOTICE, "SPI_finish() failed in RI_FKey_restrict_upd()");
|
elog(NOTICE, "SPI_finish() failed in RI_FKey_restrict_upd()");
|
||||||
|
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Handle MATCH PARTIAL restrict update.
|
* Handle MATCH PARTIAL restrict update.
|
||||||
|
@ -1774,7 +1759,7 @@ RI_FKey_restrict_upd(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
case RI_MATCH_TYPE_PARTIAL:
|
case RI_MATCH_TYPE_PARTIAL:
|
||||||
elog(ERROR, "MATCH PARTIAL not yet supported");
|
elog(ERROR, "MATCH PARTIAL not yet supported");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -1782,7 +1767,7 @@ RI_FKey_restrict_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "internal error #7 in ri_triggers.c");
|
elog(ERROR, "internal error #7 in ri_triggers.c");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1792,10 +1777,10 @@ RI_FKey_restrict_upd(FmgrInfo *proinfo)
|
||||||
* Set foreign key references to NULL values at delete event on PK table.
|
* Set foreign key references to NULL values at delete event on PK table.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
Datum
|
||||||
RI_FKey_setnull_del(FmgrInfo *proinfo)
|
RI_FKey_setnull_del(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
int tgnargs;
|
int tgnargs;
|
||||||
char **tgargs;
|
char **tgargs;
|
||||||
Relation fk_rel;
|
Relation fk_rel;
|
||||||
|
@ -1808,15 +1793,13 @@ RI_FKey_setnull_del(FmgrInfo *proinfo)
|
||||||
bool isnull;
|
bool isnull;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
ReferentialIntegritySnapshotOverride = true;
|
ReferentialIntegritySnapshotOverride = true;
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Check that this is a valid trigger call on the right time and event.
|
* Check that this is a valid trigger call on the right time and event.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (trigdata == NULL)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "RI_FKey_setnull_del() not fired by trigger manager");
|
elog(ERROR, "RI_FKey_setnull_del() not fired by trigger manager");
|
||||||
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
||||||
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
||||||
|
@ -1841,7 +1824,7 @@ RI_FKey_setnull_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (tgnargs == 4)
|
if (tgnargs == 4)
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Get the relation descriptors of the FK and PK tables and
|
* Get the relation descriptors of the FK and PK tables and
|
||||||
|
@ -1878,7 +1861,7 @@ RI_FKey_setnull_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
heap_close(fk_rel, NoLock);
|
heap_close(fk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
case RI_KEYS_NONE_NULL:
|
case RI_KEYS_NONE_NULL:
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -1973,7 +1956,7 @@ RI_FKey_setnull_del(FmgrInfo *proinfo)
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(NOTICE, "SPI_finish() failed in RI_FKey_setnull_del()");
|
elog(NOTICE, "SPI_finish() failed in RI_FKey_setnull_del()");
|
||||||
|
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Handle MATCH PARTIAL set null delete.
|
* Handle MATCH PARTIAL set null delete.
|
||||||
|
@ -1981,7 +1964,7 @@ RI_FKey_setnull_del(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
case RI_MATCH_TYPE_PARTIAL:
|
case RI_MATCH_TYPE_PARTIAL:
|
||||||
elog(ERROR, "MATCH PARTIAL not yet supported");
|
elog(ERROR, "MATCH PARTIAL not yet supported");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -1989,7 +1972,7 @@ RI_FKey_setnull_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "internal error #8 in ri_triggers.c");
|
elog(ERROR, "internal error #8 in ri_triggers.c");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1999,10 +1982,10 @@ RI_FKey_setnull_del(FmgrInfo *proinfo)
|
||||||
* Set foreign key references to NULL at update event on PK table.
|
* Set foreign key references to NULL at update event on PK table.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
Datum
|
||||||
RI_FKey_setnull_upd(FmgrInfo *proinfo)
|
RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
int tgnargs;
|
int tgnargs;
|
||||||
char **tgargs;
|
char **tgargs;
|
||||||
Relation fk_rel;
|
Relation fk_rel;
|
||||||
|
@ -2018,15 +2001,13 @@ RI_FKey_setnull_upd(FmgrInfo *proinfo)
|
||||||
int match_type;
|
int match_type;
|
||||||
bool use_cached_query;
|
bool use_cached_query;
|
||||||
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
ReferentialIntegritySnapshotOverride = true;
|
ReferentialIntegritySnapshotOverride = true;
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Check that this is a valid trigger call on the right time and event.
|
* Check that this is a valid trigger call on the right time and event.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (trigdata == NULL)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "RI_FKey_setnull_upd() not fired by trigger manager");
|
elog(ERROR, "RI_FKey_setnull_upd() not fired by trigger manager");
|
||||||
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
||||||
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
||||||
|
@ -2051,7 +2032,7 @@ RI_FKey_setnull_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (tgnargs == 4)
|
if (tgnargs == 4)
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Get the relation descriptors of the FK and PK tables and
|
* Get the relation descriptors of the FK and PK tables and
|
||||||
|
@ -2090,7 +2071,7 @@ RI_FKey_setnull_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
heap_close(fk_rel, NoLock);
|
heap_close(fk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
case RI_KEYS_NONE_NULL:
|
case RI_KEYS_NONE_NULL:
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -2108,7 +2089,7 @@ RI_FKey_setnull_upd(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
|
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
|
||||||
RI_KEYPAIR_PK_IDX))
|
RI_KEYPAIR_PK_IDX))
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
if (SPI_connect() != SPI_OK_CONNECT)
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
elog(NOTICE, "SPI_connect() failed in RI_FKey_setnull_upd()");
|
elog(NOTICE, "SPI_connect() failed in RI_FKey_setnull_upd()");
|
||||||
|
@ -2231,7 +2212,7 @@ RI_FKey_setnull_upd(FmgrInfo *proinfo)
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(NOTICE, "SPI_finish() failed in RI_FKey_setnull_upd()");
|
elog(NOTICE, "SPI_finish() failed in RI_FKey_setnull_upd()");
|
||||||
|
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Handle MATCH PARTIAL set null update.
|
* Handle MATCH PARTIAL set null update.
|
||||||
|
@ -2239,7 +2220,7 @@ RI_FKey_setnull_upd(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
case RI_MATCH_TYPE_PARTIAL:
|
case RI_MATCH_TYPE_PARTIAL:
|
||||||
elog(ERROR, "MATCH PARTIAL not yet supported");
|
elog(ERROR, "MATCH PARTIAL not yet supported");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -2247,7 +2228,7 @@ RI_FKey_setnull_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "internal error #9 in ri_triggers.c");
|
elog(ERROR, "internal error #9 in ri_triggers.c");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2257,10 +2238,10 @@ RI_FKey_setnull_upd(FmgrInfo *proinfo)
|
||||||
* Set foreign key references to defaults at delete event on PK table.
|
* Set foreign key references to defaults at delete event on PK table.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
Datum
|
||||||
RI_FKey_setdefault_del(FmgrInfo *proinfo)
|
RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
int tgnargs;
|
int tgnargs;
|
||||||
char **tgargs;
|
char **tgargs;
|
||||||
Relation fk_rel;
|
Relation fk_rel;
|
||||||
|
@ -2273,15 +2254,13 @@ RI_FKey_setdefault_del(FmgrInfo *proinfo)
|
||||||
bool isnull;
|
bool isnull;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
ReferentialIntegritySnapshotOverride = true;
|
ReferentialIntegritySnapshotOverride = true;
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Check that this is a valid trigger call on the right time and event.
|
* Check that this is a valid trigger call on the right time and event.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (trigdata == NULL)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "RI_FKey_setdefault_del() not fired by trigger manager");
|
elog(ERROR, "RI_FKey_setdefault_del() not fired by trigger manager");
|
||||||
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
||||||
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
||||||
|
@ -2306,7 +2285,7 @@ RI_FKey_setdefault_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (tgnargs == 4)
|
if (tgnargs == 4)
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Get the relation descriptors of the FK and PK tables and
|
* Get the relation descriptors of the FK and PK tables and
|
||||||
|
@ -2343,7 +2322,7 @@ RI_FKey_setdefault_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
heap_close(fk_rel, NoLock);
|
heap_close(fk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
case RI_KEYS_NONE_NULL:
|
case RI_KEYS_NONE_NULL:
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -2485,7 +2464,7 @@ RI_FKey_setdefault_del(FmgrInfo *proinfo)
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(NOTICE, "SPI_finish() failed in RI_FKey_setdefault_del()");
|
elog(NOTICE, "SPI_finish() failed in RI_FKey_setdefault_del()");
|
||||||
|
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Handle MATCH PARTIAL set null delete.
|
* Handle MATCH PARTIAL set null delete.
|
||||||
|
@ -2493,7 +2472,7 @@ RI_FKey_setdefault_del(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
case RI_MATCH_TYPE_PARTIAL:
|
case RI_MATCH_TYPE_PARTIAL:
|
||||||
elog(ERROR, "MATCH PARTIAL not yet supported");
|
elog(ERROR, "MATCH PARTIAL not yet supported");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -2501,7 +2480,7 @@ RI_FKey_setdefault_del(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "internal error #10 in ri_triggers.c");
|
elog(ERROR, "internal error #10 in ri_triggers.c");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2511,10 +2490,10 @@ RI_FKey_setdefault_del(FmgrInfo *proinfo)
|
||||||
* Set foreign key references to defaults at update event on PK table.
|
* Set foreign key references to defaults at update event on PK table.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
Datum
|
||||||
RI_FKey_setdefault_upd(FmgrInfo *proinfo)
|
RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
int tgnargs;
|
int tgnargs;
|
||||||
char **tgargs;
|
char **tgargs;
|
||||||
Relation fk_rel;
|
Relation fk_rel;
|
||||||
|
@ -2529,15 +2508,13 @@ RI_FKey_setdefault_upd(FmgrInfo *proinfo)
|
||||||
int i;
|
int i;
|
||||||
int match_type;
|
int match_type;
|
||||||
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
ReferentialIntegritySnapshotOverride = true;
|
ReferentialIntegritySnapshotOverride = true;
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Check that this is a valid trigger call on the right time and event.
|
* Check that this is a valid trigger call on the right time and event.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (trigdata == NULL)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "RI_FKey_setdefault_upd() not fired by trigger manager");
|
elog(ERROR, "RI_FKey_setdefault_upd() not fired by trigger manager");
|
||||||
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
||||||
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
||||||
|
@ -2562,7 +2539,7 @@ RI_FKey_setdefault_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (tgnargs == 4)
|
if (tgnargs == 4)
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Get the relation descriptors of the FK and PK tables and
|
* Get the relation descriptors of the FK and PK tables and
|
||||||
|
@ -2602,7 +2579,7 @@ RI_FKey_setdefault_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
heap_close(fk_rel, NoLock);
|
heap_close(fk_rel, NoLock);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
case RI_KEYS_NONE_NULL:
|
case RI_KEYS_NONE_NULL:
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -2619,7 +2596,7 @@ RI_FKey_setdefault_upd(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
|
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
|
||||||
RI_KEYPAIR_PK_IDX))
|
RI_KEYPAIR_PK_IDX))
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
if (SPI_connect() != SPI_OK_CONNECT)
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
elog(NOTICE, "SPI_connect() failed in RI_FKey_setdefault_upd()");
|
elog(NOTICE, "SPI_connect() failed in RI_FKey_setdefault_upd()");
|
||||||
|
@ -2769,7 +2746,7 @@ RI_FKey_setdefault_upd(FmgrInfo *proinfo)
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(NOTICE, "SPI_finish() failed in RI_FKey_setdefault_upd()");
|
elog(NOTICE, "SPI_finish() failed in RI_FKey_setdefault_upd()");
|
||||||
|
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Handle MATCH PARTIAL set null delete.
|
* Handle MATCH PARTIAL set null delete.
|
||||||
|
@ -2777,7 +2754,7 @@ RI_FKey_setdefault_upd(FmgrInfo *proinfo)
|
||||||
*/
|
*/
|
||||||
case RI_MATCH_TYPE_PARTIAL:
|
case RI_MATCH_TYPE_PARTIAL:
|
||||||
elog(ERROR, "MATCH PARTIAL not yet supported");
|
elog(ERROR, "MATCH PARTIAL not yet supported");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -2785,7 +2762,7 @@ RI_FKey_setdefault_upd(FmgrInfo *proinfo)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "internal error #11 in ri_triggers.c");
|
elog(ERROR, "internal error #11 in ri_triggers.c");
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2794,14 +2771,13 @@ RI_FKey_setdefault_upd(FmgrInfo *proinfo)
|
||||||
*
|
*
|
||||||
* Check if we have a key change on update.
|
* Check if we have a key change on update.
|
||||||
*
|
*
|
||||||
* This is no real trigger procedure. It is used by the deferred
|
* This is not a real trigger procedure. It is used by the deferred
|
||||||
* trigger queue manager to detect "triggered data change violation".
|
* trigger queue manager to detect "triggered data change violation".
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
RI_FKey_keyequal_upd(void)
|
RI_FKey_keyequal_upd(TriggerData *trigdata)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
|
||||||
int tgnargs;
|
int tgnargs;
|
||||||
char **tgargs;
|
char **tgargs;
|
||||||
Relation fk_rel;
|
Relation fk_rel;
|
||||||
|
@ -2810,9 +2786,6 @@ RI_FKey_keyequal_upd(void)
|
||||||
HeapTuple old_row;
|
HeapTuple old_row;
|
||||||
RI_QueryKey qkey;
|
RI_QueryKey qkey;
|
||||||
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Check for the correct # of call arguments
|
* Check for the correct # of call arguments
|
||||||
* ----------
|
* ----------
|
||||||
|
@ -3262,8 +3235,10 @@ ri_OneKeyEqual(Relation rel, int column, HeapTuple oldtup, HeapTuple newtup,
|
||||||
/* ----------
|
/* ----------
|
||||||
* ri_AttributesEqual -
|
* ri_AttributesEqual -
|
||||||
*
|
*
|
||||||
* Call the type specific '=' operator comparision function
|
* Call the type specific '=' operator comparison function
|
||||||
* for two values.
|
* for two values.
|
||||||
|
*
|
||||||
|
* NB: we have already checked that neither value is null.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
|
@ -3271,7 +3246,6 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
|
||||||
{
|
{
|
||||||
RI_OpreqHashEntry *entry;
|
RI_OpreqHashEntry *entry;
|
||||||
bool found;
|
bool found;
|
||||||
Datum result;
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* On the first call initialize the hashtable
|
* On the first call initialize the hashtable
|
||||||
|
@ -3291,6 +3265,7 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* If not found, lookup the OPERNAME system cache for it
|
* If not found, lookup the OPERNAME system cache for it
|
||||||
|
* to get the func OID, then do the function manager lookup,
|
||||||
* and remember that info.
|
* and remember that info.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
|
@ -3307,7 +3282,7 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
|
||||||
|
|
||||||
if (!HeapTupleIsValid(opr_tup))
|
if (!HeapTupleIsValid(opr_tup))
|
||||||
elog(ERROR, "ri_AttributesEqual(): cannot find '=' operator "
|
elog(ERROR, "ri_AttributesEqual(): cannot find '=' operator "
|
||||||
"for type %d", typeid);
|
"for type %u", typeid);
|
||||||
opr_struct = (Form_pg_operator) GETSTRUCT(opr_tup);
|
opr_struct = (Form_pg_operator) GETSTRUCT(opr_tup);
|
||||||
|
|
||||||
entry = (RI_OpreqHashEntry *) hash_search(ri_opreq_cache,
|
entry = (RI_OpreqHashEntry *) hash_search(ri_opreq_cache,
|
||||||
|
@ -3315,15 +3290,14 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
elog(FATAL, "can't insert into RI operator cache");
|
elog(FATAL, "can't insert into RI operator cache");
|
||||||
|
|
||||||
entry->oprfnid = opr_struct->oprcode;
|
entry->typeid = typeid;
|
||||||
memset(&(entry->oprfmgrinfo), 0, sizeof(FmgrInfo));
|
fmgr_info(opr_struct->oprcode, &(entry->oprfmgrinfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Call the type specific '=' function
|
* Call the type specific '=' function
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
fmgr_info(entry->oprfnid, &(entry->oprfmgrinfo));
|
return DatumGetBool(FunctionCall2(&(entry->oprfmgrinfo),
|
||||||
result = (Datum) (*fmgr_faddr(&(entry->oprfmgrinfo))) (oldvalue, newvalue);
|
oldvalue, newvalue));
|
||||||
return (bool) result;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.16 2000/04/12 17:15:51 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.17 2000/05/29 01:59:08 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* input routine largely stolen from boxin().
|
* input routine largely stolen from boxin().
|
||||||
|
@ -17,6 +17,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "access/heapam.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
#define LDELIM '('
|
#define LDELIM '('
|
||||||
|
|
|
@ -8,16 +8,17 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.26 2000/04/14 15:22:10 thomas Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.27 2000/05/29 01:59:08 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include <ctype.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#ifdef HAVE_FLOAT_H
|
#ifdef HAVE_FLOAT_H
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
#include <sys/timeb.h>
|
#include <sys/timeb.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "access/xact.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.40 2000/05/28 17:56:07 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.41 2000/05/29 01:59:09 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
#include "catalog/pg_language.h"
|
#include "catalog/pg_language.h"
|
||||||
#include "catalog/pg_proc.h"
|
#include "catalog/pg_proc.h"
|
||||||
#include "commands/trigger.h" /* TEMPORARY: for CurrentTriggerData */
|
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgrtab.h"
|
#include "utils/fmgrtab.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: catversion.h,v 1.22 2000/05/28 17:56:16 tgl Exp $
|
* $Id: catversion.h,v 1.23 2000/05/29 01:59:10 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -53,6 +53,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200005281
|
#define CATALOG_VERSION_NO 200005282
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: pg_proc.h,v 1.134 2000/05/28 17:56:16 tgl Exp $
|
* $Id: pg_proc.h,v 1.135 2000/05/29 01:59:10 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The script catalog/genbki.sh reads this file and generates .bki
|
* The script catalog/genbki.sh reads this file and generates .bki
|
||||||
|
@ -2103,7 +2103,7 @@ DESCR("less-than");
|
||||||
DATA(insert OID = 1656 ( lztext_le PGUID 11 f t t t 2 f 16 "1625 1625" 100 0 1 0 lztext_le - ));
|
DATA(insert OID = 1656 ( lztext_le PGUID 11 f t t t 2 f 16 "1625 1625" 100 0 1 0 lztext_le - ));
|
||||||
DESCR("less-than-or-equal");
|
DESCR("less-than-or-equal");
|
||||||
|
|
||||||
DATA(insert OID = 1689 ( update_pg_pwd PGUID 11 f t f t 0 f 0 "" 100 0 0 100 update_pg_pwd - ));
|
DATA(insert OID = 1689 ( update_pg_pwd PGUID 12 f t f t 0 f 0 "" 100 0 0 100 update_pg_pwd - ));
|
||||||
DESCR("update pg_pwd file");
|
DESCR("update pg_pwd file");
|
||||||
|
|
||||||
/* Oracle Compatibility Related Functions - By Edmund Mergl <E.Mergl@bawue.de> */
|
/* Oracle Compatibility Related Functions - By Edmund Mergl <E.Mergl@bawue.de> */
|
||||||
|
@ -2163,29 +2163,29 @@ DATA(insert OID = 1643 ( pg_get_indexdef PGUID 11 f t f t 1 f 25 "26" 100 0
|
||||||
DESCR("index description");
|
DESCR("index description");
|
||||||
|
|
||||||
/* Generic referential integrity constraint triggers */
|
/* Generic referential integrity constraint triggers */
|
||||||
DATA(insert OID = 1644 ( RI_FKey_check_ins PGUID 11 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_check_ins - ));
|
DATA(insert OID = 1644 ( RI_FKey_check_ins PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_check_ins - ));
|
||||||
DESCR("referential integrity FOREIGN KEY ... REFERENCES");
|
DESCR("referential integrity FOREIGN KEY ... REFERENCES");
|
||||||
DATA(insert OID = 1645 ( RI_FKey_check_upd PGUID 11 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_check_upd - ));
|
DATA(insert OID = 1645 ( RI_FKey_check_upd PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_check_upd - ));
|
||||||
DESCR("referential integrity FOREIGN KEY ... REFERENCES");
|
DESCR("referential integrity FOREIGN KEY ... REFERENCES");
|
||||||
DATA(insert OID = 1646 ( RI_FKey_cascade_del PGUID 11 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_cascade_del - ));
|
DATA(insert OID = 1646 ( RI_FKey_cascade_del PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_cascade_del - ));
|
||||||
DESCR("referential integrity ON DELETE CASCADE");
|
DESCR("referential integrity ON DELETE CASCADE");
|
||||||
DATA(insert OID = 1647 ( RI_FKey_cascade_upd PGUID 11 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_cascade_upd - ));
|
DATA(insert OID = 1647 ( RI_FKey_cascade_upd PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_cascade_upd - ));
|
||||||
DESCR("referential integrity ON UPDATE CASCADE");
|
DESCR("referential integrity ON UPDATE CASCADE");
|
||||||
DATA(insert OID = 1648 ( RI_FKey_restrict_del PGUID 11 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_restrict_del - ));
|
DATA(insert OID = 1648 ( RI_FKey_restrict_del PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_restrict_del - ));
|
||||||
DESCR("referential integrity ON DELETE RESTRICT");
|
DESCR("referential integrity ON DELETE RESTRICT");
|
||||||
DATA(insert OID = 1649 ( RI_FKey_restrict_upd PGUID 11 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_restrict_upd - ));
|
DATA(insert OID = 1649 ( RI_FKey_restrict_upd PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_restrict_upd - ));
|
||||||
DESCR("referential integrity ON UPDATE RESTRICT");
|
DESCR("referential integrity ON UPDATE RESTRICT");
|
||||||
DATA(insert OID = 1650 ( RI_FKey_setnull_del PGUID 11 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_setnull_del - ));
|
DATA(insert OID = 1650 ( RI_FKey_setnull_del PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_setnull_del - ));
|
||||||
DESCR("referential integrity ON DELETE SET NULL");
|
DESCR("referential integrity ON DELETE SET NULL");
|
||||||
DATA(insert OID = 1651 ( RI_FKey_setnull_upd PGUID 11 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_setnull_upd - ));
|
DATA(insert OID = 1651 ( RI_FKey_setnull_upd PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_setnull_upd - ));
|
||||||
DESCR("referential integrity ON UPDATE SET NULL");
|
DESCR("referential integrity ON UPDATE SET NULL");
|
||||||
DATA(insert OID = 1652 ( RI_FKey_setdefault_del PGUID 11 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_setdefault_del - ));
|
DATA(insert OID = 1652 ( RI_FKey_setdefault_del PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_setdefault_del - ));
|
||||||
DESCR("referential integrity ON DELETE SET DEFAULT");
|
DESCR("referential integrity ON DELETE SET DEFAULT");
|
||||||
DATA(insert OID = 1653 ( RI_FKey_setdefault_upd PGUID 11 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_setdefault_upd - ));
|
DATA(insert OID = 1653 ( RI_FKey_setdefault_upd PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_setdefault_upd - ));
|
||||||
DESCR("referential integrity ON UPDATE SET DEFAULT");
|
DESCR("referential integrity ON UPDATE SET DEFAULT");
|
||||||
DATA(insert OID = 1654 ( RI_FKey_noaction_del PGUID 11 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_noaction_del - ));
|
DATA(insert OID = 1654 ( RI_FKey_noaction_del PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_noaction_del - ));
|
||||||
DESCR("referential integrity ON DELETE NO ACTION");
|
DESCR("referential integrity ON DELETE NO ACTION");
|
||||||
DATA(insert OID = 1655 ( RI_FKey_noaction_upd PGUID 11 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_noaction_upd - ));
|
DATA(insert OID = 1655 ( RI_FKey_noaction_upd PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_noaction_upd - ));
|
||||||
DESCR("referential integrity ON UPDATE NO ACTION");
|
DESCR("referential integrity ON UPDATE NO ACTION");
|
||||||
|
|
||||||
DATA(insert OID = 1666 ( varbiteq PGUID 11 f t t t 2 f 16 "1562 1562" 100 0 1 0 varbiteq - ));
|
DATA(insert OID = 1666 ( varbiteq PGUID 11 f t t t 2 f 16 "1562 1562" 100 0 1 0 varbiteq - ));
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* trigger.h
|
* trigger.h
|
||||||
* prototypes for trigger.c.
|
* Declarations for trigger handling.
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: trigger.h,v 1.19 2000/04/12 17:16:32 momjian Exp $
|
* $Id: trigger.h,v 1.20 2000/05/29 01:59:11 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -16,10 +16,19 @@
|
||||||
#include "nodes/execnodes.h"
|
#include "nodes/execnodes.h"
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TriggerData is the node type that is passed as fmgr "context" info
|
||||||
|
* when a function is called by the trigger manager.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CALLED_AS_TRIGGER(fcinfo) \
|
||||||
|
((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))
|
||||||
|
|
||||||
typedef uint32 TriggerEvent;
|
typedef uint32 TriggerEvent;
|
||||||
|
|
||||||
typedef struct TriggerData
|
typedef struct TriggerData
|
||||||
{
|
{
|
||||||
|
NodeTag type;
|
||||||
TriggerEvent tg_event;
|
TriggerEvent tg_event;
|
||||||
Relation tg_relation;
|
Relation tg_relation;
|
||||||
HeapTuple tg_trigtuple;
|
HeapTuple tg_trigtuple;
|
||||||
|
@ -27,7 +36,7 @@ typedef struct TriggerData
|
||||||
Trigger *tg_trigger;
|
Trigger *tg_trigger;
|
||||||
} TriggerData;
|
} TriggerData;
|
||||||
|
|
||||||
extern DLLIMPORT TriggerData *CurrentTriggerData;
|
/* TriggerEvent bit flags */
|
||||||
|
|
||||||
#define TRIGGER_EVENT_INSERT 0x00000000
|
#define TRIGGER_EVENT_INSERT 0x00000000
|
||||||
#define TRIGGER_EVENT_DELETE 0x00000001
|
#define TRIGGER_EVENT_DELETE 0x00000001
|
||||||
|
@ -136,6 +145,6 @@ extern void DeferredTriggerSaveEvent(Relation rel, int event,
|
||||||
* in utils/adt/ri_triggers.c
|
* in utils/adt/ri_triggers.c
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
extern bool RI_FKey_keyequal_upd(void);
|
extern bool RI_FKey_keyequal_upd(TriggerData *trigdata);
|
||||||
|
|
||||||
#endif /* TRIGGER_H */
|
#endif /* TRIGGER_H */
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* user.h
|
* user.h
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
* $Id: user.h,v 1.12 2000/05/29 01:59:11 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -21,6 +21,6 @@ extern void CreateGroup(CreateGroupStmt *stmt);
|
||||||
extern void AlterGroup(AlterGroupStmt *stmt, const char *tag);
|
extern void AlterGroup(AlterGroupStmt *stmt, const char *tag);
|
||||||
extern void DropGroup(DropGroupStmt *stmt);
|
extern void DropGroup(DropGroupStmt *stmt);
|
||||||
|
|
||||||
extern HeapTuple update_pg_pwd(void);
|
extern Datum update_pg_pwd(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
#endif /* USER_H */
|
#endif /* USER_H */
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: executor.h,v 1.42 2000/01/26 05:58:05 momjian Exp $
|
* $Id: executor.h,v 1.43 2000/05/29 01:59:11 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -59,6 +59,8 @@ extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
||||||
extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
|
extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
|
||||||
extern void ExecConstraints(char *caller, Relation rel, HeapTuple tuple,
|
extern void ExecConstraints(char *caller, Relation rel, HeapTuple tuple,
|
||||||
EState *estate);
|
EState *estate);
|
||||||
|
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
|
||||||
|
ItemPointer tid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* prototypes from functions in execProcnode.c
|
* prototypes from functions in execProcnode.c
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: fmgr.h,v 1.1 2000/05/28 17:56:12 tgl Exp $
|
* $Id: fmgr.h,v 1.2 2000/05/29 01:59:09 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -107,6 +107,7 @@ extern void fmgr_info(Oid functionId, FmgrInfo *finfo);
|
||||||
#define PG_GETARG_BOOL(n) DatumGetBool(fcinfo->arg[n])
|
#define PG_GETARG_BOOL(n) DatumGetBool(fcinfo->arg[n])
|
||||||
#define PG_GETARG_OID(n) DatumGetObjectId(fcinfo->arg[n])
|
#define PG_GETARG_OID(n) DatumGetObjectId(fcinfo->arg[n])
|
||||||
#define PG_GETARG_POINTER(n) DatumGetPointer(fcinfo->arg[n])
|
#define PG_GETARG_POINTER(n) DatumGetPointer(fcinfo->arg[n])
|
||||||
|
#define PG_GETARG_NAME(n) DatumGetName(fcinfo->arg[n])
|
||||||
/* these macros hide the pass-by-reference-ness of the datatype: */
|
/* these macros hide the pass-by-reference-ness of the datatype: */
|
||||||
#define PG_GETARG_FLOAT4(n) DatumGetFloat4(fcinfo->arg[n])
|
#define PG_GETARG_FLOAT4(n) DatumGetFloat4(fcinfo->arg[n])
|
||||||
#define PG_GETARG_FLOAT8(n) DatumGetFloat8(fcinfo->arg[n])
|
#define PG_GETARG_FLOAT8(n) DatumGetFloat8(fcinfo->arg[n])
|
||||||
|
@ -133,6 +134,7 @@ extern void fmgr_info(Oid functionId, FmgrInfo *finfo);
|
||||||
#define PG_RETURN_BOOL(x) return BoolGetDatum(x)
|
#define PG_RETURN_BOOL(x) return BoolGetDatum(x)
|
||||||
#define PG_RETURN_OID(x) return ObjectIdGetDatum(x)
|
#define PG_RETURN_OID(x) return ObjectIdGetDatum(x)
|
||||||
#define PG_RETURN_POINTER(x) return PointerGetDatum(x)
|
#define PG_RETURN_POINTER(x) return PointerGetDatum(x)
|
||||||
|
#define PG_RETURN_NAME(x) return NameGetDatum(x)
|
||||||
/* these macros hide the pass-by-reference-ness of the datatype: */
|
/* these macros hide the pass-by-reference-ness of the datatype: */
|
||||||
#define PG_RETURN_FLOAT4(x) return Float4GetDatum(x)
|
#define PG_RETURN_FLOAT4(x) return Float4GetDatum(x)
|
||||||
#define PG_RETURN_FLOAT8(x) return Float8GetDatum(x)
|
#define PG_RETURN_FLOAT8(x) return Float8GetDatum(x)
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: nodes.h,v 1.67 2000/04/12 17:16:40 momjian Exp $
|
* $Id: nodes.h,v 1.68 2000/05/29 01:59:12 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -223,7 +223,13 @@ typedef enum NodeTag
|
||||||
T_CaseExpr,
|
T_CaseExpr,
|
||||||
T_CaseWhen,
|
T_CaseWhen,
|
||||||
T_RowMark,
|
T_RowMark,
|
||||||
T_FkConstraint
|
T_FkConstraint,
|
||||||
|
|
||||||
|
/*---------------------
|
||||||
|
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (cf. fmgr.h)
|
||||||
|
*---------------------
|
||||||
|
*/
|
||||||
|
T_TriggerData = 800 /* in commands/trigger.h */
|
||||||
} NodeTag;
|
} NodeTag;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -7,23 +7,14 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: builtins.h,v 1.111 2000/04/16 04:41:03 tgl Exp $
|
* $Id: builtins.h,v 1.112 2000/05/29 01:59:13 tgl Exp $
|
||||||
*
|
|
||||||
* NOTES
|
|
||||||
* This should normally only be included by fmgr.h.
|
|
||||||
* Under no circumstances should it ever be included before
|
|
||||||
* including fmgr.h!
|
|
||||||
* fmgr.h does not seem to include this file, so don't know where this
|
|
||||||
* comment came from. Backend code must include this stuff explicitly
|
|
||||||
* as far as I can tell...
|
|
||||||
* - thomas 1998-06-08
|
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#ifndef BUILTINS_H
|
#ifndef BUILTINS_H
|
||||||
#define BUILTINS_H
|
#define BUILTINS_H
|
||||||
|
|
||||||
#include "access/heapam.h" /* for HeapTuple */
|
#include "fmgr.h"
|
||||||
#include "nodes/relation.h" /* for amcostestimate parameters */
|
#include "nodes/relation.h" /* for amcostestimate parameters */
|
||||||
#include "storage/itemptr.h"
|
#include "storage/itemptr.h"
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
|
@ -648,17 +639,17 @@ bool lztext_lt(lztext *lz1, lztext *lz2);
|
||||||
bool lztext_le(lztext *lz1, lztext *lz2);
|
bool lztext_le(lztext *lz1, lztext *lz2);
|
||||||
|
|
||||||
/* ri_triggers.c */
|
/* ri_triggers.c */
|
||||||
extern HeapTuple RI_FKey_check_ins(FmgrInfo *proinfo);
|
extern Datum RI_FKey_check_ins(PG_FUNCTION_ARGS);
|
||||||
extern HeapTuple RI_FKey_check_upd(FmgrInfo *proinfo);
|
extern Datum RI_FKey_check_upd(PG_FUNCTION_ARGS);
|
||||||
extern HeapTuple RI_FKey_noaction_del(FmgrInfo *proinfo);
|
extern Datum RI_FKey_noaction_del(PG_FUNCTION_ARGS);
|
||||||
extern HeapTuple RI_FKey_noaction_upd(FmgrInfo *proinfo);
|
extern Datum RI_FKey_noaction_upd(PG_FUNCTION_ARGS);
|
||||||
extern HeapTuple RI_FKey_cascade_del(FmgrInfo *proinfo);
|
extern Datum RI_FKey_cascade_del(PG_FUNCTION_ARGS);
|
||||||
extern HeapTuple RI_FKey_cascade_upd(FmgrInfo *proinfo);
|
extern Datum RI_FKey_cascade_upd(PG_FUNCTION_ARGS);
|
||||||
extern HeapTuple RI_FKey_restrict_del(FmgrInfo *proinfo);
|
extern Datum RI_FKey_restrict_del(PG_FUNCTION_ARGS);
|
||||||
extern HeapTuple RI_FKey_restrict_upd(FmgrInfo *proinfo);
|
extern Datum RI_FKey_restrict_upd(PG_FUNCTION_ARGS);
|
||||||
extern HeapTuple RI_FKey_setnull_del(FmgrInfo *proinfo);
|
extern Datum RI_FKey_setnull_del(PG_FUNCTION_ARGS);
|
||||||
extern HeapTuple RI_FKey_setnull_upd(FmgrInfo *proinfo);
|
extern Datum RI_FKey_setnull_upd(PG_FUNCTION_ARGS);
|
||||||
extern HeapTuple RI_FKey_setdefault_del(FmgrInfo *proinfo);
|
extern Datum RI_FKey_setdefault_del(PG_FUNCTION_ARGS);
|
||||||
extern HeapTuple RI_FKey_setdefault_upd(FmgrInfo *proinfo);
|
extern Datum RI_FKey_setdefault_upd(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
#endif /* BUILTINS_H */
|
#endif /* BUILTINS_H */
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
* ENHANCEMENTS, OR MODIFICATIONS.
|
* ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.7 2000/05/28 17:56:26 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.8 2000/05/29 01:59:13 tgl Exp $
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
|
@ -283,18 +283,18 @@ plperl_call_handler(PG_FUNCTION_ARGS)
|
||||||
* Determine if called as function or trigger and
|
* Determine if called as function or trigger and
|
||||||
* call appropriate subhandler
|
* call appropriate subhandler
|
||||||
************************************************************/
|
************************************************************/
|
||||||
if (CurrentTriggerData == NULL)
|
if (CALLED_AS_TRIGGER(fcinfo))
|
||||||
retval = plperl_func_handler(fcinfo);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
elog(ERROR, "plperl: can't use perl in triggers yet.");
|
elog(ERROR, "plperl: can't use perl in triggers yet.");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* retval = (Datum) plperl_trigger_handler(fcinfo);
|
* retval = PointerGetDatum(plperl_trigger_handler(fcinfo));
|
||||||
*/
|
*/
|
||||||
/* make the compiler happy */
|
/* make the compiler happy */
|
||||||
retval = (Datum) 0;
|
retval = (Datum) 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
retval = plperl_func_handler(fcinfo);
|
||||||
|
|
||||||
plperl_call_level--;
|
plperl_call_level--;
|
||||||
|
|
||||||
|
@ -687,7 +687,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
|
||||||
static HeapTuple
|
static HeapTuple
|
||||||
plperl_trigger_handler(PG_FUNCTION_ARGS)
|
plperl_trigger_handler(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
char internal_proname[512];
|
char internal_proname[512];
|
||||||
char *stroid;
|
char *stroid;
|
||||||
Tcl_HashEntry *hashent;
|
Tcl_HashEntry *hashent;
|
||||||
|
@ -710,12 +710,6 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
sigjmp_buf save_restart;
|
sigjmp_buf save_restart;
|
||||||
|
|
||||||
/************************************************************
|
|
||||||
* Save the current trigger data local
|
|
||||||
************************************************************/
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* Build our internal proc name from the functions Oid
|
* Build our internal proc name from the functions Oid
|
||||||
************************************************************/
|
************************************************************/
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.4 2000/05/28 17:56:28 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.5 2000/05/29 01:59:14 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
|
@ -69,21 +69,10 @@ static PLpgSQL_function *compiled_functions = NULL;
|
||||||
Datum
|
Datum
|
||||||
plpgsql_call_handler(PG_FUNCTION_ARGS)
|
plpgsql_call_handler(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
bool isTrigger = CALLED_AS_TRIGGER(fcinfo);
|
||||||
bool isTrigger;
|
|
||||||
PLpgSQL_function *func;
|
PLpgSQL_function *func;
|
||||||
Datum retval;
|
Datum retval;
|
||||||
|
|
||||||
/* ----------
|
|
||||||
* Save the current trigger data local
|
|
||||||
*
|
|
||||||
* XXX this should go away in favor of using fcinfo->context
|
|
||||||
* ----------
|
|
||||||
*/
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
isTrigger = (trigdata != NULL);
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Connect to SPI manager
|
* Connect to SPI manager
|
||||||
* ----------
|
* ----------
|
||||||
|
@ -136,7 +125,8 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (isTrigger)
|
if (isTrigger)
|
||||||
retval = PointerGetDatum(plpgsql_exec_trigger(func, trigdata));
|
retval = PointerGetDatum(plpgsql_exec_trigger(func,
|
||||||
|
(TriggerData *) fcinfo->context));
|
||||||
else
|
else
|
||||||
retval = plpgsql_exec_function(func, fcinfo);
|
retval = plpgsql_exec_function(func, fcinfo);
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
* ENHANCEMENTS, OR MODIFICATIONS.
|
* ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.23 2000/05/28 17:56:29 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.24 2000/05/29 01:59:15 tgl Exp $
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
|
@ -390,10 +390,10 @@ pltcl_call_handler(PG_FUNCTION_ARGS)
|
||||||
* Determine if called as function or trigger and
|
* Determine if called as function or trigger and
|
||||||
* call appropriate subhandler
|
* call appropriate subhandler
|
||||||
************************************************************/
|
************************************************************/
|
||||||
if (CurrentTriggerData == NULL)
|
if (CALLED_AS_TRIGGER(fcinfo))
|
||||||
retval = pltcl_func_handler(fcinfo);
|
retval = PointerGetDatum(pltcl_trigger_handler(fcinfo));
|
||||||
else
|
else
|
||||||
retval = (Datum) pltcl_trigger_handler(fcinfo);
|
retval = pltcl_func_handler(fcinfo);
|
||||||
|
|
||||||
pltcl_call_level--;
|
pltcl_call_level--;
|
||||||
|
|
||||||
|
@ -734,7 +734,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
|
||||||
static HeapTuple
|
static HeapTuple
|
||||||
pltcl_trigger_handler(PG_FUNCTION_ARGS)
|
pltcl_trigger_handler(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
char internal_proname[512];
|
char internal_proname[512];
|
||||||
char *stroid;
|
char *stroid;
|
||||||
Tcl_HashEntry *hashent;
|
Tcl_HashEntry *hashent;
|
||||||
|
@ -757,12 +757,6 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
sigjmp_buf save_restart;
|
sigjmp_buf save_restart;
|
||||||
|
|
||||||
/************************************************************
|
|
||||||
* Save the current trigger data local
|
|
||||||
************************************************************/
|
|
||||||
trigdata = CurrentTriggerData;
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* Build our internal proc name from the functions Oid
|
* Build our internal proc name from the functions Oid
|
||||||
************************************************************/
|
************************************************************/
|
||||||
|
|
|
@ -15,27 +15,27 @@ CREATE FUNCTION widget_out(opaque)
|
||||||
CREATE FUNCTION check_primary_key ()
|
CREATE FUNCTION check_primary_key ()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/../../../contrib/spi/refint_DLSUFFIX_'
|
AS '_OBJWD_/../../../contrib/spi/refint_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
|
|
||||||
CREATE FUNCTION check_foreign_key ()
|
CREATE FUNCTION check_foreign_key ()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/../../../contrib/spi/refint_DLSUFFIX_'
|
AS '_OBJWD_/../../../contrib/spi/refint_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
|
|
||||||
CREATE FUNCTION autoinc ()
|
CREATE FUNCTION autoinc ()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/../../../contrib/spi/autoinc_DLSUFFIX_'
|
AS '_OBJWD_/../../../contrib/spi/autoinc_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
|
|
||||||
CREATE FUNCTION funny_dup17 ()
|
CREATE FUNCTION funny_dup17 ()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/regress_DLSUFFIX_'
|
AS '_OBJWD_/regress_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
|
|
||||||
CREATE FUNCTION ttdummy ()
|
CREATE FUNCTION ttdummy ()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/regress_DLSUFFIX_'
|
AS '_OBJWD_/regress_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
|
|
||||||
CREATE FUNCTION set_ttdummy (int4)
|
CREATE FUNCTION set_ttdummy (int4)
|
||||||
RETURNS int4
|
RETURNS int4
|
||||||
|
|
|
@ -13,23 +13,23 @@ CREATE FUNCTION widget_out(opaque)
|
||||||
CREATE FUNCTION check_primary_key ()
|
CREATE FUNCTION check_primary_key ()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/../../../contrib/spi/refint_DLSUFFIX_'
|
AS '_OBJWD_/../../../contrib/spi/refint_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
CREATE FUNCTION check_foreign_key ()
|
CREATE FUNCTION check_foreign_key ()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/../../../contrib/spi/refint_DLSUFFIX_'
|
AS '_OBJWD_/../../../contrib/spi/refint_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
CREATE FUNCTION autoinc ()
|
CREATE FUNCTION autoinc ()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/../../../contrib/spi/autoinc_DLSUFFIX_'
|
AS '_OBJWD_/../../../contrib/spi/autoinc_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
CREATE FUNCTION funny_dup17 ()
|
CREATE FUNCTION funny_dup17 ()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/regress_DLSUFFIX_'
|
AS '_OBJWD_/regress_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
CREATE FUNCTION ttdummy ()
|
CREATE FUNCTION ttdummy ()
|
||||||
RETURNS opaque
|
RETURNS opaque
|
||||||
AS '_OBJWD_/regress_DLSUFFIX_'
|
AS '_OBJWD_/regress_DLSUFFIX_'
|
||||||
LANGUAGE 'c';
|
LANGUAGE 'newC';
|
||||||
CREATE FUNCTION set_ttdummy (int4)
|
CREATE FUNCTION set_ttdummy (int4)
|
||||||
RETURNS int4
|
RETURNS int4
|
||||||
AS '_OBJWD_/regress_DLSUFFIX_'
|
AS '_OBJWD_/regress_DLSUFFIX_'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.36 2000/04/12 17:17:21 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.37 2000/05/29 01:59:15 tgl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <float.h> /* faked on sunos */
|
#include <float.h> /* faked on sunos */
|
||||||
|
@ -306,11 +306,12 @@ static int fd17b_level = 0;
|
||||||
static int fd17a_level = 0;
|
static int fd17a_level = 0;
|
||||||
static bool fd17b_recursion = true;
|
static bool fd17b_recursion = true;
|
||||||
static bool fd17a_recursion = true;
|
static bool fd17a_recursion = true;
|
||||||
HeapTuple funny_dup17(void);
|
extern Datum funny_dup17(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
HeapTuple /* have to return HeapTuple to Executor */
|
Datum
|
||||||
funny_dup17()
|
funny_dup17(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
TransactionId *xid;
|
TransactionId *xid;
|
||||||
int *level;
|
int *level;
|
||||||
bool *recursion;
|
bool *recursion;
|
||||||
|
@ -325,10 +326,13 @@ funny_dup17()
|
||||||
int selected = 0;
|
int selected = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
tuple = CurrentTriggerData->tg_trigtuple;
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
rel = CurrentTriggerData->tg_relation;
|
elog(ERROR, "funny_dup17: not fired by trigger manager");
|
||||||
|
|
||||||
|
tuple = trigdata->tg_trigtuple;
|
||||||
|
rel = trigdata->tg_relation;
|
||||||
tupdesc = rel->rd_att;
|
tupdesc = rel->rd_att;
|
||||||
if (TRIGGER_FIRED_BEFORE(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
|
||||||
{
|
{
|
||||||
xid = &fd17b_xid;
|
xid = &fd17b_xid;
|
||||||
level = &fd17b_level;
|
level = &fd17b_level;
|
||||||
|
@ -343,8 +347,6 @@ funny_dup17()
|
||||||
when = "AFTER ";
|
when = "AFTER ";
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
|
|
||||||
if (!TransactionIdIsCurrentTransactionId(*xid))
|
if (!TransactionIdIsCurrentTransactionId(*xid))
|
||||||
{
|
{
|
||||||
*xid = GetCurrentTransactionId();
|
*xid = GetCurrentTransactionId();
|
||||||
|
@ -355,11 +357,11 @@ funny_dup17()
|
||||||
if (*level == 17)
|
if (*level == 17)
|
||||||
{
|
{
|
||||||
*recursion = false;
|
*recursion = false;
|
||||||
return tuple;
|
return PointerGetDatum(tuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(*recursion))
|
if (!(*recursion))
|
||||||
return tuple;
|
return PointerGetDatum(tuple);
|
||||||
|
|
||||||
(*level)++;
|
(*level)++;
|
||||||
|
|
||||||
|
@ -412,10 +414,10 @@ funny_dup17()
|
||||||
if (*level == 0)
|
if (*level == 0)
|
||||||
*xid = InvalidTransactionId;
|
*xid = InvalidTransactionId;
|
||||||
|
|
||||||
return tuple;
|
return PointerGetDatum(tuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
HeapTuple ttdummy(void);
|
extern Datum ttdummy(PG_FUNCTION_ARGS);
|
||||||
int32 set_ttdummy(int32 on);
|
int32 set_ttdummy(int32 on);
|
||||||
|
|
||||||
extern int4 nextval(struct varlena * seqin);
|
extern int4 nextval(struct varlena * seqin);
|
||||||
|
@ -425,9 +427,10 @@ extern int4 nextval(struct varlena * seqin);
|
||||||
static void *splan = NULL;
|
static void *splan = NULL;
|
||||||
static bool ttoff = false;
|
static bool ttoff = false;
|
||||||
|
|
||||||
HeapTuple
|
Datum
|
||||||
ttdummy()
|
ttdummy(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
Trigger *trigger; /* to get trigger name */
|
Trigger *trigger; /* to get trigger name */
|
||||||
char **args; /* arguments */
|
char **args; /* arguments */
|
||||||
int attnum[2]; /* fnumbers of start/stop columns */
|
int attnum[2]; /* fnumbers of start/stop columns */
|
||||||
|
@ -448,30 +451,30 @@ ttdummy()
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!CurrentTriggerData)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
elog(ERROR, "ttdummy: triggers are not initialized");
|
elog(ERROR, "ttdummy: not fired by trigger manager");
|
||||||
if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
|
||||||
elog(ERROR, "ttdummy: can't process STATEMENT events");
|
elog(ERROR, "ttdummy: can't process STATEMENT events");
|
||||||
if (TRIGGER_FIRED_AFTER(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
|
||||||
elog(ERROR, "ttdummy: must be fired before event");
|
elog(ERROR, "ttdummy: must be fired before event");
|
||||||
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
|
||||||
elog(ERROR, "ttdummy: can't process INSERT event");
|
elog(ERROR, "ttdummy: can't process INSERT event");
|
||||||
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||||
newtuple = CurrentTriggerData->tg_newtuple;
|
newtuple = trigdata->tg_newtuple;
|
||||||
|
|
||||||
trigtuple = CurrentTriggerData->tg_trigtuple;
|
trigtuple = trigdata->tg_trigtuple;
|
||||||
|
|
||||||
rel = CurrentTriggerData->tg_relation;
|
rel = trigdata->tg_relation;
|
||||||
relname = SPI_getrelname(rel);
|
relname = SPI_getrelname(rel);
|
||||||
|
|
||||||
/* check if TT is OFF for this relation */
|
/* check if TT is OFF for this relation */
|
||||||
if (ttoff) /* OFF - nothing to do */
|
if (ttoff) /* OFF - nothing to do */
|
||||||
{
|
{
|
||||||
pfree(relname);
|
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)
|
if (trigger->tgnargs != 2)
|
||||||
elog(ERROR, "ttdummy (%s): invalid (!= 2) number of arguments %d",
|
elog(ERROR, "ttdummy (%s): invalid (!= 2) number of arguments %d",
|
||||||
|
@ -481,8 +484,6 @@ ttdummy()
|
||||||
tupdesc = rel->rd_att;
|
tupdesc = rel->rd_att;
|
||||||
natts = tupdesc->natts;
|
natts = tupdesc->natts;
|
||||||
|
|
||||||
CurrentTriggerData = NULL;
|
|
||||||
|
|
||||||
for (i = 0; i < 2; i++)
|
for (i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
attnum[i] = SPI_fnumber(tupdesc, args[i]);
|
attnum[i] = SPI_fnumber(tupdesc, args[i]);
|
||||||
|
@ -517,13 +518,13 @@ ttdummy()
|
||||||
if (newoff != TTDUMMY_INFINITY)
|
if (newoff != TTDUMMY_INFINITY)
|
||||||
{
|
{
|
||||||
pfree(relname); /* allocated in upper executor context */
|
pfree(relname); /* allocated in upper executor context */
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (oldoff != TTDUMMY_INFINITY) /* DELETE */
|
else if (oldoff != TTDUMMY_INFINITY) /* DELETE */
|
||||||
{
|
{
|
||||||
pfree(relname);
|
pfree(relname);
|
||||||
return NULL;
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -618,7 +619,7 @@ ttdummy()
|
||||||
|
|
||||||
pfree(relname);
|
pfree(relname);
|
||||||
|
|
||||||
return rettuple;
|
return PointerGetDatum(rettuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32
|
int32
|
||||||
|
|
Loading…
Reference in New Issue