Oid tgoid;
char *tgname;
Oid tgfoid;
- FmgrInfo tgfunc;
int16 tgtype;
bool tgenabled;
bool tgisconstraint;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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.
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));
}
*
*
* 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
uint16 numberOfKeys,
ScanKey key)
{
- IndexScanDesc scandesc;
+ IndexScanDesc scan;
RegProcedure procedure;
RELATION_CHECKS;
*/
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;
}
/* ----------------
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,
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/* ----------------
* OperatorRelationFillScanKeyEntry
+ *
+ * Initialize a ScanKey entry given already-opened pg_operator relation.
* ----------------
*/
static void
operatorObjectId);
}
+ MemSet(entry, 0, sizeof(*entry));
entry->sk_flags = 0;
entry->sk_procedure = ((Form_pg_operator) GETSTRUCT(tuple))->oprcode;
"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,
if (!OidIsValid(iform->indkey[attIndex]))
{
if (attIndex == InvalidAttrNumber)
- elog(ERROR, "IndexSupportInitialize: no pg_index tuple");
+ elog(ERROR, "IndexSupportInitialize: bogus pg_index tuple");
break;
}
heap_close(relation, AccessShareLock);
}
+ /* Now load the strategy information for the index operators */
ScanKeyEntryInitialize(&entry[0], 0,
Anum_pg_amop_amopid,
F_OIDEQ,
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);
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);
*
*
* 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
/* ----------------------------------------------------------------
* InitIndexStrategy
+ *
+ * XXX this is essentially the same as relcache.c's
+ * IndexedAccessMethodInitialize(), and probably ought to be merged with it.
* ----------------------------------------------------------------
*/
void
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);
IndexSupportInitialize(strategy, support,
&indexRelation->rd_uniqueindex,
- attrelid, accessMethodObjectId,
+ RelationGetRelid(indexRelation),
+ accessMethodObjectId,
amstrategies, amsupport, numatts);
/*
*
*
* 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.
*
* 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,
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
int i,
j;
Relation pg_operator_desc;
-
HeapScanDesc pg_operator_scan;
HeapTuple tup;
char nulls[Natts_pg_operator];
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,
*/
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? */
heap_insert(pg_operator_desc, tup);
operatorObjectId = tup->t_data->t_oid;
-
}
if (RelationGetForm(pg_operator_desc)->relhasindex)
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] = ' ';
}
*/
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,
heap_endscan(pg_operator_scan);
-
heap_close(pg_operator_desc, RowExclusiveLock);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
resultRelInfo = makeNode(ResultRelInfo);
resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
resultRelInfo->ri_RelationDesc = rel;
+ resultRelInfo->ri_TrigDesc = rel->trigdesc;
ExecOpenIndices(resultRelInfo);
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;
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++)
* 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 $
*
*-------------------------------------------------------------------------
*/
#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
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;
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;
}
}
else
-/* STATEMENT (NI) */
{
+ /* STATEMENT trigger */
if (TRIGGER_FOR_BEFORE(trigger->tgtype))
{
n = trigdesc->n_before_statement;
{
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])++;
}
{
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])++;
}
{
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;
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]);
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)
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;
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
*/
MemSet(&fcinfo, 0, sizeof(fcinfo));
- fcinfo.flinfo = &trigger->tgfunc;
+ fcinfo.flinfo = finfo;
fcinfo.context = (Node *) trigdata;
result = FunctionCallInvoke(&fcinfo);
}
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);
}
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;
}
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;
TupleTableSlot *newSlot;
int i;
- trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
+ trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
if (trigtuple == NULL)
return NULL;
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);
}
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;
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)))
{
/* ----------
- * 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)))
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");
}
/*
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;
}
* 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);
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);
}
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
for (event = deftrig_events; event != NULL; event = event->dte_next)
{
+ bool still_deferred_ones;
+ int i;
/*
* Check if event is completely done.
}
/*
- * 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_event |= TRIGGER_DEFERRED_DONE;
}
+ if (rel)
+ heap_close(rel, NoLock);
+ if (finfo)
+ pfree(finfo);
MemoryContextDelete(per_tuple_context);
}
* ----------
*/
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;
*/
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);
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);
}
*/
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:
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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
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;
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);
}
/* ----------------------------------------------------------------
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;
*/
/* AFTER ROW DELETE Triggers */
- if (resultRelationDesc->trigdesc)
- ExecARDeleteTriggers(estate, tupleid);
+ if (resultRelInfo->ri_TrigDesc)
+ ExecARDeleteTriggers(estate, resultRelInfo, tupleid);
}
/* ----------------------------------------------------------------
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;
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 *
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/*
* switch to the cache context so our allocations do not vanish at the
* end of a transaction
- *
*/
if (!CacheMemoryContext)
CreateCacheMemoryContext();
/*
* 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);
/*
* initialize cache's key information
- *
*/
for (i = 0; i < cache->cc_nkeys; ++i)
{
*/
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];
/*
* mark this cache fully initialized
- *
*/
cache->cc_tupdesc = tupdesc;
}
* 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)
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
}
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);
}
/*
* 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;
* 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);
/*
* initialize attribute tuple form
- *
*/
relation->rd_att = CreateTemplateTupleDesc(natts);
/*
* initialize tuple desc info
- *
*/
for (i = 0; i < natts; i++)
{
}
/*
- * 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 */
/*
* initialize the rel-has-index flag, using hardwired knowledge
- *
*/
relation->rd_rel->relhasindex = false;
/*
* add new reldesc to relcache
- *
*/
RelationCacheInsert(relation);
}
{
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
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/*
* 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)
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;
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;
switch (procedureStruct->prolang)
{
case INTERNALlanguageId:
-
/*
* For an ordinary builtin function, we should never get here
* because the isbuiltin() search above will have succeeded.
* 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:
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
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
/* ----------
* 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 $
*
*-------------------------------------------------------------------------
*/
/* ----------------
* 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
* ----------------
int ri_NumIndices;
RelationPtr ri_IndexRelationDescs;
IndexInfo **ri_IndexRelationInfo;
+ TriggerDesc *ri_TrigDesc;
+ FmgrInfo *ri_TrigFunctions;
List **ri_ConstraintExprs;
JunkFilter *ri_junkFilter;
} ResultRelInfo;
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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;
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;