Commit 0b370ea7 authored by Tom Lane's avatar Tom Lane

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.
parent a1d9d096
...@@ -366,7 +366,6 @@ typedef struct Trigger ...@@ -366,7 +366,6 @@ typedef struct Trigger
Oid tgoid; Oid tgoid;
char *tgname; char *tgname;
Oid tgfoid; Oid tgfoid;
FmgrInfo tgfunc;
int16 tgtype; int16 tgtype;
bool tgenabled; bool tgenabled;
bool tgisconstraint; bool tgisconstraint;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -40,11 +40,13 @@ ScanKeyEntrySetIllegal(ScanKey entry)
entry->sk_flags = 0; /* just in case... */ entry->sk_flags = 0; /* just in case... */
entry->sk_attno = InvalidAttrNumber; entry->sk_attno = InvalidAttrNumber;
entry->sk_procedure = 0; /* should be InvalidRegProcedure */ entry->sk_procedure = 0; /* should be InvalidRegProcedure */
entry->sk_func.fn_oid = InvalidOid;
entry->sk_argument = (Datum) 0;
} }
/* /*
* ScanKeyEntryInitialize * ScanKeyEntryInitialize
* Initializes an scan key entry. * Initializes a scan key entry.
* *
* Note: * Note:
* Assumes the scan key entry is valid. * Assumes the scan key entry is valid.
...@@ -64,7 +66,6 @@ ScanKeyEntryInitialize(ScanKey entry, ...@@ -64,7 +66,6 @@ ScanKeyEntryInitialize(ScanKey entry,
entry->sk_procedure = procedure; entry->sk_procedure = procedure;
entry->sk_argument = argument; entry->sk_argument = argument;
fmgr_info(procedure, &entry->sk_func); fmgr_info(procedure, &entry->sk_func);
entry->sk_nargs = entry->sk_func.fn_nargs;
Assert(ScanKeyEntryIsLegal(entry)); Assert(ScanKeyEntryIsLegal(entry));
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
* index_open - open an index relation by relationId * index_open - open an index relation by relationId
...@@ -232,7 +232,7 @@ index_beginscan(Relation relation, ...@@ -232,7 +232,7 @@ index_beginscan(Relation relation,
uint16 numberOfKeys, uint16 numberOfKeys,
ScanKey key) ScanKey key)
{ {
IndexScanDesc scandesc; IndexScanDesc scan;
RegProcedure procedure; RegProcedure procedure;
RELATION_CHECKS; RELATION_CHECKS;
...@@ -249,14 +249,22 @@ index_beginscan(Relation relation, ...@@ -249,14 +249,22 @@ index_beginscan(Relation relation,
*/ */
LockRelation(relation, AccessShareLock); LockRelation(relation, AccessShareLock);
scandesc = (IndexScanDesc) scan = (IndexScanDesc)
DatumGetPointer(OidFunctionCall4(procedure, DatumGetPointer(OidFunctionCall4(procedure,
PointerGetDatum(relation), PointerGetDatum(relation),
BoolGetDatum(scanFromEnd), BoolGetDatum(scanFromEnd),
UInt16GetDatum(numberOfKeys), UInt16GetDatum(numberOfKeys),
PointerGetDatum(key))); 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, ...@@ -345,19 +353,9 @@ index_getnext(IndexScanDesc scan,
SCAN_CHECKS; 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. * have the am's gettuple proc do all the work.
* index_beginscan already set up fn_getnext.
*/ */
result = (RetrieveIndexResult) result = (RetrieveIndexResult)
DatumGetPointer(FunctionCall2(&scan->fn_getnext, DatumGetPointer(FunctionCall2(&scan->fn_getnext,
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -458,6 +458,8 @@ RelationInvokeStrategy(Relation relation,
/* ---------------- /* ----------------
* OperatorRelationFillScanKeyEntry * OperatorRelationFillScanKeyEntry
*
* Initialize a ScanKey entry given already-opened pg_operator relation.
* ---------------- * ----------------
*/ */
static void static void
...@@ -498,6 +500,7 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation, ...@@ -498,6 +500,7 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation,
operatorObjectId); operatorObjectId);
} }
MemSet(entry, 0, sizeof(*entry));
entry->sk_flags = 0; entry->sk_flags = 0;
entry->sk_procedure = ((Form_pg_operator) GETSTRUCT(tuple))->oprcode; entry->sk_procedure = ((Form_pg_operator) GETSTRUCT(tuple))->oprcode;
...@@ -511,14 +514,29 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation, ...@@ -511,14 +514,29 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation,
"OperatorRelationFillScanKeyEntry: no procedure for operator %u", "OperatorRelationFillScanKeyEntry: no procedure for operator %u",
operatorObjectId); 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 * IndexSupportInitialize
* Initializes an index strategy and associated support procedures. * 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 void
IndexSupportInitialize(IndexStrategy indexStrategy, IndexSupportInitialize(IndexStrategy indexStrategy,
...@@ -578,7 +596,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy, ...@@ -578,7 +596,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
if (!OidIsValid(iform->indkey[attIndex])) if (!OidIsValid(iform->indkey[attIndex]))
{ {
if (attIndex == InvalidAttrNumber) if (attIndex == InvalidAttrNumber)
elog(ERROR, "IndexSupportInitialize: no pg_index tuple"); elog(ERROR, "IndexSupportInitialize: bogus pg_index tuple");
break; break;
} }
...@@ -637,6 +655,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy, ...@@ -637,6 +655,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
heap_close(relation, AccessShareLock); heap_close(relation, AccessShareLock);
} }
/* Now load the strategy information for the index operators */
ScanKeyEntryInitialize(&entry[0], 0, ScanKeyEntryInitialize(&entry[0], 0,
Anum_pg_amop_amopid, Anum_pg_amop_amopid,
F_OIDEQ, F_OIDEQ,
...@@ -644,7 +663,8 @@ IndexSupportInitialize(IndexStrategy indexStrategy, ...@@ -644,7 +663,8 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
ScanKeyEntryInitialize(&entry[1], 0, ScanKeyEntryInitialize(&entry[1], 0,
Anum_pg_amop_amopclaid, Anum_pg_amop_amopclaid,
F_OIDEQ, 0); F_OIDEQ,
0); /* will fill below */
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock); relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
operatorRelation = heap_openr(OperatorRelationName, AccessShareLock); operatorRelation = heap_openr(OperatorRelationName, AccessShareLock);
...@@ -670,9 +690,11 @@ IndexSupportInitialize(IndexStrategy indexStrategy, ...@@ -670,9 +690,11 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
Form_pg_amop aform; Form_pg_amop aform;
aform = (Form_pg_amop) GETSTRUCT(tuple); aform = (Form_pg_amop) GETSTRUCT(tuple);
strategy = aform->amopstrategy;
Assert(strategy > 0 && strategy <= maxStrategyNumber);
OperatorRelationFillScanKeyEntry(operatorRelation, OperatorRelationFillScanKeyEntry(operatorRelation,
aform->amopopr, aform->amopopr,
StrategyMapGetScanKeyEntry(map, aform->amopstrategy)); StrategyMapGetScanKeyEntry(map, strategy));
} }
heap_endscan(scan); heap_endscan(scan);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
...@@ -722,6 +722,9 @@ UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate) ...@@ -722,6 +722,9 @@ UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* InitIndexStrategy * InitIndexStrategy
*
* XXX this is essentially the same as relcache.c's
* IndexedAccessMethodInitialize(), and probably ought to be merged with it.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
void void
...@@ -733,18 +736,16 @@ InitIndexStrategy(int numatts, ...@@ -733,18 +736,16 @@ InitIndexStrategy(int numatts,
RegProcedure *support; RegProcedure *support;
uint16 amstrategies; uint16 amstrategies;
uint16 amsupport; uint16 amsupport;
Oid attrelid;
Size strsize; Size strsize;
/* /*
* get information from the index relation descriptor * get information from the index relation descriptor
*/ */
attrelid = indexRelation->rd_att->attrs[0]->attrelid;
amstrategies = indexRelation->rd_am->amstrategies; amstrategies = indexRelation->rd_am->amstrategies;
amsupport = indexRelation->rd_am->amsupport; amsupport = indexRelation->rd_am->amsupport;
/* /*
* get the size of the strategy * compute the size of the strategy array
*/ */
strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies); strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
...@@ -779,7 +780,8 @@ InitIndexStrategy(int numatts, ...@@ -779,7 +780,8 @@ InitIndexStrategy(int numatts,
IndexSupportInitialize(strategy, support, IndexSupportInitialize(strategy, support,
&indexRelation->rd_uniqueindex, &indexRelation->rd_uniqueindex,
attrelid, accessMethodObjectId, RelationGetRelid(indexRelation),
accessMethodObjectId,
amstrategies, amsupport, numatts); amstrategies, amsupport, numatts);
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* these routines moved here from commands/define.c and somewhat cleaned up. * 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); ...@@ -71,12 +71,13 @@ static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
* *
* performs a scan on pg_operator for an operator tuple * performs a scan on pg_operator for an operator tuple
* with given name and left/right type oids. * with given name and left/right type oids.
* ---------------------------------------------------------------- *
* pg_operator_desc -- reldesc for pg_operator * pg_operator_desc -- reldesc for pg_operator
* operatorName -- name of operator to fetch * operatorName -- name of operator to fetch
* leftObjectId -- left data type oid of operator to fetch * leftObjectId -- left data type oid of operator to fetch
* rightObjectId -- right data type oid of operator to fetch * rightObjectId -- right data type oid of operator to fetch
* defined -- set TRUE if defined (not a shell) * defined -- set TRUE if defined (not a shell)
* ----------------------------------------------------------------
*/ */
static Oid static Oid
OperatorGetWithOpenRelation(Relation pg_operator_desc, OperatorGetWithOpenRelation(Relation pg_operator_desc,
...@@ -88,26 +89,23 @@ OperatorGetWithOpenRelation(Relation pg_operator_desc, ...@@ -88,26 +89,23 @@ OperatorGetWithOpenRelation(Relation pg_operator_desc,
HeapScanDesc pg_operator_scan; HeapScanDesc pg_operator_scan;
Oid operatorObjectId; Oid operatorObjectId;
HeapTuple tup; HeapTuple tup;
ScanKeyData opKey[3];
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;
/* /*
* form scan key * form scan key
*/ */
opKey[0].sk_argument = PointerGetDatum(operatorName); ScanKeyEntryInitialize(&opKey[0], 0x0,
opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId); Anum_pg_operator_oprname,
opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId); 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 * begin the scan
...@@ -451,7 +449,6 @@ OperatorDef(char *operatorName, ...@@ -451,7 +449,6 @@ OperatorDef(char *operatorName,
int i, int i,
j; j;
Relation pg_operator_desc; Relation pg_operator_desc;
HeapScanDesc pg_operator_scan; HeapScanDesc pg_operator_scan;
HeapTuple tup; HeapTuple tup;
char nulls[Natts_pg_operator]; char nulls[Natts_pg_operator];
...@@ -471,19 +468,7 @@ OperatorDef(char *operatorName, ...@@ -471,19 +468,7 @@ OperatorDef(char *operatorName,
int nargs; int nargs;
NameData oname; NameData oname;
TupleDesc tupDesc; TupleDesc tupDesc;
ScanKeyData opKey[3];
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;
operatorObjectId = OperatorGet(operatorName, operatorObjectId = OperatorGet(operatorName,
leftTypeName, leftTypeName,
...@@ -753,13 +738,22 @@ OperatorDef(char *operatorName, ...@@ -753,13 +738,22 @@ OperatorDef(char *operatorName,
*/ */
if (operatorObjectId) 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 */ /* Make sure we can see the shell even if it is new in current cmd */
CommandCounterIncrement(); 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, pg_operator_scan = heap_beginscan(pg_operator_desc,
0, 0,
SnapshotSelf, /* no cache? */ SnapshotSelf, /* no cache? */
...@@ -789,7 +783,6 @@ OperatorDef(char *operatorName, ...@@ -789,7 +783,6 @@ OperatorDef(char *operatorName,
heap_insert(pg_operator_desc, tup); heap_insert(pg_operator_desc, tup);
operatorObjectId = tup->t_data->t_oid; operatorObjectId = tup->t_data->t_oid;
} }
if (RelationGetForm(pg_operator_desc)->relhasindex) if (RelationGetForm(pg_operator_desc)->relhasindex)
...@@ -841,17 +834,11 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) ...@@ -841,17 +834,11 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
char nulls[Natts_pg_operator]; char nulls[Natts_pg_operator];
char replaces[Natts_pg_operator]; char replaces[Natts_pg_operator];
Datum values[Natts_pg_operator]; Datum values[Natts_pg_operator];
ScanKeyData opKey[1];
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;
for (i = 0; i < Natts_pg_operator; ++i) for (i = 0; i < Natts_pg_operator; ++i)
{ {
values[i] = (Datum) NULL; values[i] = (Datum) 0;
replaces[i] = ' '; replaces[i] = ' ';
nulls[i] = ' '; nulls[i] = ' ';
} }
...@@ -865,7 +852,10 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) ...@@ -865,7 +852,10 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
*/ */
CommandCounterIncrement(); CommandCounterIncrement();
opKey[0].sk_argument = ObjectIdGetDatum(commId); ScanKeyEntryInitialize(&opKey[0], 0x0,
ObjectIdAttributeNumber,
F_OIDEQ,
ObjectIdGetDatum(commId));
pg_operator_scan = heap_beginscan(pg_operator_desc, pg_operator_scan = heap_beginscan(pg_operator_desc,
0, 0,
...@@ -993,7 +983,6 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) ...@@ -993,7 +983,6 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
heap_endscan(pg_operator_scan); heap_endscan(pg_operator_scan);
heap_close(pg_operator_desc, RowExclusiveLock); heap_close(pg_operator_desc, RowExclusiveLock);
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -636,6 +636,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
resultRelInfo = makeNode(ResultRelInfo); resultRelInfo = makeNode(ResultRelInfo);
resultRelInfo->ri_RangeTableIndex = 1; /* dummy */ resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
resultRelInfo->ri_RelationDesc = rel; resultRelInfo->ri_RelationDesc = rel;
resultRelInfo->ri_TrigDesc = rel->trigdesc;
ExecOpenIndices(resultRelInfo); ExecOpenIndices(resultRelInfo);
...@@ -868,12 +869,12 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, ...@@ -868,12 +869,12 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
skip_tuple = false; skip_tuple = false;
/* BEFORE ROW INSERT Triggers */ /* BEFORE ROW INSERT Triggers */
if (rel->trigdesc && if (resultRelInfo->ri_TrigDesc &&
rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0) resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
{ {
HeapTuple newtuple; HeapTuple newtuple;
newtuple = ExecBRInsertTriggers(estate, rel, tuple); newtuple = ExecBRInsertTriggers(estate, resultRelInfo, tuple);
if (newtuple == NULL) /* "do nothing" */ if (newtuple == NULL) /* "do nothing" */
skip_tuple = true; skip_tuple = true;
...@@ -903,8 +904,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, ...@@ -903,8 +904,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false); ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
/* AFTER ROW INSERT Triggers */ /* AFTER ROW INSERT Triggers */
if (rel->trigdesc) if (resultRelInfo->ri_TrigDesc)
ExecARInsertTriggers(estate, rel, tuple); ExecARInsertTriggers(estate, resultRelInfo, tuple);
} }
for (i = 0; i < attr_count; i++) for (i = 0; i < attr_count; i++)
......
...@@ -7,7 +7,7 @@ ...@@ -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.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 @@ ...@@ -32,14 +32,19 @@
#include "utils/syscache.h" #include "utils/syscache.h"
static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger); static void InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx);
static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid, static HeapTuple GetTupleForTrigger(EState *estate,
ResultRelInfo *relinfo,
ItemPointer tid,
TupleTableSlot **newSlot); TupleTableSlot **newSlot);
static HeapTuple ExecCallTriggerFunc(Trigger *trigger, static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
TriggerData *trigdata, FmgrInfo *finfo,
MemoryContext per_tuple_context); MemoryContext per_tuple_context);
static void DeferredTriggerSaveEvent(Relation rel, int event, static void DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
HeapTuple oldtup, HeapTuple newtup); HeapTuple oldtup, HeapTuple newtup);
static void DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
Relation rel, FmgrInfo *finfo,
MemoryContext per_tuple_context);
void void
...@@ -577,8 +582,6 @@ RelationBuildTriggers(Relation relation) ...@@ -577,8 +582,6 @@ RelationBuildTriggers(Relation relation)
DatumGetCString(DirectFunctionCall1(nameout, DatumGetCString(DirectFunctionCall1(nameout,
NameGetDatum(&pg_trigger->tgname)))); NameGetDatum(&pg_trigger->tgname))));
build->tgfoid = pg_trigger->tgfoid; build->tgfoid = pg_trigger->tgfoid;
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;
...@@ -641,21 +644,22 @@ RelationBuildTriggers(Relation relation) ...@@ -641,21 +644,22 @@ RelationBuildTriggers(Relation relation)
trigdesc->triggers = triggers; trigdesc->triggers = triggers;
trigdesc->numtriggers = ntrigs; trigdesc->numtriggers = ntrigs;
for (found = 0; found < ntrigs; found++) for (found = 0; found < ntrigs; found++)
DescribeTrigger(trigdesc, &(triggers[found])); InsertTrigger(trigdesc, &(triggers[found]), found);
relation->trigdesc = trigdesc; relation->trigdesc = trigdesc;
} }
/* Insert the given trigger into the appropriate index list(s) for it */
static void static void
DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger) InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
{ {
uint16 *n; uint16 *n;
Trigger ***t, int **t,
***tp; **tp;
if (TRIGGER_FOR_ROW(trigger->tgtype)) /* Is ROW/STATEMENT if (TRIGGER_FOR_ROW(trigger->tgtype))
* trigger */
{ {
/* ROW trigger */
if (TRIGGER_FOR_BEFORE(trigger->tgtype)) if (TRIGGER_FOR_BEFORE(trigger->tgtype))
{ {
n = trigdesc->n_before_row; n = trigdesc->n_before_row;
...@@ -668,8 +672,8 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger) ...@@ -668,8 +672,8 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
} }
} }
else else
/* STATEMENT (NI) */
{ {
/* STATEMENT trigger */
if (TRIGGER_FOR_BEFORE(trigger->tgtype)) if (TRIGGER_FOR_BEFORE(trigger->tgtype))
{ {
n = trigdesc->n_before_statement; n = trigdesc->n_before_statement;
...@@ -686,12 +690,12 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger) ...@@ -686,12 +690,12 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
{ {
tp = &(t[TRIGGER_EVENT_INSERT]); tp = &(t[TRIGGER_EVENT_INSERT]);
if (*tp == NULL) if (*tp == NULL)
*tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext, *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
sizeof(Trigger *)); sizeof(int));
else else
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) * *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
sizeof(Trigger *)); sizeof(int));
(*tp)[n[TRIGGER_EVENT_INSERT]] = trigger; (*tp)[n[TRIGGER_EVENT_INSERT]] = indx;
(n[TRIGGER_EVENT_INSERT])++; (n[TRIGGER_EVENT_INSERT])++;
} }
...@@ -699,12 +703,12 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger) ...@@ -699,12 +703,12 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
{ {
tp = &(t[TRIGGER_EVENT_DELETE]); tp = &(t[TRIGGER_EVENT_DELETE]);
if (*tp == NULL) if (*tp == NULL)
*tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext, *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
sizeof(Trigger *)); sizeof(int));
else else
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) * *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
sizeof(Trigger *)); sizeof(int));
(*tp)[n[TRIGGER_EVENT_DELETE]] = trigger; (*tp)[n[TRIGGER_EVENT_DELETE]] = indx;
(n[TRIGGER_EVENT_DELETE])++; (n[TRIGGER_EVENT_DELETE])++;
} }
...@@ -712,21 +716,20 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger) ...@@ -712,21 +716,20 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
{ {
tp = &(t[TRIGGER_EVENT_UPDATE]); tp = &(t[TRIGGER_EVENT_UPDATE]);
if (*tp == NULL) if (*tp == NULL)
*tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext, *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
sizeof(Trigger *)); sizeof(int));
else else
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) * *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
sizeof(Trigger *)); sizeof(int));
(*tp)[n[TRIGGER_EVENT_UPDATE]] = trigger; (*tp)[n[TRIGGER_EVENT_UPDATE]] = indx;
(n[TRIGGER_EVENT_UPDATE])++; (n[TRIGGER_EVENT_UPDATE])++;
} }
} }
void void
FreeTriggerDesc(TriggerDesc *trigdesc) FreeTriggerDesc(TriggerDesc *trigdesc)
{ {
Trigger ***t; int **t;
Trigger *trigger; Trigger *trigger;
int i; int i;
...@@ -734,19 +737,19 @@ FreeTriggerDesc(TriggerDesc *trigdesc) ...@@ -734,19 +737,19 @@ FreeTriggerDesc(TriggerDesc *trigdesc)
return; return;
t = trigdesc->tg_before_statement; t = trigdesc->tg_before_statement;
for (i = 0; i < 4; i++) for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
if (t[i] != NULL) if (t[i] != NULL)
pfree(t[i]); pfree(t[i]);
t = trigdesc->tg_before_row; t = trigdesc->tg_before_row;
for (i = 0; i < 4; i++) for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
if (t[i] != NULL) if (t[i] != NULL)
pfree(t[i]); pfree(t[i]);
t = trigdesc->tg_after_row; t = trigdesc->tg_after_row;
for (i = 0; i < 4; i++) for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
if (t[i] != NULL) if (t[i] != NULL)
pfree(t[i]); pfree(t[i]);
t = trigdesc->tg_after_statement; t = trigdesc->tg_after_statement;
for (i = 0; i < 4; i++) for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
if (t[i] != NULL) if (t[i] != NULL)
pfree(t[i]); pfree(t[i]);
...@@ -806,7 +809,6 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2) ...@@ -806,7 +809,6 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
return false; return false;
if (trig1->tgfoid != trig2->tgfoid) if (trig1->tgfoid != trig2->tgfoid)
return false; return false;
/* need not examine tgfunc, if tgfoid matches */
if (trig1->tgtype != trig2->tgtype) if (trig1->tgtype != trig2->tgtype)
return false; return false;
if (trig1->tgenabled != trig2->tgenabled) if (trig1->tgenabled != trig2->tgenabled)
...@@ -832,9 +834,18 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2) ...@@ -832,9 +834,18 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
return true; 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 static HeapTuple
ExecCallTriggerFunc(Trigger *trigger, ExecCallTriggerFunc(TriggerData *trigdata,
TriggerData *trigdata, FmgrInfo *finfo,
MemoryContext per_tuple_context) MemoryContext per_tuple_context)
{ {
FunctionCallInfoData fcinfo; FunctionCallInfoData fcinfo;
...@@ -842,11 +853,13 @@ ExecCallTriggerFunc(Trigger *trigger, ...@@ -842,11 +853,13 @@ ExecCallTriggerFunc(Trigger *trigger,
MemoryContext oldContext; MemoryContext oldContext;
/* /*
* Fmgr lookup info is cached in the Trigger structure, so that we * We cache fmgr lookup info, to avoid making the lookup
* need not repeat the lookup on every call. * again on each call.
*/ */
if (trigger->tgfunc.fn_oid == InvalidOid) if (finfo->fn_oid == InvalidOid)
fmgr_info(trigger->tgfoid, &trigger->tgfunc); 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 * Do the function evaluation in the per-tuple memory context, so that
...@@ -861,7 +874,7 @@ ExecCallTriggerFunc(Trigger *trigger, ...@@ -861,7 +874,7 @@ ExecCallTriggerFunc(Trigger *trigger,
*/ */
MemSet(&fcinfo, 0, sizeof(fcinfo)); MemSet(&fcinfo, 0, sizeof(fcinfo));
fcinfo.flinfo = &trigger->tgfunc; fcinfo.flinfo = finfo;
fcinfo.context = (Node *) trigdata; fcinfo.context = (Node *) trigdata;
result = FunctionCallInvoke(&fcinfo); result = FunctionCallInvoke(&fcinfo);
...@@ -880,26 +893,40 @@ ExecCallTriggerFunc(Trigger *trigger, ...@@ -880,26 +893,40 @@ ExecCallTriggerFunc(Trigger *trigger,
} }
HeapTuple 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]; TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT]; int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
HeapTuple newtuple = trigtuple; HeapTuple newtuple = trigtuple;
HeapTuple oldtuple; HeapTuple oldtuple;
TriggerData LocTriggerData; TriggerData LocTriggerData;
int i; 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.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; 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; LocTriggerData.tg_newtuple = NULL;
for (i = 0; i < ntrigs; i++) for (i = 0; i < ntrigs; i++)
{ {
if (!trigger[i]->tgenabled) Trigger *trigger = &trigdesc->triggers[tgindx[i]];
if (!trigger->tgenabled)
continue; continue;
LocTriggerData.tg_trigtuple = oldtuple = newtuple; LocTriggerData.tg_trigtuple = oldtuple = newtuple;
LocTriggerData.tg_trigger = trigger[i]; LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData, newtuple = ExecCallTriggerFunc(&LocTriggerData,
relinfo->ri_TrigFunctions + tgindx[i],
GetPerTupleMemoryContext(estate)); GetPerTupleMemoryContext(estate));
if (oldtuple != newtuple && oldtuple != trigtuple) if (oldtuple != newtuple && oldtuple != trigtuple)
heap_freetuple(oldtuple); heap_freetuple(oldtuple);
...@@ -910,42 +937,59 @@ ExecBRInsertTriggers(EState *estate, Relation rel, HeapTuple trigtuple) ...@@ -910,42 +937,59 @@ ExecBRInsertTriggers(EState *estate, Relation rel, HeapTuple trigtuple)
} }
void 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 */ /* Must save info if there are any deferred triggers on this rel */
if (rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0 || if (trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0 ||
rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 || trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0) trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
DeferredTriggerSaveEvent(rel, TRIGGER_EVENT_INSERT, NULL, trigtuple); DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_INSERT,
NULL, trigtuple);
} }
bool bool
ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid) ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
ItemPointer tupleid)
{ {
Relation rel = estate->es_result_relation_info->ri_RelationDesc; TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE]; int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE]; int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
TriggerData LocTriggerData; TriggerData LocTriggerData;
HeapTuple trigtuple; HeapTuple trigtuple;
HeapTuple newtuple = NULL; HeapTuple newtuple = NULL;
TupleTableSlot *newSlot; TupleTableSlot *newSlot;
int i; int i;
trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot); trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
if (trigtuple == NULL) if (trigtuple == NULL)
return false; 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.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; 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; LocTriggerData.tg_newtuple = NULL;
for (i = 0; i < ntrigs; i++) for (i = 0; i < ntrigs; i++)
{ {
if (!trigger[i]->tgenabled) Trigger *trigger = &trigdesc->triggers[tgindx[i]];
if (!trigger->tgenabled)
continue; continue;
LocTriggerData.tg_trigtuple = trigtuple; LocTriggerData.tg_trigtuple = trigtuple;
LocTriggerData.tg_trigger = trigger[i]; LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData, newtuple = ExecCallTriggerFunc(&LocTriggerData,
relinfo->ri_TrigFunctions + tgindx[i],
GetPerTupleMemoryContext(estate)); GetPerTupleMemoryContext(estate));
if (newtuple == NULL) if (newtuple == NULL)
break; break;
...@@ -958,27 +1002,31 @@ ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid) ...@@ -958,27 +1002,31 @@ ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
} }
void 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 */ /* Must save info if there are upd/del deferred triggers on this rel */
if (rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 || if (trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 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); heap_freetuple(trigtuple);
} }
} }
HeapTuple 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; TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE]; int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE]; int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
TriggerData LocTriggerData; TriggerData LocTriggerData;
HeapTuple trigtuple; HeapTuple trigtuple;
HeapTuple oldtuple; HeapTuple oldtuple;
...@@ -986,7 +1034,7 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple) ...@@ -986,7 +1034,7 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
TupleTableSlot *newSlot; TupleTableSlot *newSlot;
int i; int i;
trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot); trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
if (trigtuple == NULL) if (trigtuple == NULL)
return NULL; return NULL;
...@@ -997,17 +1045,29 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple) ...@@ -997,17 +1045,29 @@ 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);
/* 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.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; 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++) for (i = 0; i < ntrigs; i++)
{ {
if (!trigger[i]->tgenabled) Trigger *trigger = &trigdesc->triggers[tgindx[i]];
if (!trigger->tgenabled)
continue; continue;
LocTriggerData.tg_trigtuple = trigtuple; LocTriggerData.tg_trigtuple = trigtuple;
LocTriggerData.tg_newtuple = oldtuple = newtuple; LocTriggerData.tg_newtuple = oldtuple = newtuple;
LocTriggerData.tg_trigger = trigger[i]; LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData, newtuple = ExecCallTriggerFunc(&LocTriggerData,
relinfo->ri_TrigFunctions + tgindx[i],
GetPerTupleMemoryContext(estate)); GetPerTupleMemoryContext(estate));
if (oldtuple != newtuple && oldtuple != intuple) if (oldtuple != newtuple && oldtuple != intuple)
heap_freetuple(oldtuple); heap_freetuple(oldtuple);
...@@ -1019,26 +1079,30 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple) ...@@ -1019,26 +1079,30 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
} }
void 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 */ /* Must save info if there are upd/del deferred triggers on this rel */
if (rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 || if (trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 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); heap_freetuple(trigtuple);
} }
} }
static HeapTuple 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; HeapTupleData tuple;
HeapTuple result; HeapTuple result;
Buffer buffer; Buffer buffer;
...@@ -1070,7 +1134,7 @@ ltrmark:; ...@@ -1070,7 +1134,7 @@ ltrmark:;
else if (!(ItemPointerEquals(&(tuple.t_self), tid))) else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
{ {
TupleTableSlot *epqslot = EvalPlanQual(estate, TupleTableSlot *epqslot = EvalPlanQual(estate,
estate->es_result_relation_info->ri_RangeTableIndex, relinfo->ri_RangeTableIndex,
&(tuple.t_self)); &(tuple.t_self));
if (!(TupIsNull(epqslot))) if (!(TupIsNull(epqslot)))
...@@ -1293,35 +1357,46 @@ deferredTriggerGetPreviousEvent(Oid relid, ItemPointer ctid) ...@@ -1293,35 +1357,46 @@ deferredTriggerGetPreviousEvent(Oid relid, ItemPointer ctid)
/* ---------- /* ----------
* deferredTriggerExecute() * DeferredTriggerExecute()
* *
* Fetch the required tuples back from the heap and fire one * Fetch the required tuples back from the heap and fire one
* single trigger function. * 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 static void
deferredTriggerExecute(DeferredTriggerEvent event, int itemno, DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
Relation rel, FmgrInfo *finfo,
MemoryContext per_tuple_context) MemoryContext per_tuple_context)
{ {
Relation rel; Oid tgoid = event->dte_item[itemno].dti_tgoid;
TriggerDesc *trigdesc = rel->trigdesc;
TriggerData LocTriggerData; TriggerData LocTriggerData;
HeapTupleData oldtuple; HeapTupleData oldtuple;
HeapTupleData newtuple; HeapTupleData newtuple;
HeapTuple rettuple; HeapTuple rettuple;
Buffer oldbuffer; Buffer oldbuffer;
Buffer newbuffer; 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))) if (ItemPointerIsValid(&(event->dte_oldctid)))
{ {
ItemPointerCopy(&(event->dte_oldctid), &(oldtuple.t_self)); ItemPointerCopy(&(event->dte_oldctid), &(oldtuple.t_self));
heap_fetch(rel, SnapshotAny, &oldtuple, &oldbuffer); heap_fetch(rel, SnapshotAny, &oldtuple, &oldbuffer);
if (!oldtuple.t_data) 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))) if (ItemPointerIsValid(&(event->dte_newctid)))
...@@ -1329,7 +1404,7 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno, ...@@ -1329,7 +1404,7 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
ItemPointerCopy(&(event->dte_newctid), &(newtuple.t_self)); ItemPointerCopy(&(event->dte_newctid), &(newtuple.t_self));
heap_fetch(rel, SnapshotAny, &newtuple, &newbuffer); heap_fetch(rel, SnapshotAny, &newtuple, &newbuffer);
if (!newtuple.t_data) 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, ...@@ -1340,27 +1415,33 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
TRIGGER_EVENT_ROW; TRIGGER_EVENT_ROW;
LocTriggerData.tg_relation = rel; 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) switch (event->dte_event & TRIGGER_EVENT_OPMASK)
{ {
case TRIGGER_EVENT_INSERT: case TRIGGER_EVENT_INSERT:
LocTriggerData.tg_trigtuple = &newtuple; LocTriggerData.tg_trigtuple = &newtuple;
LocTriggerData.tg_newtuple = NULL; LocTriggerData.tg_newtuple = NULL;
LocTriggerData.tg_trigger =
rel->trigdesc->tg_after_row[TRIGGER_EVENT_INSERT][itemno];
break; break;
case TRIGGER_EVENT_UPDATE: case TRIGGER_EVENT_UPDATE:
LocTriggerData.tg_trigtuple = &oldtuple; LocTriggerData.tg_trigtuple = &oldtuple;
LocTriggerData.tg_newtuple = &newtuple; LocTriggerData.tg_newtuple = &newtuple;
LocTriggerData.tg_trigger =
rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE][itemno];
break; break;
case TRIGGER_EVENT_DELETE: case TRIGGER_EVENT_DELETE:
LocTriggerData.tg_trigtuple = &oldtuple; LocTriggerData.tg_trigtuple = &oldtuple;
LocTriggerData.tg_newtuple = NULL; LocTriggerData.tg_newtuple = NULL;
LocTriggerData.tg_trigger =
rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE][itemno];
break; break;
} }
...@@ -1368,8 +1449,8 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno, ...@@ -1368,8 +1449,8 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
* Call the trigger and throw away an eventually returned updated * Call the trigger and throw away an eventually returned updated
* tuple. * tuple.
*/ */
rettuple = ExecCallTriggerFunc(LocTriggerData.tg_trigger, rettuple = ExecCallTriggerFunc(&LocTriggerData,
&LocTriggerData, finfo + tgindx,
per_tuple_context); per_tuple_context);
if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple) if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple)
heap_freetuple(rettuple); heap_freetuple(rettuple);
...@@ -1381,14 +1462,12 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno, ...@@ -1381,14 +1462,12 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
ReferentialIntegritySnapshotOverride = false; ReferentialIntegritySnapshotOverride = false;
/* /*
* Release buffers and close the relation * Release buffers
*/ */
if (ItemPointerIsValid(&(event->dte_oldctid))) if (ItemPointerIsValid(&(event->dte_oldctid)))
ReleaseBuffer(oldbuffer); ReleaseBuffer(oldbuffer);
if (ItemPointerIsValid(&(event->dte_newctid))) if (ItemPointerIsValid(&(event->dte_newctid)))
ReleaseBuffer(newbuffer); ReleaseBuffer(newbuffer);
heap_close(rel, NoLock);
} }
...@@ -1403,9 +1482,9 @@ static void ...@@ -1403,9 +1482,9 @@ static void
deferredTriggerInvokeEvents(bool immediate_only) deferredTriggerInvokeEvents(bool immediate_only)
{ {
DeferredTriggerEvent event; DeferredTriggerEvent event;
int still_deferred_ones;
int i;
MemoryContext per_tuple_context; MemoryContext per_tuple_context;
Relation rel = NULL;
FmgrInfo *finfo = NULL;
/* /*
* For now we process all events - to speedup transaction blocks we * For now we process all events - to speedup transaction blocks we
...@@ -1426,6 +1505,8 @@ deferredTriggerInvokeEvents(bool immediate_only) ...@@ -1426,6 +1505,8 @@ deferredTriggerInvokeEvents(bool immediate_only)
for (event = deftrig_events; event != NULL; event = event->dte_next) for (event = deftrig_events; event != NULL; event = event->dte_next)
{ {
bool still_deferred_ones;
int i;
/* /*
* Check if event is completely done. * Check if event is completely done.
...@@ -1458,9 +1539,32 @@ deferredTriggerInvokeEvents(bool immediate_only) ...@@ -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; event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
} }
...@@ -1471,6 +1575,10 @@ deferredTriggerInvokeEvents(bool immediate_only) ...@@ -1471,6 +1575,10 @@ deferredTriggerInvokeEvents(bool immediate_only)
event->dte_event |= TRIGGER_DEFERRED_DONE; event->dte_event |= TRIGGER_DEFERRED_DONE;
} }
if (rel)
heap_close(rel, NoLock);
if (finfo)
pfree(finfo);
MemoryContextDelete(per_tuple_context); MemoryContextDelete(per_tuple_context);
} }
...@@ -1892,16 +2000,18 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt) ...@@ -1892,16 +2000,18 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* ---------- * ----------
*/ */
static void static void
DeferredTriggerSaveEvent(Relation rel, int event, DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
HeapTuple oldtup, HeapTuple newtup) HeapTuple oldtup, HeapTuple newtup)
{ {
Relation rel = relinfo->ri_RelationDesc;
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
MemoryContext oldcxt; MemoryContext oldcxt;
DeferredTriggerEvent new_event; DeferredTriggerEvent new_event;
DeferredTriggerEvent prev_event; DeferredTriggerEvent prev_event;
int new_size; int new_size;
int i; int i;
int ntriggers; int ntriggers;
Trigger **triggers; int *tgindx;
ItemPointerData oldctid; ItemPointerData oldctid;
ItemPointerData newctid; ItemPointerData newctid;
TriggerData LocTriggerData; TriggerData LocTriggerData;
...@@ -1927,8 +2037,8 @@ DeferredTriggerSaveEvent(Relation rel, int event, ...@@ -1927,8 +2037,8 @@ DeferredTriggerSaveEvent(Relation rel, int event,
*/ */
oldcxt = MemoryContextSwitchTo(deftrig_cxt); oldcxt = MemoryContextSwitchTo(deftrig_cxt);
ntriggers = rel->trigdesc->n_after_row[event]; ntriggers = trigdesc->n_after_row[event];
triggers = rel->trigdesc->tg_after_row[event]; tgindx = trigdesc->tg_after_row[event];
new_size = offsetof(DeferredTriggerEventData, dte_item[0]) + new_size = offsetof(DeferredTriggerEventData, dte_item[0]) +
ntriggers * sizeof(DeferredTriggerEventItem); ntriggers * sizeof(DeferredTriggerEventItem);
...@@ -1941,13 +2051,15 @@ DeferredTriggerSaveEvent(Relation rel, int event, ...@@ -1941,13 +2051,15 @@ DeferredTriggerSaveEvent(Relation rel, int event,
new_event->dte_n_items = ntriggers; new_event->dte_n_items = ntriggers;
for (i = 0; i < ntriggers; i++) 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 = new_event->dte_item[i].dti_state =
((triggers[i]->tgdeferrable) ? ((trigger->tgdeferrable) ?
TRIGGER_DEFERRED_DEFERRABLE : 0) | TRIGGER_DEFERRED_DEFERRABLE : 0) |
((triggers[i]->tginitdeferred) ? ((trigger->tginitdeferred) ?
TRIGGER_DEFERRED_INITDEFERRED : 0) | TRIGGER_DEFERRED_INITDEFERRED : 0) |
((rel->trigdesc->n_before_row[event] > 0) ? ((trigdesc->n_before_row[event] > 0) ?
TRIGGER_DEFERRED_HAS_BEFORE : 0); TRIGGER_DEFERRED_HAS_BEFORE : 0);
} }
...@@ -1978,13 +2090,14 @@ DeferredTriggerSaveEvent(Relation rel, int event, ...@@ -1978,13 +2090,14 @@ DeferredTriggerSaveEvent(Relation rel, int event,
*/ */
for (i = 0; i < ntriggers; i++) for (i = 0; i < ntriggers; i++)
{ {
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
bool is_ri_trigger; bool is_ri_trigger;
bool key_unchanged; bool key_unchanged;
/* /*
* We are interested in RI_FKEY triggers only. * 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_NOACTION_UPD:
case F_RI_FKEY_CASCADE_UPD: case F_RI_FKEY_CASCADE_UPD:
...@@ -2006,7 +2119,7 @@ DeferredTriggerSaveEvent(Relation rel, int event, ...@@ -2006,7 +2119,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
LocTriggerData.tg_relation = rel; LocTriggerData.tg_relation = rel;
LocTriggerData.tg_trigtuple = oldtup; LocTriggerData.tg_trigtuple = oldtup;
LocTriggerData.tg_newtuple = newtup; LocTriggerData.tg_newtuple = newtup;
LocTriggerData.tg_trigger = triggers[i]; LocTriggerData.tg_trigger = trigger;
key_unchanged = RI_FKey_keyequal_upd(&LocTriggerData); key_unchanged = RI_FKey_keyequal_upd(&LocTriggerData);
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -830,6 +830,8 @@ initResultRelInfo(ResultRelInfo *resultRelInfo,
resultRelInfo->ri_NumIndices = 0; resultRelInfo->ri_NumIndices = 0;
resultRelInfo->ri_IndexRelationDescs = NULL; resultRelInfo->ri_IndexRelationDescs = NULL;
resultRelInfo->ri_IndexRelationInfo = NULL; resultRelInfo->ri_IndexRelationInfo = NULL;
resultRelInfo->ri_TrigDesc = resultRelationDesc->trigdesc;
resultRelInfo->ri_TrigFunctions = NULL;
resultRelInfo->ri_ConstraintExprs = NULL; resultRelInfo->ri_ConstraintExprs = NULL;
resultRelInfo->ri_junkFilter = NULL; resultRelInfo->ri_junkFilter = NULL;
...@@ -1232,12 +1234,12 @@ ExecAppend(TupleTableSlot *slot, ...@@ -1232,12 +1234,12 @@ ExecAppend(TupleTableSlot *slot,
resultRelationDesc = resultRelInfo->ri_RelationDesc; resultRelationDesc = resultRelInfo->ri_RelationDesc;
/* BEFORE ROW INSERT Triggers */ /* BEFORE ROW INSERT Triggers */
if (resultRelationDesc->trigdesc && if (resultRelInfo->ri_TrigDesc &&
resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0) resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
{ {
HeapTuple newtuple; HeapTuple newtuple;
newtuple = ExecBRInsertTriggers(estate, resultRelationDesc, tuple); newtuple = ExecBRInsertTriggers(estate, resultRelInfo, tuple);
if (newtuple == NULL) /* "do nothing" */ if (newtuple == NULL) /* "do nothing" */
return; return;
...@@ -1283,8 +1285,8 @@ ExecAppend(TupleTableSlot *slot, ...@@ -1283,8 +1285,8 @@ ExecAppend(TupleTableSlot *slot,
ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false); ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
/* AFTER ROW INSERT Triggers */ /* AFTER ROW INSERT Triggers */
if (resultRelationDesc->trigdesc) if (resultRelInfo->ri_TrigDesc)
ExecARInsertTriggers(estate, resultRelationDesc, tuple); ExecARInsertTriggers(estate, resultRelInfo, tuple);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -1311,12 +1313,12 @@ ExecDelete(TupleTableSlot *slot, ...@@ -1311,12 +1313,12 @@ ExecDelete(TupleTableSlot *slot,
resultRelationDesc = resultRelInfo->ri_RelationDesc; resultRelationDesc = resultRelInfo->ri_RelationDesc;
/* BEFORE ROW DELETE Triggers */ /* BEFORE ROW DELETE Triggers */
if (resultRelationDesc->trigdesc && if (resultRelInfo->ri_TrigDesc &&
resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_DELETE] > 0) resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_DELETE] > 0)
{ {
bool dodelete; bool dodelete;
dodelete = ExecBRDeleteTriggers(estate, tupleid); dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid);
if (!dodelete) /* "do nothing" */ if (!dodelete) /* "do nothing" */
return; return;
...@@ -1370,8 +1372,8 @@ ldelete:; ...@@ -1370,8 +1372,8 @@ ldelete:;
*/ */
/* AFTER ROW DELETE Triggers */ /* AFTER ROW DELETE Triggers */
if (resultRelationDesc->trigdesc) if (resultRelInfo->ri_TrigDesc)
ExecARDeleteTriggers(estate, tupleid); ExecARDeleteTriggers(estate, resultRelInfo, tupleid);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -1418,12 +1420,13 @@ ExecReplace(TupleTableSlot *slot, ...@@ -1418,12 +1420,13 @@ ExecReplace(TupleTableSlot *slot,
resultRelationDesc = resultRelInfo->ri_RelationDesc; resultRelationDesc = resultRelInfo->ri_RelationDesc;
/* BEFORE ROW UPDATE Triggers */ /* BEFORE ROW UPDATE Triggers */
if (resultRelationDesc->trigdesc && if (resultRelInfo->ri_TrigDesc &&
resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0) resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
{ {
HeapTuple newtuple; HeapTuple newtuple;
newtuple = ExecBRUpdateTriggers(estate, tupleid, tuple); newtuple = ExecBRUpdateTriggers(estate, resultRelInfo,
tupleid, tuple);
if (newtuple == NULL) /* "do nothing" */ if (newtuple == NULL) /* "do nothing" */
return; return;
...@@ -1519,8 +1522,8 @@ lreplace:; ...@@ -1519,8 +1522,8 @@ lreplace:;
ExecInsertIndexTuples(slot, &(tuple->t_self), estate, true); ExecInsertIndexTuples(slot, &(tuple->t_self), estate, true);
/* AFTER ROW UPDATE Triggers */ /* AFTER ROW UPDATE Triggers */
if (resultRelationDesc->trigdesc) if (resultRelInfo->ri_TrigDesc)
ExecARUpdateTriggers(estate, tupleid, tuple); ExecARUpdateTriggers(estate, resultRelInfo, tupleid, tuple);
} }
static char * static char *
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -205,7 +205,6 @@ CatalogCacheInitializeCache(CatCache *cache)
/* /*
* switch to the cache context so our allocations do not vanish at the * switch to the cache context so our allocations do not vanish at the
* end of a transaction * end of a transaction
*
*/ */
if (!CacheMemoryContext) if (!CacheMemoryContext)
CreateCacheMemoryContext(); CreateCacheMemoryContext();
...@@ -214,13 +213,11 @@ CatalogCacheInitializeCache(CatCache *cache) ...@@ -214,13 +213,11 @@ CatalogCacheInitializeCache(CatCache *cache)
/* /*
* copy the relcache's tuple descriptor to permanent cache storage * copy the relcache's tuple descriptor to permanent cache storage
*
*/ */
tupdesc = CreateTupleDescCopyConstr(RelationGetDescr(relation)); tupdesc = CreateTupleDescCopyConstr(RelationGetDescr(relation));
/* /*
* return to the caller's memory context and close the rel * return to the caller's memory context and close the rel
*
*/ */
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
...@@ -231,7 +228,6 @@ CatalogCacheInitializeCache(CatCache *cache) ...@@ -231,7 +228,6 @@ CatalogCacheInitializeCache(CatCache *cache)
/* /*
* initialize cache's key information * initialize cache's key information
*
*/ */
for (i = 0; i < cache->cc_nkeys; ++i) for (i = 0; i < cache->cc_nkeys; ++i)
{ {
...@@ -255,9 +251,23 @@ CatalogCacheInitializeCache(CatCache *cache) ...@@ -255,9 +251,23 @@ CatalogCacheInitializeCache(CatCache *cache)
*/ */
cache->cc_skey[i].sk_procedure = EQPROC(keytype); 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, fmgr_info(cache->cc_skey[i].sk_procedure,
&cache->cc_skey[i].sk_func); &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 */ /* Initialize sk_attno suitably for HeapKeyTest() and heap scans */
cache->cc_skey[i].sk_attno = cache->cc_key[i]; cache->cc_skey[i].sk_attno = cache->cc_key[i];
...@@ -270,7 +280,6 @@ CatalogCacheInitializeCache(CatCache *cache) ...@@ -270,7 +280,6 @@ CatalogCacheInitializeCache(CatCache *cache)
/* /*
* mark this cache fully initialized * mark this cache fully initialized
*
*/ */
cache->cc_tupdesc = tupdesc; cache->cc_tupdesc = tupdesc;
} }
...@@ -705,7 +714,6 @@ InitCatCache(int id, ...@@ -705,7 +714,6 @@ InitCatCache(int id,
* certain system indexes that support critical syscaches. * certain system indexes that support critical syscaches.
* We can't use an indexscan to fetch these, else we'll get into * We can't use an indexscan to fetch these, else we'll get into
* infinite recursion. A plain heap scan will work, however. * infinite recursion. A plain heap scan will work, however.
*
*/ */
static bool static bool
IndexScanOK(CatCache *cache, ScanKey cur_skey) IndexScanOK(CatCache *cache, ScanKey cur_skey)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -1161,19 +1161,20 @@ IndexedAccessMethodInitialize(Relation relation)
int natts; int natts;
Size stratSize; Size stratSize;
Size supportSize; Size supportSize;
uint16 relamstrategies; uint16 amstrategies;
uint16 relamsupport; uint16 amsupport;
natts = relation->rd_rel->relnatts; natts = relation->rd_rel->relnatts;
relamstrategies = relation->rd_am->amstrategies; amstrategies = relation->rd_am->amstrategies;
stratSize = AttributeNumberGetIndexStrategySize(natts, relamstrategies); amsupport = relation->rd_am->amsupport;
stratSize = AttributeNumberGetIndexStrategySize(natts, amstrategies);
strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext, strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
stratSize); stratSize);
relamsupport = relation->rd_am->amsupport; if (amsupport > 0)
if (relamsupport > 0)
{ {
supportSize = natts * (relamsupport * sizeof(RegProcedure)); supportSize = natts * (amsupport * sizeof(RegProcedure));
support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext, support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
supportSize); supportSize);
} }
...@@ -1182,9 +1183,9 @@ IndexedAccessMethodInitialize(Relation relation) ...@@ -1182,9 +1183,9 @@ IndexedAccessMethodInitialize(Relation relation)
IndexSupportInitialize(strategy, support, IndexSupportInitialize(strategy, support,
&relation->rd_uniqueindex, &relation->rd_uniqueindex,
relation->rd_att->attrs[0]->attrelid, RelationGetRelid(relation),
relation->rd_rel->relam, relation->rd_rel->relam,
relamstrategies, relamsupport, natts); amstrategies, amsupport, natts);
RelationSetIndexSupport(relation, strategy, support); RelationSetIndexSupport(relation, strategy, support);
} }
...@@ -1212,26 +1213,22 @@ formrdesc(char *relationName, ...@@ -1212,26 +1213,22 @@ formrdesc(char *relationName,
/* /*
* allocate new relation desc * allocate new relation desc
*
*/ */
relation = (Relation) palloc(sizeof(RelationData)); relation = (Relation) palloc(sizeof(RelationData));
MemSet((char *) relation, 0, sizeof(RelationData)); MemSet((char *) relation, 0, sizeof(RelationData));
/* /*
* don't open the unix file yet.. * don't open the unix file yet..
*
*/ */
relation->rd_fd = -1; relation->rd_fd = -1;
/* /*
* initialize reference count * initialize reference count
*
*/ */
RelationSetReferenceCount(relation, 1); RelationSetReferenceCount(relation, 1);
/* /*
* all entries built with this routine are nailed-in-cache * all entries built with this routine are nailed-in-cache
*
*/ */
relation->rd_isnailed = true; relation->rd_isnailed = true;
...@@ -1241,7 +1238,6 @@ formrdesc(char *relationName, ...@@ -1241,7 +1238,6 @@ formrdesc(char *relationName,
* The data we insert here is pretty incomplete/bogus, but it'll serve to * The data we insert here is pretty incomplete/bogus, but it'll serve to
* get us launched. RelationCacheInitializePhase2() will read the * get us launched. RelationCacheInitializePhase2() will read the
* real data from pg_class and replace what we've done here. * real data from pg_class and replace what we've done here.
*
*/ */
relation->rd_rel = (Form_pg_class) palloc(CLASS_TUPLE_SIZE); relation->rd_rel = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
MemSet(relation->rd_rel, 0, CLASS_TUPLE_SIZE); MemSet(relation->rd_rel, 0, CLASS_TUPLE_SIZE);
...@@ -1266,13 +1262,11 @@ formrdesc(char *relationName, ...@@ -1266,13 +1262,11 @@ formrdesc(char *relationName,
/* /*
* initialize attribute tuple form * initialize attribute tuple form
*
*/ */
relation->rd_att = CreateTemplateTupleDesc(natts); relation->rd_att = CreateTemplateTupleDesc(natts);
/* /*
* initialize tuple desc info * initialize tuple desc info
*
*/ */
for (i = 0; i < natts; i++) for (i = 0; i < natts; i++)
{ {
...@@ -1283,14 +1277,12 @@ formrdesc(char *relationName, ...@@ -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; RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid;
/* /*
* initialize the relation's lock manager and RelFileNode information * initialize the relation's lock manager and RelFileNode information
*
*/ */
RelationInitLockInfo(relation); /* see lmgr.c */ RelationInitLockInfo(relation); /* see lmgr.c */
...@@ -1303,7 +1295,6 @@ formrdesc(char *relationName, ...@@ -1303,7 +1295,6 @@ formrdesc(char *relationName,
/* /*
* initialize the rel-has-index flag, using hardwired knowledge * initialize the rel-has-index flag, using hardwired knowledge
*
*/ */
relation->rd_rel->relhasindex = false; relation->rd_rel->relhasindex = false;
...@@ -1322,7 +1313,6 @@ formrdesc(char *relationName, ...@@ -1322,7 +1313,6 @@ formrdesc(char *relationName,
/* /*
* add new reldesc to relcache * add new reldesc to relcache
*
*/ */
RelationCacheInsert(relation); RelationCacheInsert(relation);
} }
...@@ -2755,10 +2745,8 @@ init_irels(void) ...@@ -2755,10 +2745,8 @@ init_irels(void)
{ {
fmgr_info(SMD(i).sk_procedure, fmgr_info(SMD(i).sk_procedure,
&(SMD(i).sk_func)); &(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 * use a real field called rd_istrat instead of the bogosity of
* hanging invisible fields off the end of a structure - jolly * hanging invisible fields off the end of a structure - jolly
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -114,6 +114,15 @@ fmgr_lookupByName(const char *name)
/* /*
* This routine fills a FmgrInfo struct, given the OID * This routine fills a FmgrInfo struct, given the OID
* of the function to be called. * 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 void
fmgr_info(Oid functionId, FmgrInfo *finfo) fmgr_info(Oid functionId, FmgrInfo *finfo)
...@@ -124,8 +133,9 @@ fmgr_info(Oid functionId, FmgrInfo *finfo) ...@@ -124,8 +133,9 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
char *prosrc; char *prosrc;
/* /*
* fn_oid *must* be filled in last. Code may assume that is fn_oid is valid, * fn_oid *must* be filled in last. Some code assumes that if fn_oid is
* the whole struct is valid. Some FmgrInfo struct's do survive elogs. * valid, the whole struct is valid. Some FmgrInfo struct's do survive
* elogs.
*/ */
finfo->fn_oid = InvalidOid; finfo->fn_oid = InvalidOid;
finfo->fn_extra = NULL; finfo->fn_extra = NULL;
...@@ -133,10 +143,8 @@ fmgr_info(Oid functionId, FmgrInfo *finfo) ...@@ -133,10 +143,8 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
if ((fbp = fmgr_isbuiltin(functionId)) != NULL) if ((fbp = fmgr_isbuiltin(functionId)) != NULL)
{ {
/* /*
* Fast path for builtin functions: don't bother consulting * Fast path for builtin functions: don't bother consulting pg_proc
* pg_proc
*/ */
finfo->fn_nargs = fbp->nargs; finfo->fn_nargs = fbp->nargs;
finfo->fn_strict = fbp->strict; finfo->fn_strict = fbp->strict;
...@@ -171,7 +179,6 @@ fmgr_info(Oid functionId, FmgrInfo *finfo) ...@@ -171,7 +179,6 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
switch (procedureStruct->prolang) switch (procedureStruct->prolang)
{ {
case INTERNALlanguageId: case INTERNALlanguageId:
/* /*
* For an ordinary builtin function, we should never get here * For an ordinary builtin function, we should never get here
* because the isbuiltin() search above will have succeeded. * because the isbuiltin() search above will have succeeded.
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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: * Note:
...@@ -25,18 +25,18 @@ typedef struct ScanKeyData ...@@ -25,18 +25,18 @@ typedef struct ScanKeyData
bits16 sk_flags; /* flags */ bits16 sk_flags; /* flags */
AttrNumber sk_attno; /* domain number */ AttrNumber sk_attno; /* domain number */
RegProcedure sk_procedure; /* procedure OID */ RegProcedure sk_procedure; /* procedure OID */
FmgrInfo sk_func; FmgrInfo sk_func; /* fmgr call info for procedure */
int32 sk_nargs;
Datum sk_argument; /* data to compare */ Datum sk_argument; /* data to compare */
} ScanKeyData; } ScanKeyData;
typedef ScanKeyData *ScanKey; 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 ScanUnmarked 0x01
#define ScanUncheckedPrevious 0x02 #define ScanUncheckedPrevious 0x02
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* 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.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); ...@@ -90,15 +90,25 @@ extern void FreeTriggerDesc(TriggerDesc *trigdesc);
extern bool equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2); extern bool equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2);
extern HeapTuple ExecBRInsertTriggers(EState *estate, extern HeapTuple ExecBRInsertTriggers(EState *estate,
Relation rel, HeapTuple tuple); ResultRelInfo *relinfo,
HeapTuple trigtuple);
extern void ExecARInsertTriggers(EState *estate, extern void ExecARInsertTriggers(EState *estate,
Relation rel, HeapTuple tuple); ResultRelInfo *relinfo,
extern bool ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid); HeapTuple trigtuple);
extern void ExecARDeleteTriggers(EState *estate, ItemPointer tupleid); extern bool ExecBRDeleteTriggers(EState *estate,
extern HeapTuple ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, ResultRelInfo *relinfo,
HeapTuple tuple); ItemPointer tupleid);
extern void ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, extern void ExecARDeleteTriggers(EState *estate,
HeapTuple tuple); 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);
/* ---------- /* ----------
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -198,16 +198,18 @@ typedef struct JunkFilter
/* ---------------- /* ----------------
* ResultRelInfo information * ResultRelInfo information
* *
* whenever we update an existing relation, we have to * Whenever we update an existing relation, we have to
* update indices on the relation. The ResultRelInfo class * update indices on the relation, and perhaps also fire triggers.
* is used to hold all the information on result relations, * The ResultRelInfo class is used to hold all the information needed
* including indices.. -cim 10/15/89 * about a result relation, including indices.. -cim 10/15/89
* *
* RangeTableIndex result relation's range table index * RangeTableIndex result relation's range table index
* RelationDesc relation descriptor for result relation * RelationDesc relation descriptor for result relation
* NumIndices # of indices existing on result relation * NumIndices # of indices existing on result relation
* IndexRelationDescs array of relation descriptors for indices * IndexRelationDescs array of relation descriptors for indices
* IndexRelationInfo array of key/attr info 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 * ConstraintExprs array of constraint-checking expressions
* junkFilter for removing junk attributes from tuples * junkFilter for removing junk attributes from tuples
* ---------------- * ----------------
...@@ -220,6 +222,8 @@ typedef struct ResultRelInfo ...@@ -220,6 +222,8 @@ typedef struct ResultRelInfo
int ri_NumIndices; int ri_NumIndices;
RelationPtr ri_IndexRelationDescs; RelationPtr ri_IndexRelationDescs;
IndexInfo **ri_IndexRelationInfo; IndexInfo **ri_IndexRelationInfo;
TriggerDesc *ri_TrigDesc;
FmgrInfo *ri_TrigFunctions;
List **ri_ConstraintExprs; List **ri_ConstraintExprs;
JunkFilter *ri_junkFilter; JunkFilter *ri_junkFilter;
} ResultRelInfo; } ResultRelInfo;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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; ...@@ -47,13 +47,11 @@ typedef LockInfoData *LockInfo;
* Likewise, this struct really belongs to trigger.h, but for convenience * Likewise, this struct really belongs to trigger.h, but for convenience
* we put it here. * we put it here.
*/ */
typedef struct Trigger typedef struct Trigger
{ {
Oid tgoid; Oid tgoid;
char *tgname; char *tgname;
Oid tgfoid; Oid tgfoid;
FmgrInfo tgfunc;
int16 tgtype; int16 tgtype;
bool tgenabled; bool tgenabled;
bool tgisconstraint; bool tgisconstraint;
...@@ -66,16 +64,23 @@ typedef struct Trigger ...@@ -66,16 +64,23 @@ typedef struct Trigger
typedef struct TriggerDesc typedef struct TriggerDesc
{ {
/* index data to identify which triggers are which */ /*
uint16 n_before_statement[4]; * Index data to identify which triggers are which. Since each trigger
uint16 n_before_row[4]; * can appear in more than one class, for each class we provide a list
uint16 n_after_row[4]; * of integer indexes into the triggers array.
uint16 n_after_statement[4]; */
Trigger **tg_before_statement[4]; #define TRIGGER_NUM_EVENT_CLASSES 4
Trigger **tg_before_row[4];
Trigger **tg_after_row[4]; uint16 n_before_statement[TRIGGER_NUM_EVENT_CLASSES];
Trigger **tg_after_statement[4]; uint16 n_before_row[TRIGGER_NUM_EVENT_CLASSES];
/* the actual array of triggers is here */ 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; Trigger *triggers;
int numtriggers; int numtriggers;
} TriggerDesc; } TriggerDesc;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment