diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index 567fcab1cd..b2af4ff932 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.60 2000/01/26 05:55:53 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.61 2000/01/31 04:35:48 tgl Exp $ * * NOTES * some of the executor utility code such as "ExecTypeFromTL" should be @@ -226,6 +226,71 @@ FreeTupleDesc(TupleDesc tupdesc) } +bool +equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) +{ + int i; + + if (tupdesc1->natts != tupdesc2->natts) + return false; + for (i = 0; i < tupdesc1->natts; i++) + { + Form_pg_attribute attr1 = tupdesc1->attrs[i]; + Form_pg_attribute attr2 = tupdesc2->attrs[i]; + + /* We do not need to check every single field here, and in fact + * some fields such as attdisbursion probably shouldn't be compared. + */ + if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0) + return false; + if (attr1->atttypid != attr2->atttypid) + return false; + if (attr1->atttypmod != attr2->atttypmod) + return false; + if (attr1->attstorage != attr2->attstorage) + return false; + if (attr1->attnotnull != attr2->attnotnull) + return false; + } + if (tupdesc1->constr != NULL) + { + TupleConstr *constr1 = tupdesc1->constr; + TupleConstr *constr2 = tupdesc2->constr; + + if (constr2 == NULL) + return false; + if (constr1->num_defval != constr2->num_defval) + return false; + for (i = 0; i < (int) constr1->num_defval; i++) + { + AttrDefault *defval1 = constr1->defval + i; + AttrDefault *defval2 = constr2->defval + i; + + if (defval1->adnum != defval2->adnum) + return false; + if (strcmp(defval1->adbin, defval2->adbin) != 0) + return false; + } + if (constr1->num_check != constr2->num_check) + return false; + for (i = 0; i < (int) constr1->num_check; i++) + { + ConstrCheck *check1 = constr1->check + i; + ConstrCheck *check2 = constr2->check + i; + + if (strcmp(check1->ccname, check2->ccname) != 0) + return false; + if (strcmp(check1->ccbin, check2->ccbin) != 0) + return false; + } + if (constr1->has_not_null != constr2->has_not_null) + return false; + } + else if (tupdesc2->constr != NULL) + return false; + return true; +} + /* ---------------------------------------------------------------- * TupleDescInitEntry * diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 79957e7e8c..89c20ce5fa 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.119 2000/01/26 05:56:10 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.120 2000/01/31 04:35:48 tgl Exp $ * * * INTERFACE ROUTINES @@ -2098,18 +2098,6 @@ AddRelationRawConstraints(Relation rel, heap_close(relrel, RowExclusiveLock); heap_freetuple(reltup); - - /* - * Force rebuild of our own relcache entry, otherwise subsequent commands - * in this transaction won't see the new defaults/constraints. - * Must bump command counter or relcache rebuild won't see 'em either. - * - * (This might seem unnecessary, since we are sending out an SI message; - * but if the relation has just been created then relcache.c will ignore - * the SI message on the grounds that the rel is transaction-local...) - */ - CommandCounterIncrement(); - RelationRebuildRelation(rel); } static void diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 86bacf1be5..f3c919a1ed 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -3,11 +3,16 @@ * trigger.c * PostgreSQL TRIGGERs support code. * + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.56 2000/01/31 04:35:49 tgl Exp $ + * *------------------------------------------------------------------------- */ #include "postgres.h" - #include "access/genam.h" #include "access/heapam.h" #include "catalog/catalog.h" @@ -28,14 +33,13 @@ DLLIMPORT TriggerData *CurrentTriggerData = NULL; -void RelationBuildTriggers(Relation relation); -void FreeTriggerDesc(Relation relation); +/* XXX no points for style */ +extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid); static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger); static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid, TupleTableSlot **newSlot); -extern GlobalMemory CacheCxt; void CreateTrigger(CreateTrigStmt *stmt) @@ -52,7 +56,6 @@ CreateTrigger(CreateTrigStmt *stmt) HeapTuple tuple; Relation idescs[Num_pg_trigger_indices]; Relation ridescs[Num_pg_class_indices]; - MemoryContext oldcxt; Oid fargtypes[FUNC_MAX_ARGS]; int found = 0; int i; @@ -258,13 +261,11 @@ CreateTrigger(CreateTrigStmt *stmt) CatalogCloseIndices(Num_pg_class_indices, ridescs); heap_freetuple(tuple); heap_close(pgrel, RowExclusiveLock); - - CommandCounterIncrement(); - oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); - FreeTriggerDesc(rel); - rel->rd_rel->reltriggers = found + 1; - RelationBuildTriggers(rel); - MemoryContextSwitchTo(oldcxt); + /* + * We used to try to update the rel's relcache entry here, but that's + * fairly pointless since it will happen as a byproduct of the upcoming + * CommandCounterIncrement... + */ /* Keep lock on target rel until end of xact */ heap_close(rel, NoLock); } @@ -279,7 +280,6 @@ DropTrigger(DropTrigStmt *stmt) Relation pgrel; HeapTuple tuple; Relation ridescs[Num_pg_class_indices]; - MemoryContext oldcxt; int found = 0; int tgfound = 0; @@ -337,14 +337,11 @@ DropTrigger(DropTrigStmt *stmt) CatalogCloseIndices(Num_pg_class_indices, ridescs); heap_freetuple(tuple); heap_close(pgrel, RowExclusiveLock); - - CommandCounterIncrement(); - oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); - FreeTriggerDesc(rel); - rel->rd_rel->reltriggers = found; - if (found > 0) - RelationBuildTriggers(rel); - MemoryContextSwitchTo(oldcxt); + /* + * We used to try to update the rel's relcache entry here, but that's + * fairly pointless since it will happen as a byproduct of the upcoming + * CommandCounterIncrement... + */ /* Keep lock on target rel until end of xact */ heap_close(rel, NoLock); } @@ -356,7 +353,6 @@ RelationRemoveTriggers(Relation rel) HeapScanDesc tgscan; ScanKeyData key; HeapTuple tup; - Form_pg_trigger pg_trigger; tgrel = heap_openr(TriggerRelationName, RowExclusiveLock); ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid, @@ -387,6 +383,7 @@ RelationRemoveTriggers(Relation rel) tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key); while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0))) { + Form_pg_trigger pg_trigger; Relation refrel; DropTrigStmt stmt; @@ -396,14 +393,14 @@ RelationRemoveTriggers(Relation rel) stmt.relname = pstrdup(RelationGetRelationName(refrel)); stmt.trigname = nameout(&pg_trigger->tgname); + heap_close(refrel, NoLock); + elog(NOTICE, "DROP TABLE implicitly drops referential integrity trigger from table \"%s\"", stmt.relname); DropTrigger(&stmt); pfree(stmt.relname); pfree(stmt.trigname); - - heap_close(refrel, NoLock); } heap_endscan(tgscan); @@ -453,8 +450,8 @@ RelationBuildTriggers(Relation relation) if (!tuple.t_data) continue; if (found == ntrigs) - elog(ERROR, "RelationBuildTriggers: unexpected record found for rel %.*s", - NAMEDATALEN, RelationGetRelationName(relation)); + elog(ERROR, "RelationBuildTriggers: unexpected record found for rel %s", + RelationGetRelationName(relation)); pg_trigger = (Form_pg_trigger) GETSTRUCT(&tuple); @@ -479,8 +476,8 @@ RelationBuildTriggers(Relation relation) Anum_pg_trigger_tgargs, tgrel->rd_att, &isnull); if (isnull) - elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %.*s", - NAMEDATALEN, RelationGetRelationName(relation)); + elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %s", + RelationGetRelationName(relation)); if (build->tgnargs > 0) { char *p; @@ -490,14 +487,13 @@ RelationBuildTriggers(Relation relation) Anum_pg_trigger_tgargs, tgrel->rd_att, &isnull); if (isnull) - elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %.*s", - NAMEDATALEN, RelationGetRelationName(relation)); + elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %s", + RelationGetRelationName(relation)); p = (char *) VARDATA(val); build->tgargs = (char **) palloc(build->tgnargs * sizeof(char *)); for (i = 0; i < build->tgnargs; i++) { - build->tgargs[i] = (char *) palloc(strlen(p) + 1); - strcpy(build->tgargs[i], p); + build->tgargs[i] = pstrdup(p); p += strlen(p) + 1; } } @@ -509,9 +505,9 @@ RelationBuildTriggers(Relation relation) } if (found < ntrigs) - elog(ERROR, "RelationBuildTriggers: %d record not found for rel %.*s", + elog(ERROR, "RelationBuildTriggers: %d record(s) not found for rel %s", ntrigs - found, - NAMEDATALEN, RelationGetRelationName(relation)); + RelationGetRelationName(relation)); index_endscan(sd); index_close(irel); @@ -519,60 +515,11 @@ RelationBuildTriggers(Relation relation) /* Build trigdesc */ trigdesc->triggers = triggers; + trigdesc->numtriggers = ntrigs; for (found = 0; found < ntrigs; found++) - { - build = &(triggers[found]); - DescribeTrigger(trigdesc, build); - } + DescribeTrigger(trigdesc, &(triggers[found])); relation->trigdesc = trigdesc; - -} - -void -FreeTriggerDesc(Relation relation) -{ - TriggerDesc *trigdesc = relation->trigdesc; - Trigger ***t; - Trigger *trigger; - int i; - - if (trigdesc == NULL) - return; - - t = trigdesc->tg_before_statement; - for (i = 0; i < 3; i++) - if (t[i] != NULL) - pfree(t[i]); - t = trigdesc->tg_before_row; - for (i = 0; i < 3; i++) - if (t[i] != NULL) - pfree(t[i]); - t = trigdesc->tg_after_row; - for (i = 0; i < 3; i++) - if (t[i] != NULL) - pfree(t[i]); - t = trigdesc->tg_after_statement; - for (i = 0; i < 3; i++) - if (t[i] != NULL) - pfree(t[i]); - - trigger = trigdesc->triggers; - for (i = 0; i < relation->rd_rel->reltriggers; i++) - { - pfree(trigger->tgname); - if (trigger->tgnargs > 0) - { - while (--(trigger->tgnargs) >= 0) - pfree(trigger->tgargs[trigger->tgnargs]); - pfree(trigger->tgargs); - } - trigger++; - } - pfree(trigdesc->triggers); - pfree(trigdesc); - relation->trigdesc = NULL; - return; } static void @@ -649,6 +596,119 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger) } +void +FreeTriggerDesc(TriggerDesc *trigdesc) +{ + Trigger ***t; + Trigger *trigger; + int i; + + if (trigdesc == NULL) + return; + + t = trigdesc->tg_before_statement; + for (i = 0; i < 4; i++) + if (t[i] != NULL) + pfree(t[i]); + t = trigdesc->tg_before_row; + for (i = 0; i < 4; i++) + if (t[i] != NULL) + pfree(t[i]); + t = trigdesc->tg_after_row; + for (i = 0; i < 4; i++) + if (t[i] != NULL) + pfree(t[i]); + t = trigdesc->tg_after_statement; + for (i = 0; i < 4; i++) + if (t[i] != NULL) + pfree(t[i]); + + trigger = trigdesc->triggers; + for (i = 0; i < trigdesc->numtriggers; i++) + { + pfree(trigger->tgname); + if (trigger->tgnargs > 0) + { + while (--(trigger->tgnargs) >= 0) + pfree(trigger->tgargs[trigger->tgnargs]); + pfree(trigger->tgargs); + } + trigger++; + } + pfree(trigdesc->triggers); + pfree(trigdesc); +} + +bool +equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2) +{ + int i, + j; + + /* + * We need not examine the "index" data, just the trigger array itself; + * if we have the same triggers with the same types, the derived index + * data should match. + * + * XXX It seems possible that the same triggers could appear in different + * orders in the two trigger arrays; do we need to handle that? + */ + if (trigdesc1 != NULL) + { + if (trigdesc2 == NULL) + return false; + if (trigdesc1->numtriggers != trigdesc2->numtriggers) + return false; + for (i = 0; i < trigdesc1->numtriggers; i++) + { + Trigger *trig1 = trigdesc1->triggers + i; + Trigger *trig2 = NULL; + + /* + * We can't assume that the triggers are always read from + * pg_trigger in the same order; so use the trigger OIDs to + * identify the triggers to compare. (We assume here that the + * same OID won't appear twice in either trigger set.) + */ + for (j = 0; j < trigdesc2->numtriggers; j++) + { + trig2 = trigdesc2->triggers + i; + if (trig1->tgoid == trig2->tgoid) + break; + } + if (j >= trigdesc2->numtriggers) + return false; + if (strcmp(trig1->tgname, trig2->tgname) != 0) + 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 false; + if (trig1->tgisconstraint != trig2->tgisconstraint) + return false; + if (trig1->tgdeferrable != trig2->tgdeferrable) + return false; + if (trig1->tginitdeferred != trig2->tginitdeferred) + return false; + if (trig1->tgnargs != trig2->tgnargs) + return false; + if (memcmp(trig1->tgattr, trig2->tgattr, + sizeof(trig1->tgattr)) != 0) + return false; + for (j = 0; j < trig1->tgnargs; j++) + if (strcmp(trig1->tgargs[j], trig2->tgargs[j]) != 0) + return false; + } + } + else if (trigdesc2 != NULL) + return false; + return true; +} + + static HeapTuple ExecCallTriggerFunc(Trigger *trigger) { @@ -811,7 +871,6 @@ ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple) return; } -extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid); static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid, TupleTableSlot **newSlot) diff --git a/src/backend/lib/hasht.c b/src/backend/lib/hasht.c index ad3aa660e2..5caeabd281 100644 --- a/src/backend/lib/hasht.c +++ b/src/backend/lib/hasht.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/lib/Attic/hasht.c,v 1.12 2000/01/26 05:56:26 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/lib/Attic/hasht.c,v 1.13 2000/01/31 04:35:51 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,14 +22,14 @@ * HashTableWalk * * call function on every element in hashtable - * one extra argument, arg may be supplied + * one extra argument (arg) may be supplied * ----------------------------------- */ void HashTableWalk(HTAB *hashtable, HashtFunc function, int arg) { long *hashent; - long *data; + void *data; int keysize; keysize = hashtable->hctl->keysize; @@ -43,7 +43,7 @@ HashTableWalk(HTAB *hashtable, HashtFunc function, int arg) * XXX the corresponding hash table insertion does NOT LONGALIGN * -- make sure the keysize is ok */ - data = (long *) LONGALIGN((char *) hashent + keysize); + data = (void *) LONGALIGN((char *) hashent + keysize); (*function) (data, arg); } } diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index e5e22a7ab3..f96a395605 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.58 2000/01/26 05:57:17 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.59 2000/01/31 04:35:51 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,9 +35,6 @@ static long comphash(long l, char *v); /* ---------------- * variables, macros and other stuff - * - * note CCSIZE allocates 51 buckets .. one was already allocated in - * the catcache structure. * ---------------- */ @@ -64,17 +61,20 @@ GlobalMemory CacheCxt; /* context in which caches are allocated */ /* ---------------- - * EQPROC is used in CatalogCacheInitializeCache - * XXX this should be replaced by catalog lookups soon + * EQPROC is used in CatalogCacheInitializeCache to find the equality + * functions for system types that are used as cache key fields. + * + * XXX this should be replaced by catalog lookups, + * but that seems to pose considerable risk of circularity... * ---------------- */ -static long eqproc[] = { - F_BOOLEQ, 0l, F_CHAREQ, F_NAMEEQ, 0l, - F_INT2EQ, F_KEYFIRSTEQ, F_INT4EQ, 0l, F_TEXTEQ, - F_OIDEQ, 0l, 0l, 0l, F_OIDVECTOREQ +static const Oid eqproc[] = { + F_BOOLEQ, InvalidOid, F_CHAREQ, F_NAMEEQ, InvalidOid, + F_INT2EQ, F_KEYFIRSTEQ, F_INT4EQ, F_OIDEQ, F_TEXTEQ, + F_OIDEQ, InvalidOid, InvalidOid, InvalidOid, F_OIDVECTOREQ }; -#define EQPROC(SYSTEMTYPEOID) eqproc[(SYSTEMTYPEOID)-16] +#define EQPROC(SYSTEMTYPEOID) eqproc[(SYSTEMTYPEOID)-BOOLOID] /* ---------------------------------------------------------------- * internal support functions @@ -169,12 +169,13 @@ CatalogCacheInitializeCache(struct catcache * cache, } /* ---------------- - * initialize the cache's relation id + * initialize the cache's relation id and tuple descriptor * ---------------- */ Assert(RelationIsValid(relation)); cache->relationId = RelationGetRelid(relation); - tupdesc = cache->cc_tupdesc = RelationGetDescr(relation); + tupdesc = CreateTupleDescCopyConstr(RelationGetDescr(relation)); + cache->cc_tupdesc = tupdesc; CACHE3_elog(DEBUG, "CatalogCacheInitializeCache: relid %u, %d keys", cache->relationId, cache->cc_nkeys); @@ -254,22 +255,6 @@ CatalogCacheInitializeCache(struct catcache * cache, MemoryContextSwitchTo(oldcxt); } -/* -------------------------------- - * CatalogCacheSetId - * - * XXX temporary function - * -------------------------------- - */ -#ifdef NOT_USED -void -CatalogCacheSetId(CatCache *cacheInOutP, int id) -{ - Assert(id == InvalidCatalogCacheId || id >= 0); - cacheInOutP->id = id; -} - -#endif - /* ---------------- * comphash * Compute a hash value, somehow. @@ -369,10 +354,12 @@ CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP, Relation relation, HeapTuple tuple) { - bool isNull = '\0'; + bool isNull = false; + /* XXX is this really needed? */ if (cacheInOutP->relationId == InvalidOid) CatalogCacheInitializeCache(cacheInOutP, relation); + switch (cacheInOutP->cc_nkeys) { case 4: @@ -417,8 +404,7 @@ CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP, break; default: elog(FATAL, "CCComputeTupleHashIndex: %d cc_nkeys", - cacheInOutP->cc_nkeys - ); + cacheInOutP->cc_nkeys); break; } @@ -427,6 +413,8 @@ CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP, /* -------------------------------- * CatCacheRemoveCTup + * + * NB: assumes caller has switched to CacheCxt * -------------------------------- */ static void @@ -436,19 +424,24 @@ CatCacheRemoveCTup(CatCache *cache, Dlelem *elt) CatCTup *other_ct; Dlelem *other_elt; - if (elt) - ct = (CatCTup *) DLE_VAL(elt); - else + if (!elt) /* probably-useless safety check */ return; + /* We need to zap both linked-list elements as well as the tuple */ + + ct = (CatCTup *) DLE_VAL(elt); other_elt = ct->ct_node; other_ct = (CatCTup *) DLE_VAL(other_elt); + + heap_freetuple(ct->ct_tup); + DLRemove(other_elt); DLFreeElem(other_elt); - free(other_ct); + pfree(other_ct); DLRemove(elt); DLFreeElem(elt); - free(ct); + pfree(ct); + --cache->cc_ntup; } @@ -529,7 +522,6 @@ CatalogCacheIdInvalidate(int cacheId, /* XXX */ * ---------------- */ MemoryContextSwitchTo(oldcxt); - /* sendpm('I', "Invalidated tuple"); */ } /* ---------------------------------------------------------------- @@ -615,34 +607,26 @@ ResetSystemCache() * * A special case occurs when relId is itself one of the cacheable system * tables --- although those'll never be dropped, they can get flushed from - * the relcache (VACUUM causes this, for example). In that case we need to - * force the next SearchSysCache() call to reinitialize the cache itself, - * because we have info (such as cc_tupdesc) that is pointing at the about- - * to-be-deleted relcache entry. + * the relcache (VACUUM causes this, for example). In that case we need + * to flush all cache entries from that table. The brute-force method + * currently used takes care of that quite handily. (At one point we + * also tried to force re-execution of CatalogCacheInitializeCache for + * the cache(s) on that table. This is a bad idea since it leads to all + * kinds of trouble if a cache flush occurs while loading cache entries. + * We now avoid the need to do it by copying cc_tupdesc out of the relcache, + * rather than relying on the relcache to keep a tupdesc for us. Of course + * this assumes the tupdesc of a cachable system table will not change...) * -------------------------------- */ void SystemCacheRelationFlushed(Oid relId) { - struct catcache *cache; - /* * XXX Ideally we'd search the caches and just zap entries that actually - * refer to the indicated relation. For now, we take the brute-force - * approach: just flush the caches entirely. + * refer to or come from the indicated relation. For now, we take the + * brute-force approach: just flush the caches entirely. */ ResetSystemCache(); - - /* - * If relcache is dropping a system relation's cache entry, mark the - * associated cache structures invalid, so we can rebuild them from - * scratch (not just repopulate them) next time they are used. - */ - for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next) - { - if (cache->relationId == relId) - cache->relationId = InvalidOid; - } } /* -------------------------------- @@ -715,11 +699,11 @@ InitSysCache(char *relname, { /* * We can only do this optimization because the number of hash - * buckets never changes. Without it, we call malloc() too much. + * buckets never changes. Without it, we call palloc() too much. * We could move this to dllist.c, but the way we do this is not - * dynamic/portabl, so why allow other routines to use it. + * dynamic/portable, so why allow other routines to use it. */ - Dllist *cache_begin = malloc((NCCBUCK + 1) * sizeof(Dllist)); + Dllist *cache_begin = palloc((NCCBUCK + 1) * sizeof(Dllist)); for (i = 0; i <= NCCBUCK; ++i) { @@ -927,7 +911,7 @@ SearchSysCache(struct catcache * cache, MemoryContext oldcxt; /* ---------------- - * sanity checks + * one-time startup overhead * ---------------- */ if (cache->relationId == InvalidOid) @@ -946,7 +930,7 @@ SearchSysCache(struct catcache * cache, * resolve self referencing informtion */ if ((ntp = SearchSelfReferences(cache))) - return heap_copytuple(ntp); + return ntp; /* ---------------- * find the hash bucket in which to look for the tuple @@ -995,10 +979,8 @@ SearchSysCache(struct catcache * cache, DLMoveToFront(elt); #ifdef CACHEDEBUG - relation = heap_open(cache->relationId, NoLock); CACHE3_elog(DEBUG, "SearchSysCache(%s): found in bucket %d", - RelationGetRelationName(relation), hash); - heap_close(relation, NoLock); + cache->cc_relname, hash); #endif /* CACHEDEBUG */ return ct->ct_tup; @@ -1020,9 +1002,7 @@ SearchSysCache(struct catcache * cache, */ if (cache->busy) - { elog(ERROR, "SearchSysCache: recursive use of cache %d", cache->id); - } cache->busy = true; /* ---------------- @@ -1140,10 +1120,10 @@ SearchSysCache(struct catcache * cache, * it easier to remove something from both the cache bucket and * the lru list at the same time */ - nct = (CatCTup *) malloc(sizeof(CatCTup)); + nct = (CatCTup *) palloc(sizeof(CatCTup)); nct->ct_tup = ntp; elt = DLNewElem(nct); - nct2 = (CatCTup *) malloc(sizeof(CatCTup)); + nct2 = (CatCTup *) palloc(sizeof(CatCTup)); nct2->ct_tup = ntp; lru_elt = DLNewElem(nct2); nct2->ct_node = elt; diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index 473978bd41..17071f8e23 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.33 2000/01/29 19:51:59 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.34 2000/01/31 04:35:52 tgl Exp $ * * Note - this code is real crufty... * @@ -557,7 +557,7 @@ static void ResetSystemCaches() { ResetSystemCache(); - RelationCacheInvalidate(true); + RelationCacheInvalidate(); } /* -------------------------------- diff --git a/src/backend/utils/cache/rel.c b/src/backend/utils/cache/rel.c index d24c1ca0c9..50edb42246 100644 --- a/src/backend/utils/cache/rel.c +++ b/src/backend/utils/cache/rel.c @@ -8,11 +8,10 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/rel.c,v 1.7 2000/01/26 05:57:17 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/rel.c,v 1.8 2000/01/31 04:35:52 tgl Exp $ * *------------------------------------------------------------------------- */ -/* #define RELREFDEBUG 1 */ #include "postgres.h" #include "access/istrat.h" @@ -21,45 +20,22 @@ /* * RelationIsValid is now a macro in rel.h -cim 4/27/91 * - * Many of the RelationGet...() functions are now macros in rel.h + * All of the RelationGet...() functions are now macros in rel.h * -mer 3/2/92 */ -/* - * RelationGetIndexStrategy - * Returns index strategy for a relation. - * - * Note: - * Assumes relation descriptor is valid. - * Assumes relation descriptor is for an index relation. - */ -IndexStrategy -RelationGetIndexStrategy(Relation relation) -{ - return relation->rd_istrat; -} - /* * RelationSetIndexSupport * Sets index strategy and support info for a relation. * + * This routine saves two pointers -- one to the IndexStrategy, and + * one to the RegProcs that support the indexed access method. + * * Note: - * Assumes relation descriptor is a valid pointer to sufficient space. + * Assumes relation descriptor is valid. * Assumes index strategy is valid. Assumes support is valid if non- * NULL. */ -/* ---------------- - * RelationSetIndexSupport - * - * This routine saves two pointers -- one to the IndexStrategy, and - * one to the RegProcs that support the indexed access method. These - * pointers are stored in the space following the attribute data in the - * reldesc. - * - * NEW: the index strategy and support are now stored in real fields - * at the end of the structure - jolly - * ---------------- - */ void RelationSetIndexSupport(Relation relation, IndexStrategy strategy, diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 4a6c86d84d..7c993d3d73 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.88 2000/01/29 19:51:59 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.89 2000/01/31 04:35:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,7 +20,6 @@ * RelationIdGetRelation - get a reldesc by relation id * RelationNameGetRelation - get a reldesc by relation name * RelationClose - close an open relation - * RelationRebuildRelation - rebuild relation information * * NOTES * This file is in the process of being cleaned up @@ -37,7 +36,6 @@ #include "postgres.h" -#include "utils/builtins.h" #include "access/genam.h" #include "access/heapam.h" #include "access/istrat.h" @@ -52,50 +50,45 @@ #include "catalog/pg_rewrite.h" #include "catalog/pg_type.h" #include "catalog/pg_variable.h" +#include "commands/trigger.h" #include "lib/hasht.h" #include "miscadmin.h" +#include "storage/bufmgr.h" #include "storage/smgr.h" +#include "utils/builtins.h" #include "utils/catcache.h" #include "utils/relcache.h" #include "utils/temprel.h" -static void RelationClearRelation(Relation relation, bool rebuildIt); -static void RelationFlushRelation(Relation *relationPtr, - bool onlyFlushReferenceCountZero); -static Relation RelationNameCacheGetRelation(const char *relationName); -static void RelationCacheAbortWalker(Relation *relationPtr, - int dummy); -static void init_irels(void); -static void write_irels(void); - -/* ---------------- - * externs - * ---------------- - */ -extern bool AMI_OVERRIDE; /* XXX style */ -extern GlobalMemory CacheCxt; /* from utils/cache/catcache.c */ - /* ---------------- * hardcoded tuple descriptors. see lib/backend/catalog/pg_attribute.h * ---------------- */ -FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class}; -FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute}; -FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc}; -FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type}; -FormData_pg_attribute Desc_pg_variable[Natts_pg_variable] = {Schema_pg_variable}; -FormData_pg_attribute Desc_pg_log[Natts_pg_log] = {Schema_pg_log}; +static FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class}; +static FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute}; +static FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc}; +static FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type}; +static FormData_pg_attribute Desc_pg_variable[Natts_pg_variable] = {Schema_pg_variable}; +static FormData_pg_attribute Desc_pg_log[Natts_pg_log] = {Schema_pg_log}; /* ---------------- - * global variables + * Hash tables that index the relation cache * * Relations are cached two ways, by name and by id, * thus there are two hash tables for referencing them. * ---------------- */ -HTAB *RelationNameCache; -HTAB *RelationIdCache; +static HTAB *RelationNameCache; +static HTAB *RelationIdCache; + +/* + * newlyCreatedRelns - + * relations created during this transaction. We need to keep track of + * these. + */ +static List *newlyCreatedRelns = NULL; + /* ---------------- * RelationBuildDescInfo exists so code can be shared @@ -207,8 +200,17 @@ do { \ } while(0) /* non-export function prototypes */ + +static void RelationClearRelation(Relation relation, bool rebuildIt); +static void RelationFlushRelation(Relation *relationPtr, + int skipLocalRelations); +static Relation RelationNameCacheGetRelation(const char *relationName); +static void RelationCacheAbortWalker(Relation *relationPtr, int dummy); +static void init_irels(void); +static void write_irels(void); + static void formrdesc(char *relationName, u_int natts, - FormData_pg_attribute *att); + FormData_pg_attribute *att); static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo); static HeapTuple scan_pg_rel_seq(RelationBuildDescInfo buildinfo); @@ -227,16 +229,6 @@ static void IndexedAccessMethodInitialize(Relation relation); static void AttrDefaultFetch(Relation relation); static void RelCheckFetch(Relation relation); -extern void RelationBuildTriggers(Relation relation); -extern void FreeTriggerDesc(Relation relation); - -/* - * newlyCreatedRelns - - * relations created during this transaction. We need to keep track of - * these. - */ -static List *newlyCreatedRelns = NULL; - /* ---------------------------------------------------------------- * RelationIdGetRelation() and RelationNameGetRelation() * support functions @@ -632,22 +624,20 @@ RelationBuildRuleLock(Relation relation) ObjectIdGetDatum(RelationGetRelid(relation))); /* ---------------- - * open pg_attribute and begin a scan + * open pg_rewrite and begin a scan * ---------------- */ pg_rewrite_desc = heap_openr(RewriteRelationName, AccessShareLock); pg_rewrite_scan = heap_beginscan(pg_rewrite_desc, 0, SnapshotNow, 1, &key); pg_rewrite_tupdesc = RelationGetDescr(pg_rewrite_desc); - /* ---------------- - * add attribute data to relation->rd_att - * ---------------- - */ while (HeapTupleIsValid(pg_rewrite_tuple = heap_getnext(pg_rewrite_scan, 0))) { bool isnull; Datum ruleaction; - Datum rule_evqual_string; + Datum rule_evqual; + char *ruleaction_str; + char *rule_evqual_str; RewriteRule *rule; rule = (RewriteRule *) palloc(sizeof(RewriteRule)); @@ -665,24 +655,27 @@ RelationBuildRuleLock(Relation relation) &isnull); ruleaction = heap_getattr(pg_rewrite_tuple, - Anum_pg_rewrite_ev_action, pg_rewrite_tupdesc, + Anum_pg_rewrite_ev_action, + pg_rewrite_tupdesc, &isnull); - rule_evqual_string = heap_getattr(pg_rewrite_tuple, - Anum_pg_rewrite_ev_qual, pg_rewrite_tupdesc, - &isnull); + ruleaction_str = textout((text *) DatumGetPointer(ruleaction)); + rule->actions = (List *) stringToNode(ruleaction_str); + pfree(ruleaction_str); - ruleaction = PointerGetDatum(textout((text *) DatumGetPointer(ruleaction))); - rule_evqual_string = PointerGetDatum(textout((text *) DatumGetPointer(rule_evqual_string))); + rule_evqual = heap_getattr(pg_rewrite_tuple, + Anum_pg_rewrite_ev_qual, + pg_rewrite_tupdesc, + &isnull); + rule_evqual_str = textout((text *) DatumGetPointer(rule_evqual)); + rule->qual = (Node *) stringToNode(rule_evqual_str); + pfree(rule_evqual_str); - rule->actions = (List *) stringToNode(DatumGetPointer(ruleaction)); - rule->qual = (Node *) stringToNode(DatumGetPointer(rule_evqual_string)); - - rules[numlocks++] = rule; - if (numlocks == maxlocks) + if (numlocks >= maxlocks) { maxlocks *= 2; rules = (RewriteRule **) repalloc(rules, sizeof(RewriteRule *) * maxlocks); } + rules[numlocks++] = rule; } /* ---------------- @@ -701,7 +694,91 @@ RelationBuildRuleLock(Relation relation) rulelock->rules = rules; relation->rd_rules = rulelock; - return; +} + +/* -------------------------------- + * FreeRuleLock + * + * Release the storage used for a set of rewrite rules. + * + * Probably this should be in the rules code someplace... + * -------------------------------- + */ +static void +FreeRuleLock(RuleLock *rlock) +{ + int i; + + if (rlock == NULL) + return; + for (i = 0; i < rlock->numLocks; i++) + { + RewriteRule *rule = rlock->rules[i]; + +#if 0 /* does freefuncs.c still work? Not sure */ + freeObject(rule->actions); + freeObject(rule->qual); +#endif + pfree(rule); + } + pfree(rlock->rules); + pfree(rlock); +} + +/* -------------------------------- + * equalRuleLocks + * + * Determine whether two RuleLocks are equivalent + * + * Probably this should be in the rules code someplace... + * -------------------------------- + */ +static bool +equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2) +{ + int i, + j; + + if (rlock1 != NULL) + { + if (rlock2 == NULL) + return false; + if (rlock1->numLocks != rlock2->numLocks) + return false; + for (i = 0; i < rlock1->numLocks; i++) + { + RewriteRule *rule1 = rlock1->rules[i]; + RewriteRule *rule2 = NULL; + + /* + * We can't assume that the rules are always read from + * pg_rewrite in the same order; so use the rule OIDs to + * identify the rules to compare. (We assume here that the + * same OID won't appear twice in either ruleset.) + */ + for (j = 0; j < rlock2->numLocks; j++) + { + rule2 = rlock2->rules[j]; + if (rule1->ruleId == rule2->ruleId) + break; + } + if (j >= rlock2->numLocks) + return false; + if (rule1->event != rule2->event) + return false; + if (rule1->attrno != rule2->attrno) + return false; + if (rule1->isInstead != rule2->isInstead) + return false; + if (! equal(rule1->qual, rule2->qual)) + return false; + if (! equal(rule1->actions, rule2->actions)) + return false; + } + } + else if (rlock2 != NULL) + return false; + return true; } @@ -800,7 +877,7 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo, * ---------------- */ if (OidIsValid(relam)) - relation->rd_am = (Form_pg_am) AccessMethodObjectIdGetForm(relam); + relation->rd_am = AccessMethodObjectIdGetForm(relam); /* ---------------- * initialize the tuple descriptor (relation->rd_att). @@ -1213,6 +1290,9 @@ RelationClose(Relation relation) * usually used when we are notified of a change to an open relation * (one with refcount > 0). However, this routine just does whichever * it's told to do; callers must determine which they want. + * + * If we detect a change in the relation's TupleDesc or trigger data + * while rebuilding, we complain unless refcount is 0. * -------------------------------- */ static void @@ -1252,26 +1332,53 @@ RelationClearRelation(Relation relation, bool rebuildIt) /* Clear out catcache's entries for this relation */ SystemCacheRelationFlushed(RelationGetRelid(relation)); - /* Free all the subsidiary data structures of the relcache entry */ - FreeTupleDesc(relation->rd_att); - FreeTriggerDesc(relation); - pfree(RelationGetForm(relation)); + /* + * Free all the subsidiary data structures of the relcache entry. + * We cannot free rd_att if we are trying to rebuild the entry, + * however, because pointers to it may be cached in various places. + * The trigger manager might also have pointers into the trigdesc, + * and the rule manager might have pointers into the rewrite rules. + * So to begin with, we can only get rid of these fields: + */ + if (relation->rd_am) + pfree(relation->rd_am); + if (relation->rd_rel) + pfree(relation->rd_rel); + if (relation->rd_istrat) + pfree(relation->rd_istrat); + if (relation->rd_support) + pfree(relation->rd_support); /* * If we're really done with the relcache entry, blow it away. * But if someone is still using it, reconstruct the whole deal * without moving the physical RelationData record (so that the - * someone's pointer is still valid). Must preserve ref count - * and myxactonly flag, too. + * someone's pointer is still valid). */ if (! rebuildIt) { + /* ok to zap remaining substructure */ + FreeTupleDesc(relation->rd_att); + FreeRuleLock(relation->rd_rules); + FreeTriggerDesc(relation->trigdesc); pfree(relation); } else { - uint16 old_refcnt = relation->rd_refcnt; - bool old_myxactonly = relation->rd_myxactonly; + /* + * When rebuilding an open relcache entry, must preserve ref count + * and myxactonly flag. Also attempt to preserve the tupledesc, + * rewrite rules, and trigger substructures in place. + * Furthermore we save/restore rd_nblocks (in case it is a local + * relation) *and* call RelationGetNumberOfBlocks (in case it isn't). + */ + uint16 old_refcnt = relation->rd_refcnt; + bool old_myxactonly = relation->rd_myxactonly; + TupleDesc old_att = relation->rd_att; + RuleLock *old_rules = relation->rd_rules; + TriggerDesc *old_trigdesc = relation->trigdesc; + int old_nblocks = relation->rd_nblocks; + bool relDescChanged = false; RelationBuildDescInfo buildinfo; buildinfo.infotype = INFO_RELID; @@ -1280,12 +1387,54 @@ RelationClearRelation(Relation relation, bool rebuildIt) if (RelationBuildDesc(buildinfo, relation) != relation) { /* Should only get here if relation was deleted */ + FreeTupleDesc(old_att); + FreeRuleLock(old_rules); + FreeTriggerDesc(old_trigdesc); pfree(relation); elog(ERROR, "RelationClearRelation: relation %u deleted while still in use", buildinfo.i.info_id); } RelationSetReferenceCount(relation, old_refcnt); relation->rd_myxactonly = old_myxactonly; + if (equalTupleDescs(old_att, relation->rd_att)) + { + FreeTupleDesc(relation->rd_att); + relation->rd_att = old_att; + } + else + { + FreeTupleDesc(old_att); + relDescChanged = true; + } + if (equalRuleLocks(old_rules, relation->rd_rules)) + { + FreeRuleLock(relation->rd_rules); + relation->rd_rules = old_rules; + } + else + { + FreeRuleLock(old_rules); + relDescChanged = true; + } + if (equalTriggerDescs(old_trigdesc, relation->trigdesc)) + { + FreeTriggerDesc(relation->trigdesc); + relation->trigdesc = old_trigdesc; + } + else + { + FreeTriggerDesc(old_trigdesc); + relDescChanged = true; + } + relation->rd_nblocks = old_nblocks; + /* this is kind of expensive, but I think we must do it in case + * relation has been truncated... + */ + relation->rd_nblocks = RelationGetNumberOfBlocks(relation); + + if (relDescChanged && ! RelationHasReferenceCountZero(relation)) + elog(ERROR, "RelationClearRelation: relation %u modified while in use", + buildinfo.i.info_id); } MemoryContextSwitchTo(oldcxt); @@ -1295,32 +1444,40 @@ RelationClearRelation(Relation relation, bool rebuildIt) * RelationFlushRelation * * Rebuild the relation if it is open (refcount > 0), else blow it away. - * Setting onlyFlushReferenceCountZero to FALSE overrides refcount check. - * This is currently only used to process SI invalidation notifications. + * If skipLocalRelations is TRUE, xact-local relations are ignored + * (which is useful when processing SI cache reset, since xact-local + * relations could not be targets of notifications from other backends). + * * The peculiar calling convention (pointer to pointer to relation) * is needed so that we can use this routine as a hash table walker. * -------------------------------- */ static void RelationFlushRelation(Relation *relationPtr, - bool onlyFlushReferenceCountZero) + int skipLocalRelations) { Relation relation = *relationPtr; + bool rebuildIt; - /* - * Do nothing to transaction-local relations, since they cannot be - * subjects of SI notifications from other backends. - */ if (relation->rd_myxactonly) - return; + { + if (skipLocalRelations) + return; /* don't touch local rels if so commanded */ + /* + * Local rels should always be rebuilt, not flushed; the relcache + * entry must live until RelationPurgeLocalRelation(). + */ + rebuildIt = true; + } + else + { + /* + * Nonlocal rels can be dropped from the relcache if not open. + */ + rebuildIt = ! RelationHasReferenceCountZero(relation); + } - /* - * Zap it. Rebuild if it has nonzero ref count and we did not get - * the override flag. - */ - RelationClearRelation(relation, - (onlyFlushReferenceCountZero && - ! RelationHasReferenceCountZero(relation))); + RelationClearRelation(relation, rebuildIt); } /* -------------------------------- @@ -1373,21 +1530,16 @@ RelationForgetRelation(Oid rid) } } -/* -------------------------------- - * RelationRebuildRelation - - * - * Force a relcache entry to be rebuilt from catalog entries. - * This is needed, eg, after modifying an attribute of the rel. - * -------------------------------- - */ -void -RelationRebuildRelation(Relation relation) -{ - RelationClearRelation(relation, true); -} - /* -------------------------------- * RelationIdInvalidateRelationCacheByRelationId + * + * This routine is invoked for SI cache flush messages. + * + * We used to skip local relations, on the grounds that they could + * not be targets of cross-backend SI update messages; but it seems + * safer to process them, so that our *own* SI update messages will + * have the same effects during CommandCounterIncrement for both + * local and nonlocal relations. * -------------------------------- */ void @@ -1397,36 +1549,8 @@ RelationIdInvalidateRelationCacheByRelationId(Oid relationId) RelationIdCacheLookup(relationId, relation); - /* - * "local" relations are invalidated by RelationPurgeLocalRelation. - * (This is to make LocalBufferSync's life easier: want the descriptor - * to hang around for a while. In fact, won't we want this for - * BufferSync also? But I'll leave it for now since I don't want to - * break anything.) - ay 3/95 - */ - if (PointerIsValid(relation) && !relation->rd_myxactonly) - { -#if 1 - /* - * Seems safest just to NEVER flush rels with positive refcounts. - * I think the code only had that proviso as a rather lame method of - * cleaning up unused relcache entries that had dangling refcounts - * (following elog(ERROR) with an open rel). Now we rely on - * RelationCacheAbort to clean up dangling refcounts, so there's no - * good reason to ever risk flushing a rel with positive refcount. - * IMHO anyway --- tgl 1/29/00. - */ - RelationFlushRelation(&relation, true); -#else - /* - * The boolean onlyFlushReferenceCountZero in RelationFlushReln() - * should be set to true when we are incrementing the command - * counter and to false when we are starting a new xaction. This - * can be determined by checking the current xaction status. - */ - RelationFlushRelation(&relation, CurrentXactInProgress()); -#endif - } + if (PointerIsValid(relation)) + RelationFlushRelation(&relation, false); } #if NOT_USED @@ -1448,7 +1572,7 @@ RelationFlushIndexes(Relation *r, if (relation->rd_rel->relkind == RELKIND_INDEX && /* XXX style */ (!OidIsValid(accessMethodId) || relation->rd_rel->relam == accessMethodId)) - RelationFlushRelation(&relation, true); + RelationFlushRelation(&relation, false); } #endif @@ -1477,37 +1601,19 @@ RelationIdInvalidateRelationCacheByAccessMethodId(Oid accessMethodId) /* * RelationCacheInvalidate - * - * Will blow away either all the cached relation descriptors or - * those that have a zero reference count. - * - * CAUTION: this is only called with onlyFlushReferenceCountZero=true - * at present, so that relation descriptors with positive refcounts - * are rebuilt rather than clobbered. It would only be safe to use a - * "false" parameter in a totally idle backend with no open relations. + * Blow away cached relation descriptors that have zero reference counts, + * and rebuild those with positive reference counts. * * This is currently used only to recover from SI message buffer overflow, - * so we do not blow away transaction-local relations; they cannot be - * targets of SI updates. + * so we do not touch transaction-local relations; they cannot be targets + * of cross-backend SI updates (and our own updates now go through a + * separate linked list that isn't limited by the SI message buffer size). */ void -RelationCacheInvalidate(bool onlyFlushReferenceCountZero) +RelationCacheInvalidate(void) { HashTableWalk(RelationNameCache, (HashtFunc) RelationFlushRelation, - onlyFlushReferenceCountZero); - - if (!onlyFlushReferenceCountZero) - { - /* - * Debugging check: what's left should be transaction-local relations - * plus nailed-in reldescs. There should be 6 hardwired heaps - * + 3 hardwired indices == 9 total. - */ - int numRels = length(newlyCreatedRelns) + 9; - - Assert(RelationNameCache->hctl->nkeys == numRels); - Assert(RelationIdCache->hctl->nkeys == numRels); - } + (int) true); } /* @@ -1672,8 +1778,6 @@ RelationInitialize(void) * initialize the cache with pre-made relation descriptors * for some of the more important system relations. These * relations should always be in the cache. - * - * NB: if you change this list, fix the count in RelationCacheInvalidate! * ---------------- */ formrdesc(RelationRelationName, Natts_pg_class, Desc_pg_class); @@ -2008,7 +2112,7 @@ init_irels(void) } /* oh, for god's sake... */ -#define SMD(i) strat[0].strategyMapData[i].entry[0] +#define SMD(i) strat->strategyMapData[i].entry[0] /* have to reinit the function pointers in the strategy maps */ for (i = 0; i < am->amstrategies * relform->relnatts; i++) @@ -2038,11 +2142,6 @@ init_irels(void) write_irels(); return; } - - /* - * p += sizeof(IndexStrategy); ((RegProcedure **) p) = support; - */ - ird->rd_support = support; RelationInitLockInfo(ird); @@ -2085,8 +2184,6 @@ write_irels(void) * relation searches -- a necessary step, since we're trying to * instantiate the index relation descriptors here. Once we have the * descriptors, nail them into cache so we never lose them. - * - * NB: if you change this list, fix the count in RelationCacheInvalidate! */ oldmode = GetProcessingMode(); diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index 1ee38a928b..afc6da38eb 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.23 2000/01/26 05:57:30 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.24 2000/01/31 04:35:53 tgl Exp $ * * NOTE: * This is a new (Feb. 05, 1999) implementation of the allocation set @@ -389,6 +389,11 @@ AllocSetFree(AllocSet set, AllocPointer pointer) chunk = AllocPointerGetChunk(pointer); +#ifdef CLOBBER_FREED_MEMORY + /* Wipe freed memory for debugging purposes */ + memset(pointer, 0x7F, chunk->size); +#endif + if (chunk->size >= ALLOC_BIGCHUNK_LIMIT) { /* Big chunks are certain to have been allocated as single-chunk diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index f19e1c2d46..78da0bc9ed 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.33 2000/01/26 05:57:31 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.34 2000/01/31 04:35:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -468,7 +468,7 @@ CollectNamedPortals(Portal *portalP, int destroy) void AtEOXact_portals() { - HashTableWalk(PortalHashTable, CollectNamedPortals, 0); + HashTableWalk(PortalHashTable, (HashtFunc) CollectNamedPortals, 0); CollectNamedPortals(NULL, 1); } @@ -478,7 +478,7 @@ AtEOXact_portals() */ #ifdef NOT_USED static void -PortalDump(Portal *thisP) +PortalDump(Portal *thisP, int dummy) { /* XXX state/argument checking here */ @@ -498,7 +498,7 @@ DumpPortals() { /* XXX state checking here */ - HashTableWalk(PortalHashTable, PortalDump, 0); + HashTableWalk(PortalHashTable, (HashtFunc) PortalDump, 0); } #endif @@ -556,7 +556,7 @@ EnablePortalManager(bool on) /* * Each portal must free its non-memory resources specially. */ - HashTableWalk(PortalHashTable, PortalDrop, 0); + HashTableWalk(PortalHashTable, (HashtFunc) PortalDrop, 0); hash_destroy(PortalHashTable); PortalHashTable = NULL; diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index 727fee212a..525cd6267e 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: tupdesc.h,v 1.26 2000/01/26 05:57:51 momjian Exp $ + * $Id: tupdesc.h,v 1.27 2000/01/31 04:35:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -47,12 +47,11 @@ typedef struct tupleConstr */ typedef struct tupleDesc { - int natts; - /* Number of attributes in the tuple */ + int natts; /* Number of attributes in the tuple */ Form_pg_attribute *attrs; /* attrs[N] is a pointer to the description of Attribute Number N+1. */ TupleConstr *constr; -} *TupleDesc; +} *TupleDesc; extern TupleDesc CreateTemplateTupleDesc(int natts); @@ -64,6 +63,8 @@ extern TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc); extern void FreeTupleDesc(TupleDesc tupdesc); +extern bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2); + extern bool TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, char *attributeName, diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h index ddb9f7ca5b..b2c258c2f8 100644 --- a/src/include/commands/trigger.h +++ b/src/include/commands/trigger.h @@ -3,6 +3,10 @@ * trigger.h * prototypes for trigger.c. * + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California + * + * $Id: trigger.h,v 1.18 2000/01/31 04:35:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -70,6 +74,12 @@ extern void CreateTrigger(CreateTrigStmt *stmt); extern void DropTrigger(DropTrigStmt *stmt); extern void RelationRemoveTriggers(Relation rel); +extern void RelationBuildTriggers(Relation relation); + +extern void FreeTriggerDesc(TriggerDesc *trigdesc); + +extern bool equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2); + extern HeapTuple ExecBRInsertTriggers(Relation rel, HeapTuple tuple); extern void ExecARInsertTriggers(Relation rel, HeapTuple tuple); extern bool ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid); diff --git a/src/include/lib/hasht.h b/src/include/lib/hasht.h index 6f64022e23..78318f954d 100644 --- a/src/include/lib/hasht.h +++ b/src/include/lib/hasht.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: hasht.h,v 1.9 2000/01/26 05:58:09 momjian Exp $ + * $Id: hasht.h,v 1.10 2000/01/31 04:35:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,7 +17,7 @@ #include "utils/hsearch.h" -typedef void (*HashtFunc) (); +typedef void (*HashtFunc) (void *hashitem, int arg); extern void HashTableWalk(HTAB *hashtable, HashtFunc function, int arg); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 867ffa604d..c823800802 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * rel.h - * POSTGRES relation descriptor definitions. + * POSTGRES relation descriptor (a/k/a relcache entry) definitions. * * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: rel.h,v 1.33 2000/01/26 05:58:38 momjian Exp $ + * $Id: rel.h,v 1.34 2000/01/31 04:35:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,9 @@ #include "rewrite/prs2lock.h" #include "storage/fd.h" +/* added to prevent circular dependency. bjm 1999/11/15 */ +extern char *get_temp_rel_by_physicalname(const char *relname); + /* * LockRelId and LockInfo really belong to lmgr.h, but it's more convenient * to declare them here so we can have a LockInfoData field in a Relation. @@ -39,6 +42,10 @@ typedef struct LockInfoData typedef LockInfoData *LockInfo; +/* + * Likewise, this struct really belongs to trigger.h, but for convenience + * we put it here. + */ typedef struct Trigger { @@ -58,6 +65,7 @@ typedef struct Trigger typedef struct TriggerDesc { + /* index data to identify which triggers are which */ uint16 n_before_statement[4]; uint16 n_before_row[4]; uint16 n_after_row[4]; @@ -66,9 +74,14 @@ typedef struct TriggerDesc Trigger **tg_before_row[4]; Trigger **tg_after_row[4]; Trigger **tg_after_statement[4]; + /* the actual array of triggers is here */ Trigger *triggers; + int numtriggers; } TriggerDesc; +/* + * Here are the contents of a relation cache entry. + */ typedef struct RelationData { @@ -87,7 +100,7 @@ typedef struct RelationData RuleLock *rd_rules; /* rewrite rules */ IndexStrategy rd_istrat; RegProcedure *rd_support; - TriggerDesc *trigdesc; + TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */ } RelationData; typedef RelationData *Relation; @@ -110,15 +123,6 @@ typedef Relation *RelationPtr; #define InvalidRelation ((Relation) NULL) -/* - * RelationGetSystemPort - * Returns system port of a relation. - * - * Note: - * Assumes relation descriptor is valid. - */ -#define RelationGetSystemPort(relation) ((relation)->rd_fd) - /* * RelationHasReferenceCountZero * True iff relation reference count is zero. @@ -149,7 +153,7 @@ typedef Relation *RelationPtr; /* * RelationGetForm - * Returns relation attribute values for a relation. + * Returns pg_class tuple for a relation. * * Note: * Assumes relation descriptor is valid. @@ -159,15 +163,14 @@ typedef Relation *RelationPtr; /* * RelationGetRelid * - * returns the object id of the relation - * + * returns the OID of the relation */ #define RelationGetRelid(relation) ((relation)->rd_id) /* * RelationGetFile * - * Returns the open File decscriptor + * Returns the open file descriptor for the rel */ #define RelationGetFile(relation) ((relation)->rd_fd) @@ -176,8 +179,6 @@ typedef Relation *RelationPtr; * * Returns a Relation Name */ -/* added to prevent circular dependency. bjm 1999/11/15 */ -char *get_temp_rel_by_physicalname(const char *relname); #define RelationGetRelationName(relation) \ (\ (strncmp(RelationGetPhysicalRelationName(relation), \ @@ -210,10 +211,19 @@ char *get_temp_rel_by_physicalname(const char *relname); */ #define RelationGetDescr(relation) ((relation)->rd_att) +/* + * RelationGetIndexStrategy + * Returns index strategy for a relation. + * + * Note: + * Assumes relation descriptor is valid. + * Assumes relation descriptor is for an index relation. + */ +#define RelationGetIndexStrategy(relation) ((relation)->rd_istrat) -extern IndexStrategy RelationGetIndexStrategy(Relation relation); -extern void RelationSetIndexSupport(Relation relation, IndexStrategy strategy, - RegProcedure *support); +extern void RelationSetIndexSupport(Relation relation, + IndexStrategy strategy, + RegProcedure *support); #endif /* REL_H */ diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h index cb14e1b6d3..073c846e4b 100644 --- a/src/include/utils/relcache.h +++ b/src/include/utils/relcache.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: relcache.h,v 1.18 2000/01/26 05:58:38 momjian Exp $ + * $Id: relcache.h,v 1.19 2000/01/31 04:35:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -29,11 +29,9 @@ extern void RelationForgetRelation(Oid rid); /* * Routines for flushing/rebuilding relcache entries in various scenarios */ -extern void RelationRebuildRelation(Relation relation); - extern void RelationIdInvalidateRelationCacheByRelationId(Oid relationId); -extern void RelationCacheInvalidate(bool onlyFlushReferenceCountZero); +extern void RelationCacheInvalidate(void); extern void RelationRegisterRelation(Relation relation); extern void RelationPurgeLocalRelation(bool xactComitted);