Clean up some minor problems exposed by further thought about Panon's bug

report on old-style functions invoked by RI triggers.  We had a number of
other places that were being sloppy about which memory context FmgrInfo
subsidiary data will be allocated in.  Turns out none of them actually
cause a problem in 7.1, but this is for arcane reasons such as the fact
that old-style triggers aren't supported anyway.  To avoid getting burnt
later, I've restructured the trigger support so that we don't keep trigger
FmgrInfo structs in relcache memory.  Some other related cleanups too:
it's not really necessary to call fmgr_info at all while setting up
the index support info in relcache entries, because those ScanKeyEntry
structs are never used to invoke the functions.  This should speed up
relcache initialization a tiny bit.
This commit is contained in:
Tom Lane 2001-06-01 02:41:36 +00:00
parent a1d9d096f0
commit 0b370ea7c8
16 changed files with 448 additions and 298 deletions

View File

@ -366,7 +366,6 @@ typedef struct Trigger
Oid tgoid;
char *tgname;
Oid tgfoid;
FmgrInfo tgfunc;
int16 tgtype;
bool tgenabled;
bool tgisconstraint;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/scankey.c,v 1.18 2001/01/24 19:42:47 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/access/common/scankey.c,v 1.19 2001/06/01 02:41:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -40,11 +40,13 @@ ScanKeyEntrySetIllegal(ScanKey entry)
entry->sk_flags = 0; /* just in case... */
entry->sk_attno = InvalidAttrNumber;
entry->sk_procedure = 0; /* should be InvalidRegProcedure */
entry->sk_func.fn_oid = InvalidOid;
entry->sk_argument = (Datum) 0;
}
/*
* ScanKeyEntryInitialize
* Initializes an scan key entry.
* Initializes a scan key entry.
*
* Note:
* Assumes the scan key entry is valid.
@ -64,7 +66,6 @@ ScanKeyEntryInitialize(ScanKey entry,
entry->sk_procedure = procedure;
entry->sk_argument = argument;
fmgr_info(procedure, &entry->sk_func);
entry->sk_nargs = entry->sk_func.fn_nargs;
Assert(ScanKeyEntryIsLegal(entry));
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.49 2001/05/31 18:16:54 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.50 2001/06/01 02:41:35 tgl Exp $
*
* INTERFACE ROUTINES
* index_open - open an index relation by relationId
@ -232,7 +232,7 @@ index_beginscan(Relation relation,
uint16 numberOfKeys,
ScanKey key)
{
IndexScanDesc scandesc;
IndexScanDesc scan;
RegProcedure procedure;
RELATION_CHECKS;
@ -249,14 +249,22 @@ index_beginscan(Relation relation,
*/
LockRelation(relation, AccessShareLock);
scandesc = (IndexScanDesc)
scan = (IndexScanDesc)
DatumGetPointer(OidFunctionCall4(procedure,
PointerGetDatum(relation),
BoolGetDatum(scanFromEnd),
UInt16GetDatum(numberOfKeys),
PointerGetDatum(key)));
return scandesc;
/*
* We want to look up the amgettuple procedure just once per scan,
* not once per index_getnext call. So do it here and save
* the fmgr info result in the scan descriptor.
*/
GET_SCAN_PROCEDURE(beginscan, amgettuple);
fmgr_info(procedure, &scan->fn_getnext);
return scan;
}
/* ----------------
@ -345,19 +353,9 @@ index_getnext(IndexScanDesc scan,
SCAN_CHECKS;
/*
* Look up the access procedure only once per scan.
*/
if (scan->fn_getnext.fn_oid == InvalidOid)
{
RegProcedure procedure;
GET_SCAN_PROCEDURE(getnext, amgettuple);
fmgr_info(procedure, &scan->fn_getnext);
}
/*
* have the am's gettuple proc do all the work.
* index_beginscan already set up fn_getnext.
*/
result = (RetrieveIndexResult)
DatumGetPointer(FunctionCall2(&scan->fn_getnext,

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.50 2001/05/30 19:53:40 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.51 2001/06/01 02:41:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -458,6 +458,8 @@ RelationInvokeStrategy(Relation relation,
/* ----------------
* OperatorRelationFillScanKeyEntry
*
* Initialize a ScanKey entry given already-opened pg_operator relation.
* ----------------
*/
static void
@ -498,6 +500,7 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation,
operatorObjectId);
}
MemSet(entry, 0, sizeof(*entry));
entry->sk_flags = 0;
entry->sk_procedure = ((Form_pg_operator) GETSTRUCT(tuple))->oprcode;
@ -511,14 +514,29 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation,
"OperatorRelationFillScanKeyEntry: no procedure for operator %u",
operatorObjectId);
fmgr_info(entry->sk_procedure, &entry->sk_func);
entry->sk_nargs = entry->sk_func.fn_nargs;
/*
* Formerly we initialized entry->sk_func here, but that's a waste of
* time because ScanKey entries in strategy maps are never actually
* used to invoke the operator. Furthermore, to do that we'd have to
* worry about setting the proper memory context (the map is probably
* not allocated in the current memory context!)
*/
}
/*
* IndexSupportInitialize
* Initializes an index strategy and associated support procedures.
*
* Data is returned into *indexStrategy, *indexSupport, and *isUnique,
* all of which are objects allocated by the caller.
*
* The primary input keys are indexObjectId and accessMethodObjectId.
* The caller also passes maxStrategyNumber, maxSupportNumber, and
* maxAttributeNumber, since these indicate the size of the indexStrategy
* and indexSupport arrays it has allocated --- but in practice these
* numbers must always match those obtainable from the system catalog
* entries for the index and access method.
*/
void
IndexSupportInitialize(IndexStrategy indexStrategy,
@ -578,7 +596,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
if (!OidIsValid(iform->indkey[attIndex]))
{
if (attIndex == InvalidAttrNumber)
elog(ERROR, "IndexSupportInitialize: no pg_index tuple");
elog(ERROR, "IndexSupportInitialize: bogus pg_index tuple");
break;
}
@ -637,6 +655,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
heap_close(relation, AccessShareLock);
}
/* Now load the strategy information for the index operators */
ScanKeyEntryInitialize(&entry[0], 0,
Anum_pg_amop_amopid,
F_OIDEQ,
@ -644,7 +663,8 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
ScanKeyEntryInitialize(&entry[1], 0,
Anum_pg_amop_amopclaid,
F_OIDEQ, 0);
F_OIDEQ,
0); /* will fill below */
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
operatorRelation = heap_openr(OperatorRelationName, AccessShareLock);
@ -670,9 +690,11 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
Form_pg_amop aform;
aform = (Form_pg_amop) GETSTRUCT(tuple);
strategy = aform->amopstrategy;
Assert(strategy > 0 && strategy <= maxStrategyNumber);
OperatorRelationFillScanKeyEntry(operatorRelation,
aform->amopopr,
StrategyMapGetScanKeyEntry(map, aform->amopstrategy));
StrategyMapGetScanKeyEntry(map, strategy));
}
heap_endscan(scan);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.152 2001/05/30 20:52:32 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.153 2001/06/01 02:41:35 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -722,6 +722,9 @@ UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
/* ----------------------------------------------------------------
* InitIndexStrategy
*
* XXX this is essentially the same as relcache.c's
* IndexedAccessMethodInitialize(), and probably ought to be merged with it.
* ----------------------------------------------------------------
*/
void
@ -733,18 +736,16 @@ InitIndexStrategy(int numatts,
RegProcedure *support;
uint16 amstrategies;
uint16 amsupport;
Oid attrelid;
Size strsize;
/*
* get information from the index relation descriptor
*/
attrelid = indexRelation->rd_att->attrs[0]->attrelid;
amstrategies = indexRelation->rd_am->amstrategies;
amsupport = indexRelation->rd_am->amsupport;
/*
* get the size of the strategy
* compute the size of the strategy array
*/
strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
@ -779,7 +780,8 @@ InitIndexStrategy(int numatts,
IndexSupportInitialize(strategy, support,
&indexRelation->rd_uniqueindex,
attrelid, accessMethodObjectId,
RelationGetRelid(indexRelation),
accessMethodObjectId,
amstrategies, amsupport, numatts);
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.58 2001/05/20 20:28:17 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.59 2001/06/01 02:41:35 tgl Exp $
*
* NOTES
* these routines moved here from commands/define.c and somewhat cleaned up.
@ -71,12 +71,13 @@ static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
*
* performs a scan on pg_operator for an operator tuple
* with given name and left/right type oids.
* ----------------------------------------------------------------
*
* pg_operator_desc -- reldesc for pg_operator
* operatorName -- name of operator to fetch
* leftObjectId -- left data type oid of operator to fetch
* rightObjectId -- right data type oid of operator to fetch
* defined -- set TRUE if defined (not a shell)
* ----------------------------------------------------------------
*/
static Oid
OperatorGetWithOpenRelation(Relation pg_operator_desc,
@ -88,26 +89,23 @@ OperatorGetWithOpenRelation(Relation pg_operator_desc,
HeapScanDesc pg_operator_scan;
Oid operatorObjectId;
HeapTuple tup;
static ScanKeyData opKey[3] = {
{0, Anum_pg_operator_oprname, F_NAMEEQ},
{0, Anum_pg_operator_oprleft, F_OIDEQ},
{0, Anum_pg_operator_oprright, F_OIDEQ},
};
fmgr_info(F_NAMEEQ, &opKey[0].sk_func);
fmgr_info(F_OIDEQ, &opKey[1].sk_func);
fmgr_info(F_OIDEQ, &opKey[2].sk_func);
opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs;
opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs;
ScanKeyData opKey[3];
/*
* form scan key
*/
opKey[0].sk_argument = PointerGetDatum(operatorName);
opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
ScanKeyEntryInitialize(&opKey[0], 0x0,
Anum_pg_operator_oprname,
F_NAMEEQ,
PointerGetDatum(operatorName));
ScanKeyEntryInitialize(&opKey[1], 0x0,
Anum_pg_operator_oprleft,
F_OIDEQ,
ObjectIdGetDatum(leftObjectId));
ScanKeyEntryInitialize(&opKey[2], 0x0,
Anum_pg_operator_oprright,
F_OIDEQ,
ObjectIdGetDatum(rightObjectId));
/*
* begin the scan
@ -451,7 +449,6 @@ OperatorDef(char *operatorName,
int i,
j;
Relation pg_operator_desc;
HeapScanDesc pg_operator_scan;
HeapTuple tup;
char nulls[Natts_pg_operator];
@ -471,19 +468,7 @@ OperatorDef(char *operatorName,
int nargs;
NameData oname;
TupleDesc tupDesc;
static ScanKeyData opKey[3] = {
{0, Anum_pg_operator_oprname, F_NAMEEQ},
{0, Anum_pg_operator_oprleft, F_OIDEQ},
{0, Anum_pg_operator_oprright, F_OIDEQ},
};
fmgr_info(F_NAMEEQ, &opKey[0].sk_func);
fmgr_info(F_OIDEQ, &opKey[1].sk_func);
fmgr_info(F_OIDEQ, &opKey[2].sk_func);
opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs;
opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs;
ScanKeyData opKey[3];
operatorObjectId = OperatorGet(operatorName,
leftTypeName,
@ -753,13 +738,22 @@ OperatorDef(char *operatorName,
*/
if (operatorObjectId)
{
opKey[0].sk_argument = PointerGetDatum(operatorName);
opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId);
opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId);
/* Make sure we can see the shell even if it is new in current cmd */
CommandCounterIncrement();
ScanKeyEntryInitialize(&opKey[0], 0x0,
Anum_pg_operator_oprname,
F_NAMEEQ,
PointerGetDatum(operatorName));
ScanKeyEntryInitialize(&opKey[1], 0x0,
Anum_pg_operator_oprleft,
F_OIDEQ,
ObjectIdGetDatum(leftTypeId));
ScanKeyEntryInitialize(&opKey[2], 0x0,
Anum_pg_operator_oprright,
F_OIDEQ,
ObjectIdGetDatum(rightTypeId));
pg_operator_scan = heap_beginscan(pg_operator_desc,
0,
SnapshotSelf, /* no cache? */
@ -789,7 +783,6 @@ OperatorDef(char *operatorName,
heap_insert(pg_operator_desc, tup);
operatorObjectId = tup->t_data->t_oid;
}
if (RelationGetForm(pg_operator_desc)->relhasindex)
@ -841,17 +834,11 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
char nulls[Natts_pg_operator];
char replaces[Natts_pg_operator];
Datum values[Natts_pg_operator];
static ScanKeyData opKey[1] = {
{0, ObjectIdAttributeNumber, F_OIDEQ},
};
fmgr_info(F_OIDEQ, &opKey[0].sk_func);
opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
ScanKeyData opKey[1];
for (i = 0; i < Natts_pg_operator; ++i)
{
values[i] = (Datum) NULL;
values[i] = (Datum) 0;
replaces[i] = ' ';
nulls[i] = ' ';
}
@ -865,7 +852,10 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
*/
CommandCounterIncrement();
opKey[0].sk_argument = ObjectIdGetDatum(commId);
ScanKeyEntryInitialize(&opKey[0], 0x0,
ObjectIdAttributeNumber,
F_OIDEQ,
ObjectIdGetDatum(commId));
pg_operator_scan = heap_beginscan(pg_operator_desc,
0,
@ -993,7 +983,6 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
heap_endscan(pg_operator_scan);
heap_close(pg_operator_desc, RowExclusiveLock);
}

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.137 2001/05/27 09:59:29 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.138 2001/06/01 02:41:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -636,6 +636,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
resultRelInfo = makeNode(ResultRelInfo);
resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
resultRelInfo->ri_RelationDesc = rel;
resultRelInfo->ri_TrigDesc = rel->trigdesc;
ExecOpenIndices(resultRelInfo);
@ -868,12 +869,12 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
skip_tuple = false;
/* BEFORE ROW INSERT Triggers */
if (rel->trigdesc &&
rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
if (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
{
HeapTuple newtuple;
newtuple = ExecBRInsertTriggers(estate, rel, tuple);
newtuple = ExecBRInsertTriggers(estate, resultRelInfo, tuple);
if (newtuple == NULL) /* "do nothing" */
skip_tuple = true;
@ -903,8 +904,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
/* AFTER ROW INSERT Triggers */
if (rel->trigdesc)
ExecARInsertTriggers(estate, rel, tuple);
if (resultRelInfo->ri_TrigDesc)
ExecARInsertTriggers(estate, resultRelInfo, tuple);
}
for (i = 0; i < attr_count; i++)

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.91 2001/05/27 09:59:29 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.92 2001/06/01 02:41:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -32,14 +32,19 @@
#include "utils/syscache.h"
static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid,
TupleTableSlot **newSlot);
static HeapTuple ExecCallTriggerFunc(Trigger *trigger,
TriggerData *trigdata,
MemoryContext per_tuple_context);
static void DeferredTriggerSaveEvent(Relation rel, int event,
HeapTuple oldtup, HeapTuple newtup);
static void InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx);
static HeapTuple GetTupleForTrigger(EState *estate,
ResultRelInfo *relinfo,
ItemPointer tid,
TupleTableSlot **newSlot);
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
FmgrInfo *finfo,
MemoryContext per_tuple_context);
static void DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
HeapTuple oldtup, HeapTuple newtup);
static void DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
Relation rel, FmgrInfo *finfo,
MemoryContext per_tuple_context);
void
@ -577,8 +582,6 @@ RelationBuildTriggers(Relation relation)
DatumGetCString(DirectFunctionCall1(nameout,
NameGetDatum(&pg_trigger->tgname))));
build->tgfoid = pg_trigger->tgfoid;
build->tgfunc.fn_oid = InvalidOid; /* mark FmgrInfo as
* uninitialized */
build->tgtype = pg_trigger->tgtype;
build->tgenabled = pg_trigger->tgenabled;
build->tgisconstraint = pg_trigger->tgisconstraint;
@ -641,21 +644,22 @@ RelationBuildTriggers(Relation relation)
trigdesc->triggers = triggers;
trigdesc->numtriggers = ntrigs;
for (found = 0; found < ntrigs; found++)
DescribeTrigger(trigdesc, &(triggers[found]));
InsertTrigger(trigdesc, &(triggers[found]), found);
relation->trigdesc = trigdesc;
}
/* Insert the given trigger into the appropriate index list(s) for it */
static void
DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
{
uint16 *n;
Trigger ***t,
***tp;
int **t,
**tp;
if (TRIGGER_FOR_ROW(trigger->tgtype)) /* Is ROW/STATEMENT
* trigger */
if (TRIGGER_FOR_ROW(trigger->tgtype))
{
/* ROW trigger */
if (TRIGGER_FOR_BEFORE(trigger->tgtype))
{
n = trigdesc->n_before_row;
@ -668,8 +672,8 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
}
}
else
/* STATEMENT (NI) */
{
/* STATEMENT trigger */
if (TRIGGER_FOR_BEFORE(trigger->tgtype))
{
n = trigdesc->n_before_statement;
@ -686,12 +690,12 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
{
tp = &(t[TRIGGER_EVENT_INSERT]);
if (*tp == NULL)
*tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
sizeof(Trigger *));
*tp = (int *) MemoryContextAlloc(CacheMemoryContext,
sizeof(int));
else
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
sizeof(Trigger *));
(*tp)[n[TRIGGER_EVENT_INSERT]] = trigger;
*tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
sizeof(int));
(*tp)[n[TRIGGER_EVENT_INSERT]] = indx;
(n[TRIGGER_EVENT_INSERT])++;
}
@ -699,12 +703,12 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
{
tp = &(t[TRIGGER_EVENT_DELETE]);
if (*tp == NULL)
*tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
sizeof(Trigger *));
*tp = (int *) MemoryContextAlloc(CacheMemoryContext,
sizeof(int));
else
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
sizeof(Trigger *));
(*tp)[n[TRIGGER_EVENT_DELETE]] = trigger;
*tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
sizeof(int));
(*tp)[n[TRIGGER_EVENT_DELETE]] = indx;
(n[TRIGGER_EVENT_DELETE])++;
}
@ -712,21 +716,20 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
{
tp = &(t[TRIGGER_EVENT_UPDATE]);
if (*tp == NULL)
*tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
sizeof(Trigger *));
*tp = (int *) MemoryContextAlloc(CacheMemoryContext,
sizeof(int));
else
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
sizeof(Trigger *));
(*tp)[n[TRIGGER_EVENT_UPDATE]] = trigger;
*tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
sizeof(int));
(*tp)[n[TRIGGER_EVENT_UPDATE]] = indx;
(n[TRIGGER_EVENT_UPDATE])++;
}
}
void
FreeTriggerDesc(TriggerDesc *trigdesc)
{
Trigger ***t;
int **t;
Trigger *trigger;
int i;
@ -734,19 +737,19 @@ FreeTriggerDesc(TriggerDesc *trigdesc)
return;
t = trigdesc->tg_before_statement;
for (i = 0; i < 4; i++)
for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
if (t[i] != NULL)
pfree(t[i]);
t = trigdesc->tg_before_row;
for (i = 0; i < 4; i++)
for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
if (t[i] != NULL)
pfree(t[i]);
t = trigdesc->tg_after_row;
for (i = 0; i < 4; i++)
for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
if (t[i] != NULL)
pfree(t[i]);
t = trigdesc->tg_after_statement;
for (i = 0; i < 4; i++)
for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
if (t[i] != NULL)
pfree(t[i]);
@ -806,7 +809,6 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
return false;
if (trig1->tgfoid != trig2->tgfoid)
return false;
/* need not examine tgfunc, if tgfoid matches */
if (trig1->tgtype != trig2->tgtype)
return false;
if (trig1->tgenabled != trig2->tgenabled)
@ -832,9 +834,18 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
return true;
}
/*
* Call a trigger function.
*
* trigdata: trigger descriptor.
* finfo: possibly-cached call info for the function.
* per_tuple_context: memory context to execute the function in.
*
* Returns the tuple (or NULL) as returned by the function.
*/
static HeapTuple
ExecCallTriggerFunc(Trigger *trigger,
TriggerData *trigdata,
ExecCallTriggerFunc(TriggerData *trigdata,
FmgrInfo *finfo,
MemoryContext per_tuple_context)
{
FunctionCallInfoData fcinfo;
@ -842,11 +853,13 @@ ExecCallTriggerFunc(Trigger *trigger,
MemoryContext oldContext;
/*
* Fmgr lookup info is cached in the Trigger structure, so that we
* need not repeat the lookup on every call.
* We cache fmgr lookup info, to avoid making the lookup
* again on each call.
*/
if (trigger->tgfunc.fn_oid == InvalidOid)
fmgr_info(trigger->tgfoid, &trigger->tgfunc);
if (finfo->fn_oid == InvalidOid)
fmgr_info(trigdata->tg_trigger->tgfoid, finfo);
Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid);
/*
* Do the function evaluation in the per-tuple memory context, so that
@ -861,7 +874,7 @@ ExecCallTriggerFunc(Trigger *trigger,
*/
MemSet(&fcinfo, 0, sizeof(fcinfo));
fcinfo.flinfo = &trigger->tgfunc;
fcinfo.flinfo = finfo;
fcinfo.context = (Node *) trigdata;
result = FunctionCallInvoke(&fcinfo);
@ -880,26 +893,40 @@ ExecCallTriggerFunc(Trigger *trigger,
}
HeapTuple
ExecBRInsertTriggers(EState *estate, Relation rel, HeapTuple trigtuple)
ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
HeapTuple trigtuple)
{
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
HeapTuple newtuple = trigtuple;
HeapTuple oldtuple;
TriggerData LocTriggerData;
int i;
/* Allocate cache space for fmgr lookup info, if not done yet */
if (relinfo->ri_TrigFunctions == NULL)
{
relinfo->ri_TrigFunctions = (FmgrInfo *)
palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
MemSet(relinfo->ri_TrigFunctions, 0,
trigdesc->numtriggers * sizeof(FmgrInfo));
}
LocTriggerData.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
LocTriggerData.tg_relation = rel;
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_newtuple = NULL;
for (i = 0; i < ntrigs; i++)
{
if (!trigger[i]->tgenabled)
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
if (!trigger->tgenabled)
continue;
LocTriggerData.tg_trigtuple = oldtuple = newtuple;
LocTriggerData.tg_trigger = trigger[i];
newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData,
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
relinfo->ri_TrigFunctions + tgindx[i],
GetPerTupleMemoryContext(estate));
if (oldtuple != newtuple && oldtuple != trigtuple)
heap_freetuple(oldtuple);
@ -910,42 +937,59 @@ ExecBRInsertTriggers(EState *estate, Relation rel, HeapTuple trigtuple)
}
void
ExecARInsertTriggers(EState *estate, Relation rel, HeapTuple trigtuple)
ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
HeapTuple trigtuple)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
/* Must save info if there are any deferred triggers on this rel */
if (rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0 ||
rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
DeferredTriggerSaveEvent(rel, TRIGGER_EVENT_INSERT, NULL, trigtuple);
if (trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0 ||
trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_INSERT,
NULL, trigtuple);
}
bool
ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
ItemPointer tupleid)
{
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
TriggerData LocTriggerData;
HeapTuple trigtuple;
HeapTuple newtuple = NULL;
TupleTableSlot *newSlot;
int i;
trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
if (trigtuple == NULL)
return false;
/* Allocate cache space for fmgr lookup info, if not done yet */
if (relinfo->ri_TrigFunctions == NULL)
{
relinfo->ri_TrigFunctions = (FmgrInfo *)
palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
MemSet(relinfo->ri_TrigFunctions, 0,
trigdesc->numtriggers * sizeof(FmgrInfo));
}
LocTriggerData.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
LocTriggerData.tg_relation = rel;
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_newtuple = NULL;
for (i = 0; i < ntrigs; i++)
{
if (!trigger[i]->tgenabled)
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
if (!trigger->tgenabled)
continue;
LocTriggerData.tg_trigtuple = trigtuple;
LocTriggerData.tg_trigger = trigger[i];
newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData,
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
relinfo->ri_TrigFunctions + tgindx[i],
GetPerTupleMemoryContext(estate));
if (newtuple == NULL)
break;
@ -958,27 +1002,31 @@ ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
}
void
ExecARDeleteTriggers(EState *estate, ItemPointer tupleid)
ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
ItemPointer tupleid)
{
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
/* Must save info if there are upd/del deferred triggers on this rel */
if (rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
if (trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
{
HeapTuple trigtuple = GetTupleForTrigger(estate, tupleid, NULL);
HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
tupleid, NULL);
DeferredTriggerSaveEvent(rel, TRIGGER_EVENT_DELETE, trigtuple, NULL);
DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE,
trigtuple, NULL);
heap_freetuple(trigtuple);
}
}
HeapTuple
ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
ItemPointer tupleid, HeapTuple newtuple)
{
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
TriggerData LocTriggerData;
HeapTuple trigtuple;
HeapTuple oldtuple;
@ -986,7 +1034,7 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
TupleTableSlot *newSlot;
int i;
trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
if (trigtuple == NULL)
return NULL;
@ -997,17 +1045,29 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
if (newSlot != NULL)
intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
/* Allocate cache space for fmgr lookup info, if not done yet */
if (relinfo->ri_TrigFunctions == NULL)
{
relinfo->ri_TrigFunctions = (FmgrInfo *)
palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
MemSet(relinfo->ri_TrigFunctions, 0,
trigdesc->numtriggers * sizeof(FmgrInfo));
}
LocTriggerData.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
LocTriggerData.tg_relation = rel;
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
for (i = 0; i < ntrigs; i++)
{
if (!trigger[i]->tgenabled)
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
if (!trigger->tgenabled)
continue;
LocTriggerData.tg_trigtuple = trigtuple;
LocTriggerData.tg_newtuple = oldtuple = newtuple;
LocTriggerData.tg_trigger = trigger[i];
newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData,
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
relinfo->ri_TrigFunctions + tgindx[i],
GetPerTupleMemoryContext(estate));
if (oldtuple != newtuple && oldtuple != intuple)
heap_freetuple(oldtuple);
@ -1019,26 +1079,30 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
}
void
ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
ItemPointer tupleid, HeapTuple newtuple)
{
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
/* Must save info if there are upd/del deferred triggers on this rel */
if (rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
if (trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
{
HeapTuple trigtuple = GetTupleForTrigger(estate, tupleid, NULL);
HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
tupleid, NULL);
DeferredTriggerSaveEvent(rel, TRIGGER_EVENT_UPDATE, trigtuple, newtuple);
DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE,
trigtuple, newtuple);
heap_freetuple(trigtuple);
}
}
static HeapTuple
GetTupleForTrigger(EState *estate, ItemPointer tid, TupleTableSlot **newSlot)
GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo,
ItemPointer tid, TupleTableSlot **newSlot)
{
Relation relation = estate->es_result_relation_info->ri_RelationDesc;
Relation relation = relinfo->ri_RelationDesc;
HeapTupleData tuple;
HeapTuple result;
Buffer buffer;
@ -1070,8 +1134,8 @@ ltrmark:;
else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
{
TupleTableSlot *epqslot = EvalPlanQual(estate,
estate->es_result_relation_info->ri_RangeTableIndex,
&(tuple.t_self));
relinfo->ri_RangeTableIndex,
&(tuple.t_self));
if (!(TupIsNull(epqslot)))
{
@ -1293,35 +1357,46 @@ deferredTriggerGetPreviousEvent(Oid relid, ItemPointer ctid)
/* ----------
* deferredTriggerExecute()
* DeferredTriggerExecute()
*
* Fetch the required tuples back from the heap and fire one
* single trigger function.
*
* Frequently, this will be fired many times in a row for triggers of
* a single relation. Therefore, we cache the open relation and provide
* fmgr lookup cache space at the caller level.
*
* event: event currently being fired.
* itemno: item within event currently being fired.
* rel: open relation for event.
* finfo: array of fmgr lookup cache entries (one per trigger of relation).
* per_tuple_context: memory context to call trigger function in.
* ----------
*/
static void
deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
Relation rel, FmgrInfo *finfo,
MemoryContext per_tuple_context)
{
Relation rel;
Oid tgoid = event->dte_item[itemno].dti_tgoid;
TriggerDesc *trigdesc = rel->trigdesc;
TriggerData LocTriggerData;
HeapTupleData oldtuple;
HeapTupleData newtuple;
HeapTuple rettuple;
Buffer oldbuffer;
Buffer newbuffer;
int tgindx;
/*
* Open the heap and fetch the required OLD and NEW tuples.
* Fetch the required OLD and NEW tuples.
*/
rel = heap_open(event->dte_relid, NoLock);
if (ItemPointerIsValid(&(event->dte_oldctid)))
{
ItemPointerCopy(&(event->dte_oldctid), &(oldtuple.t_self));
heap_fetch(rel, SnapshotAny, &oldtuple, &oldbuffer);
if (!oldtuple.t_data)
elog(ERROR, "deferredTriggerExecute: failed to fetch old tuple");
elog(ERROR, "DeferredTriggerExecute: failed to fetch old tuple");
}
if (ItemPointerIsValid(&(event->dte_newctid)))
@ -1329,7 +1404,7 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
ItemPointerCopy(&(event->dte_newctid), &(newtuple.t_self));
heap_fetch(rel, SnapshotAny, &newtuple, &newbuffer);
if (!newtuple.t_data)
elog(ERROR, "deferredTriggerExecute: failed to fetch new tuple");
elog(ERROR, "DeferredTriggerExecute: failed to fetch new tuple");
}
/*
@ -1340,27 +1415,33 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
TRIGGER_EVENT_ROW;
LocTriggerData.tg_relation = rel;
LocTriggerData.tg_trigger = NULL;
for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
{
if (trigdesc->triggers[tgindx].tgoid == tgoid)
{
LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
break;
}
}
if (LocTriggerData.tg_trigger == NULL)
elog(ERROR, "DeferredTriggerExecute: can't find trigger %u", tgoid);
switch (event->dte_event & TRIGGER_EVENT_OPMASK)
{
case TRIGGER_EVENT_INSERT:
LocTriggerData.tg_trigtuple = &newtuple;
LocTriggerData.tg_newtuple = NULL;
LocTriggerData.tg_trigger =
rel->trigdesc->tg_after_row[TRIGGER_EVENT_INSERT][itemno];
break;
case TRIGGER_EVENT_UPDATE:
LocTriggerData.tg_trigtuple = &oldtuple;
LocTriggerData.tg_newtuple = &newtuple;
LocTriggerData.tg_trigger =
rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE][itemno];
break;
case TRIGGER_EVENT_DELETE:
LocTriggerData.tg_trigtuple = &oldtuple;
LocTriggerData.tg_newtuple = NULL;
LocTriggerData.tg_trigger =
rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE][itemno];
break;
}
@ -1368,8 +1449,8 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
* Call the trigger and throw away an eventually returned updated
* tuple.
*/
rettuple = ExecCallTriggerFunc(LocTriggerData.tg_trigger,
&LocTriggerData,
rettuple = ExecCallTriggerFunc(&LocTriggerData,
finfo + tgindx,
per_tuple_context);
if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple)
heap_freetuple(rettuple);
@ -1381,14 +1462,12 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
ReferentialIntegritySnapshotOverride = false;
/*
* Release buffers and close the relation
* Release buffers
*/
if (ItemPointerIsValid(&(event->dte_oldctid)))
ReleaseBuffer(oldbuffer);
if (ItemPointerIsValid(&(event->dte_newctid)))
ReleaseBuffer(newbuffer);
heap_close(rel, NoLock);
}
@ -1403,9 +1482,9 @@ static void
deferredTriggerInvokeEvents(bool immediate_only)
{
DeferredTriggerEvent event;
int still_deferred_ones;
int i;
MemoryContext per_tuple_context;
Relation rel = NULL;
FmgrInfo *finfo = NULL;
/*
* For now we process all events - to speedup transaction blocks we
@ -1426,6 +1505,8 @@ deferredTriggerInvokeEvents(bool immediate_only)
for (event = deftrig_events; event != NULL; event = event->dte_next)
{
bool still_deferred_ones;
int i;
/*
* Check if event is completely done.
@ -1458,9 +1539,32 @@ deferredTriggerInvokeEvents(bool immediate_only)
}
/*
* So let's fire it...
* So let's fire it... but first, open the correct relation
* if this is not the same relation as before.
*/
deferredTriggerExecute(event, i, per_tuple_context);
if (rel == NULL || rel->rd_id != event->dte_relid)
{
if (rel)
heap_close(rel, NoLock);
if (finfo)
pfree(finfo);
/*
* We assume that an appropriate lock is still held by the
* executor, so grab no new lock here.
*/
rel = heap_open(event->dte_relid, NoLock);
/*
* Allocate space to cache fmgr lookup info for triggers
* of this relation.
*/
finfo = (FmgrInfo *)
palloc(rel->trigdesc->numtriggers * sizeof(FmgrInfo));
MemSet(finfo, 0,
rel->trigdesc->numtriggers * sizeof(FmgrInfo));
}
DeferredTriggerExecute(event, i, rel, finfo, per_tuple_context);
event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
}
@ -1471,6 +1575,10 @@ deferredTriggerInvokeEvents(bool immediate_only)
event->dte_event |= TRIGGER_DEFERRED_DONE;
}
if (rel)
heap_close(rel, NoLock);
if (finfo)
pfree(finfo);
MemoryContextDelete(per_tuple_context);
}
@ -1892,16 +2000,18 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* ----------
*/
static void
DeferredTriggerSaveEvent(Relation rel, int event,
DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
HeapTuple oldtup, HeapTuple newtup)
{
Relation rel = relinfo->ri_RelationDesc;
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
MemoryContext oldcxt;
DeferredTriggerEvent new_event;
DeferredTriggerEvent prev_event;
int new_size;
int i;
int ntriggers;
Trigger **triggers;
int *tgindx;
ItemPointerData oldctid;
ItemPointerData newctid;
TriggerData LocTriggerData;
@ -1927,8 +2037,8 @@ DeferredTriggerSaveEvent(Relation rel, int event,
*/
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
ntriggers = rel->trigdesc->n_after_row[event];
triggers = rel->trigdesc->tg_after_row[event];
ntriggers = trigdesc->n_after_row[event];
tgindx = trigdesc->tg_after_row[event];
new_size = offsetof(DeferredTriggerEventData, dte_item[0]) +
ntriggers * sizeof(DeferredTriggerEventItem);
@ -1941,13 +2051,15 @@ DeferredTriggerSaveEvent(Relation rel, int event,
new_event->dte_n_items = ntriggers;
for (i = 0; i < ntriggers; i++)
{
new_event->dte_item[i].dti_tgoid = triggers[i]->tgoid;
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
new_event->dte_item[i].dti_tgoid = trigger->tgoid;
new_event->dte_item[i].dti_state =
((triggers[i]->tgdeferrable) ?
((trigger->tgdeferrable) ?
TRIGGER_DEFERRED_DEFERRABLE : 0) |
((triggers[i]->tginitdeferred) ?
((trigger->tginitdeferred) ?
TRIGGER_DEFERRED_INITDEFERRED : 0) |
((rel->trigdesc->n_before_row[event] > 0) ?
((trigdesc->n_before_row[event] > 0) ?
TRIGGER_DEFERRED_HAS_BEFORE : 0);
}
@ -1978,13 +2090,14 @@ DeferredTriggerSaveEvent(Relation rel, int event,
*/
for (i = 0; i < ntriggers; i++)
{
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
bool is_ri_trigger;
bool key_unchanged;
/*
* We are interested in RI_FKEY triggers only.
*/
switch (triggers[i]->tgfoid)
switch (trigger->tgfoid)
{
case F_RI_FKEY_NOACTION_UPD:
case F_RI_FKEY_CASCADE_UPD:
@ -2006,7 +2119,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
LocTriggerData.tg_relation = rel;
LocTriggerData.tg_trigtuple = oldtup;
LocTriggerData.tg_newtuple = newtup;
LocTriggerData.tg_trigger = triggers[i];
LocTriggerData.tg_trigger = trigger;
key_unchanged = RI_FKey_keyequal_upd(&LocTriggerData);

View File

@ -27,7 +27,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.142 2001/05/27 20:48:51 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.143 2001/06/01 02:41:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -830,6 +830,8 @@ initResultRelInfo(ResultRelInfo *resultRelInfo,
resultRelInfo->ri_NumIndices = 0;
resultRelInfo->ri_IndexRelationDescs = NULL;
resultRelInfo->ri_IndexRelationInfo = NULL;
resultRelInfo->ri_TrigDesc = resultRelationDesc->trigdesc;
resultRelInfo->ri_TrigFunctions = NULL;
resultRelInfo->ri_ConstraintExprs = NULL;
resultRelInfo->ri_junkFilter = NULL;
@ -1232,12 +1234,12 @@ ExecAppend(TupleTableSlot *slot,
resultRelationDesc = resultRelInfo->ri_RelationDesc;
/* BEFORE ROW INSERT Triggers */
if (resultRelationDesc->trigdesc &&
resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
if (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
{
HeapTuple newtuple;
newtuple = ExecBRInsertTriggers(estate, resultRelationDesc, tuple);
newtuple = ExecBRInsertTriggers(estate, resultRelInfo, tuple);
if (newtuple == NULL) /* "do nothing" */
return;
@ -1283,8 +1285,8 @@ ExecAppend(TupleTableSlot *slot,
ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
/* AFTER ROW INSERT Triggers */
if (resultRelationDesc->trigdesc)
ExecARInsertTriggers(estate, resultRelationDesc, tuple);
if (resultRelInfo->ri_TrigDesc)
ExecARInsertTriggers(estate, resultRelInfo, tuple);
}
/* ----------------------------------------------------------------
@ -1311,12 +1313,12 @@ ExecDelete(TupleTableSlot *slot,
resultRelationDesc = resultRelInfo->ri_RelationDesc;
/* BEFORE ROW DELETE Triggers */
if (resultRelationDesc->trigdesc &&
resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_DELETE] > 0)
if (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_DELETE] > 0)
{
bool dodelete;
dodelete = ExecBRDeleteTriggers(estate, tupleid);
dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid);
if (!dodelete) /* "do nothing" */
return;
@ -1370,8 +1372,8 @@ ldelete:;
*/
/* AFTER ROW DELETE Triggers */
if (resultRelationDesc->trigdesc)
ExecARDeleteTriggers(estate, tupleid);
if (resultRelInfo->ri_TrigDesc)
ExecARDeleteTriggers(estate, resultRelInfo, tupleid);
}
/* ----------------------------------------------------------------
@ -1418,12 +1420,13 @@ ExecReplace(TupleTableSlot *slot,
resultRelationDesc = resultRelInfo->ri_RelationDesc;
/* BEFORE ROW UPDATE Triggers */
if (resultRelationDesc->trigdesc &&
resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
if (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
{
HeapTuple newtuple;
newtuple = ExecBRUpdateTriggers(estate, tupleid, tuple);
newtuple = ExecBRUpdateTriggers(estate, resultRelInfo,
tupleid, tuple);
if (newtuple == NULL) /* "do nothing" */
return;
@ -1519,8 +1522,8 @@ lreplace:;
ExecInsertIndexTuples(slot, &(tuple->t_self), estate, true);
/* AFTER ROW UPDATE Triggers */
if (resultRelationDesc->trigdesc)
ExecARUpdateTriggers(estate, tupleid, tuple);
if (resultRelInfo->ri_TrigDesc)
ExecARUpdateTriggers(estate, resultRelInfo, tupleid, tuple);
}
static char *

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.77 2001/03/22 03:59:55 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.78 2001/06/01 02:41:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -205,7 +205,6 @@ CatalogCacheInitializeCache(CatCache *cache)
/*
* switch to the cache context so our allocations do not vanish at the
* end of a transaction
*
*/
if (!CacheMemoryContext)
CreateCacheMemoryContext();
@ -214,13 +213,11 @@ CatalogCacheInitializeCache(CatCache *cache)
/*
* copy the relcache's tuple descriptor to permanent cache storage
*
*/
tupdesc = CreateTupleDescCopyConstr(RelationGetDescr(relation));
/*
* return to the caller's memory context and close the rel
*
*/
MemoryContextSwitchTo(oldcxt);
@ -231,7 +228,6 @@ CatalogCacheInitializeCache(CatCache *cache)
/*
* initialize cache's key information
*
*/
for (i = 0; i < cache->cc_nkeys; ++i)
{
@ -255,9 +251,23 @@ CatalogCacheInitializeCache(CatCache *cache)
*/
cache->cc_skey[i].sk_procedure = EQPROC(keytype);
/*
* Note: to avoid any possible leakage of scan temporary data into
* the cache context, we do not switch into CacheMemoryContext while
* calling fmgr_info here. Instead set fn_mcxt on return. This
* would fail to work correctly if fmgr_info allocated any subsidiary
* data structures to attach to the FmgrInfo record; but it doesn't
* do so for built-in functions, and all the comparator functions
* for system caches should most assuredly be built-in functions.
* Currently there's no real need to fix fn_mcxt either, but let's do
* that anyway just to make sure it's not pointing to a dead context
* later on.
*/
fmgr_info(cache->cc_skey[i].sk_procedure,
&cache->cc_skey[i].sk_func);
cache->cc_skey[i].sk_nargs = cache->cc_skey[i].sk_func.fn_nargs;
cache->cc_skey[i].sk_func.fn_mcxt = CacheMemoryContext;
/* Initialize sk_attno suitably for HeapKeyTest() and heap scans */
cache->cc_skey[i].sk_attno = cache->cc_key[i];
@ -270,7 +280,6 @@ CatalogCacheInitializeCache(CatCache *cache)
/*
* mark this cache fully initialized
*
*/
cache->cc_tupdesc = tupdesc;
}
@ -705,7 +714,6 @@ InitCatCache(int id,
* certain system indexes that support critical syscaches.
* We can't use an indexscan to fetch these, else we'll get into
* infinite recursion. A plain heap scan will work, however.
*
*/
static bool
IndexScanOK(CatCache *cache, ScanKey cur_skey)

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.135 2001/05/30 14:15:26 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.136 2001/06/01 02:41:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1161,19 +1161,20 @@ IndexedAccessMethodInitialize(Relation relation)
int natts;
Size stratSize;
Size supportSize;
uint16 relamstrategies;
uint16 relamsupport;
uint16 amstrategies;
uint16 amsupport;
natts = relation->rd_rel->relnatts;
relamstrategies = relation->rd_am->amstrategies;
stratSize = AttributeNumberGetIndexStrategySize(natts, relamstrategies);
amstrategies = relation->rd_am->amstrategies;
amsupport = relation->rd_am->amsupport;
stratSize = AttributeNumberGetIndexStrategySize(natts, amstrategies);
strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
stratSize);
relamsupport = relation->rd_am->amsupport;
if (relamsupport > 0)
if (amsupport > 0)
{
supportSize = natts * (relamsupport * sizeof(RegProcedure));
supportSize = natts * (amsupport * sizeof(RegProcedure));
support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
supportSize);
}
@ -1182,9 +1183,9 @@ IndexedAccessMethodInitialize(Relation relation)
IndexSupportInitialize(strategy, support,
&relation->rd_uniqueindex,
relation->rd_att->attrs[0]->attrelid,
RelationGetRelid(relation),
relation->rd_rel->relam,
relamstrategies, relamsupport, natts);
amstrategies, amsupport, natts);
RelationSetIndexSupport(relation, strategy, support);
}
@ -1212,26 +1213,22 @@ formrdesc(char *relationName,
/*
* allocate new relation desc
*
*/
relation = (Relation) palloc(sizeof(RelationData));
MemSet((char *) relation, 0, sizeof(RelationData));
/*
* don't open the unix file yet..
*
*/
relation->rd_fd = -1;
/*
* initialize reference count
*
*/
RelationSetReferenceCount(relation, 1);
/*
* all entries built with this routine are nailed-in-cache
*
*/
relation->rd_isnailed = true;
@ -1241,7 +1238,6 @@ formrdesc(char *relationName,
* The data we insert here is pretty incomplete/bogus, but it'll serve to
* get us launched. RelationCacheInitializePhase2() will read the
* real data from pg_class and replace what we've done here.
*
*/
relation->rd_rel = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
MemSet(relation->rd_rel, 0, CLASS_TUPLE_SIZE);
@ -1266,13 +1262,11 @@ formrdesc(char *relationName,
/*
* initialize attribute tuple form
*
*/
relation->rd_att = CreateTemplateTupleDesc(natts);
/*
* initialize tuple desc info
*
*/
for (i = 0; i < natts; i++)
{
@ -1283,14 +1277,12 @@ formrdesc(char *relationName,
}
/*
* initialize relation id
*
* initialize relation id from info in att array (my, this is ugly)
*/
RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid;
/*
* initialize the relation's lock manager and RelFileNode information
*
*/
RelationInitLockInfo(relation); /* see lmgr.c */
@ -1303,7 +1295,6 @@ formrdesc(char *relationName,
/*
* initialize the rel-has-index flag, using hardwired knowledge
*
*/
relation->rd_rel->relhasindex = false;
@ -1322,7 +1313,6 @@ formrdesc(char *relationName,
/*
* add new reldesc to relcache
*
*/
RelationCacheInsert(relation);
}
@ -2755,10 +2745,8 @@ init_irels(void)
{
fmgr_info(SMD(i).sk_procedure,
&(SMD(i).sk_func));
SMD(i).sk_nargs = SMD(i).sk_func.fn_nargs;
}
/*
* use a real field called rd_istrat instead of the bogosity of
* hanging invisible fields off the end of a structure - jolly

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.52 2001/05/19 09:28:08 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.53 2001/06/01 02:41:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -114,6 +114,15 @@ fmgr_lookupByName(const char *name)
/*
* This routine fills a FmgrInfo struct, given the OID
* of the function to be called.
*
* The caller's CurrentMemoryContext is used as the fn_mcxt of the info
* struct; this means that any subsidiary data attached to the info struct
* (either by fmgr_info itself, or later on by a function call handler)
* will be allocated in that context. The caller must ensure that this
* context is at least as long-lived as the info struct itself. This is
* not a problem in typical cases where the info struct is on the stack or
* in freshly-palloc'd space, but one must take extra care when the info
* struct is in a long-lived table.
*/
void
fmgr_info(Oid functionId, FmgrInfo *finfo)
@ -124,8 +133,9 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
char *prosrc;
/*
* fn_oid *must* be filled in last. Code may assume that is fn_oid is valid,
* the whole struct is valid. Some FmgrInfo struct's do survive elogs.
* fn_oid *must* be filled in last. Some code assumes that if fn_oid is
* valid, the whole struct is valid. Some FmgrInfo struct's do survive
* elogs.
*/
finfo->fn_oid = InvalidOid;
finfo->fn_extra = NULL;
@ -133,10 +143,8 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
if ((fbp = fmgr_isbuiltin(functionId)) != NULL)
{
/*
* Fast path for builtin functions: don't bother consulting
* pg_proc
* Fast path for builtin functions: don't bother consulting pg_proc
*/
finfo->fn_nargs = fbp->nargs;
finfo->fn_strict = fbp->strict;
@ -171,7 +179,6 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
switch (procedureStruct->prolang)
{
case INTERNALlanguageId:
/*
* For an ordinary builtin function, we should never get here
* because the isbuiltin() search above will have succeeded.

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: skey.h,v 1.14 2001/01/24 19:43:19 momjian Exp $
* $Id: skey.h,v 1.15 2001/06/01 02:41:36 tgl Exp $
*
*
* Note:
@ -25,18 +25,18 @@ typedef struct ScanKeyData
bits16 sk_flags; /* flags */
AttrNumber sk_attno; /* domain number */
RegProcedure sk_procedure; /* procedure OID */
FmgrInfo sk_func;
int32 sk_nargs;
FmgrInfo sk_func; /* fmgr call info for procedure */
Datum sk_argument; /* data to compare */
} ScanKeyData;
typedef ScanKeyData *ScanKey;
/* ScanKeyData flags */
#define SK_ISNULL 0x1 /* sk_argument is NULL */
#define SK_UNARY 0x2 /* unary function (currently unsupported) */
#define SK_NEGATE 0x4 /* negate function result */
#define SK_COMMUTE 0x8 /* commute function (not fully supported) */
#define SK_ISNULL 0x1
#define SK_UNARY 0x2
#define SK_NEGATE 0x4
#define SK_COMMUTE 0x8
#define ScanUnmarked 0x01
#define ScanUncheckedPrevious 0x02

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: trigger.h,v 1.26 2001/03/22 04:00:43 momjian Exp $
* $Id: trigger.h,v 1.27 2001/06/01 02:41:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -90,15 +90,25 @@ extern void FreeTriggerDesc(TriggerDesc *trigdesc);
extern bool equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2);
extern HeapTuple ExecBRInsertTriggers(EState *estate,
Relation rel, HeapTuple tuple);
ResultRelInfo *relinfo,
HeapTuple trigtuple);
extern void ExecARInsertTriggers(EState *estate,
Relation rel, HeapTuple tuple);
extern bool ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid);
extern void ExecARDeleteTriggers(EState *estate, ItemPointer tupleid);
extern HeapTuple ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid,
HeapTuple tuple);
extern void ExecARUpdateTriggers(EState *estate, ItemPointer tupleid,
HeapTuple tuple);
ResultRelInfo *relinfo,
HeapTuple trigtuple);
extern bool ExecBRDeleteTriggers(EState *estate,
ResultRelInfo *relinfo,
ItemPointer tupleid);
extern void ExecARDeleteTriggers(EState *estate,
ResultRelInfo *relinfo,
ItemPointer tupleid);
extern HeapTuple ExecBRUpdateTriggers(EState *estate,
ResultRelInfo *relinfo,
ItemPointer tupleid,
HeapTuple newtuple);
extern void ExecARUpdateTriggers(EState *estate,
ResultRelInfo *relinfo,
ItemPointer tupleid,
HeapTuple newtuple);
/* ----------

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: execnodes.h,v 1.60 2001/05/27 20:48:51 tgl Exp $
* $Id: execnodes.h,v 1.61 2001/06/01 02:41:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -198,16 +198,18 @@ typedef struct JunkFilter
/* ----------------
* ResultRelInfo information
*
* whenever we update an existing relation, we have to
* update indices on the relation. The ResultRelInfo class
* is used to hold all the information on result relations,
* including indices.. -cim 10/15/89
* Whenever we update an existing relation, we have to
* update indices on the relation, and perhaps also fire triggers.
* The ResultRelInfo class is used to hold all the information needed
* about a result relation, including indices.. -cim 10/15/89
*
* RangeTableIndex result relation's range table index
* RelationDesc relation descriptor for result relation
* NumIndices # of indices existing on result relation
* IndexRelationDescs array of relation descriptors for indices
* IndexRelationInfo array of key/attr info for indices
* TrigDesc triggers to be fired, if any
* TrigFunctions cached lookup info for trigger functions
* ConstraintExprs array of constraint-checking expressions
* junkFilter for removing junk attributes from tuples
* ----------------
@ -220,6 +222,8 @@ typedef struct ResultRelInfo
int ri_NumIndices;
RelationPtr ri_IndexRelationDescs;
IndexInfo **ri_IndexRelationInfo;
TriggerDesc *ri_TrigDesc;
FmgrInfo *ri_TrigFunctions;
List **ri_ConstraintExprs;
JunkFilter *ri_junkFilter;
} ResultRelInfo;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: rel.h,v 1.45 2001/03/22 04:01:14 momjian Exp $
* $Id: rel.h,v 1.46 2001/06/01 02:41:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -47,13 +47,11 @@ typedef LockInfoData *LockInfo;
* Likewise, this struct really belongs to trigger.h, but for convenience
* we put it here.
*/
typedef struct Trigger
{
Oid tgoid;
char *tgname;
Oid tgfoid;
FmgrInfo tgfunc;
int16 tgtype;
bool tgenabled;
bool tgisconstraint;
@ -66,16 +64,23 @@ typedef struct Trigger
typedef struct TriggerDesc
{
/* index data to identify which triggers are which */
uint16 n_before_statement[4];
uint16 n_before_row[4];
uint16 n_after_row[4];
uint16 n_after_statement[4];
Trigger **tg_before_statement[4];
Trigger **tg_before_row[4];
Trigger **tg_after_row[4];
Trigger **tg_after_statement[4];
/* the actual array of triggers is here */
/*
* Index data to identify which triggers are which. Since each trigger
* can appear in more than one class, for each class we provide a list
* of integer indexes into the triggers array.
*/
#define TRIGGER_NUM_EVENT_CLASSES 4
uint16 n_before_statement[TRIGGER_NUM_EVENT_CLASSES];
uint16 n_before_row[TRIGGER_NUM_EVENT_CLASSES];
uint16 n_after_row[TRIGGER_NUM_EVENT_CLASSES];
uint16 n_after_statement[TRIGGER_NUM_EVENT_CLASSES];
int *tg_before_statement[TRIGGER_NUM_EVENT_CLASSES];
int *tg_before_row[TRIGGER_NUM_EVENT_CLASSES];
int *tg_after_row[TRIGGER_NUM_EVENT_CLASSES];
int *tg_after_statement[TRIGGER_NUM_EVENT_CLASSES];
/* The actual array of triggers is here */
Trigger *triggers;
int numtriggers;
} TriggerDesc;