*
*
* 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
}
+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
*
*
*
* 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
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
* 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"
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)
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;
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);
}
Relation pgrel;
HeapTuple tuple;
Relation ridescs[Num_pg_class_indices];
- MemoryContext oldcxt;
int found = 0;
int tgfound = 0;
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);
}
HeapScanDesc tgscan;
ScanKeyData key;
HeapTuple tup;
- Form_pg_trigger pg_trigger;
tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0)))
{
+ Form_pg_trigger pg_trigger;
Relation refrel;
DropTrigStmt stmt;
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);
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);
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;
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;
}
}
}
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);
/* 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
}
+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)
{
return;
}
-extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid);
static HeapTuple
GetTupleForTrigger(EState *estate, ItemPointer tid, TupleTableSlot **newSlot)
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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;
* 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);
}
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/* ----------------
* variables, macros and other stuff
- *
- * note CCSIZE allocates 51 buckets .. one was already allocated in
- * the catcache structure.
* ----------------
*/
/* ----------------
- * 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
}
/* ----------------
- * 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);
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.
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:
break;
default:
elog(FATAL, "CCComputeTupleHashIndex: %d cc_nkeys",
- cacheInOutP->cc_nkeys
- );
+ cacheInOutP->cc_nkeys);
break;
}
/* --------------------------------
* CatCacheRemoveCTup
+ *
+ * NB: assumes caller has switched to CacheCxt
* --------------------------------
*/
static void
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;
}
* ----------------
*/
MemoryContextSwitchTo(oldcxt);
- /* sendpm('I', "Invalidated tuple"); */
}
/* ----------------------------------------------------------------
*
* 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;
- }
}
/* --------------------------------
{
/*
* 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)
{
MemoryContext oldcxt;
/* ----------------
- * sanity checks
+ * one-time startup overhead
* ----------------
*/
if (cache->relationId == InvalidOid)
* 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
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;
*/
if (cache->busy)
- {
elog(ERROR, "SearchSysCache: recursive use of cache %d", cache->id);
- }
cache->busy = true;
/* ----------------
* 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;
*
*
* 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...
*
ResetSystemCaches()
{
ResetSystemCache();
- RelationCacheInvalidate(true);
+ RelationCacheInvalidate();
}
/* --------------------------------
*
*
* 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"
/*
* 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,
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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
#include "postgres.h"
-#include "utils/builtins.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/istrat.h"
#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
} 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);
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
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));
&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 = PointerGetDatum(textout((text *) DatumGetPointer(ruleaction)));
- rule_evqual_string = PointerGetDatum(textout((text *) DatumGetPointer(rule_evqual_string)));
-
- rule->actions = (List *) stringToNode(DatumGetPointer(ruleaction));
- rule->qual = (Node *) stringToNode(DatumGetPointer(rule_evqual_string));
-
- rules[numlocks++] = rule;
- if (numlocks == maxlocks)
+ ruleaction_str = textout((text *) DatumGetPointer(ruleaction));
+ rule->actions = (List *) stringToNode(ruleaction_str);
+ pfree(ruleaction_str);
+
+ 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);
+
+ if (numlocks >= maxlocks)
{
maxlocks *= 2;
rules = (RewriteRule **) repalloc(rules, sizeof(RewriteRule *) * maxlocks);
}
+ rules[numlocks++] = rule;
}
/* ----------------
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;
}
* ----------------
*/
if (OidIsValid(relam))
- relation->rd_am = (Form_pg_am) AccessMethodObjectIdGetForm(relam);
+ relation->rd_am = AccessMethodObjectIdGetForm(relam);
/* ----------------
* initialize the tuple descriptor (relation->rd_att).
* 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
/* 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;
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);
* 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);
}
/* --------------------------------
}
}
-/* --------------------------------
- * 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
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
if (relation->rd_rel->relkind == RELKIND_INDEX && /* XXX style */
(!OidIsValid(accessMethodId) ||
relation->rd_rel->relam == accessMethodId))
- RelationFlushRelation(&relation, true);
+ RelationFlushRelation(&relation, false);
}
#endif
/*
* 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);
}
/*
* 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);
}
/* 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++)
write_irels();
return;
}
-
- /*
- * p += sizeof(IndexStrategy); ((RegProcedure **) p) = support;
- */
-
ird->rd_support = support;
RelationInitLockInfo(ird);
* 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();
*
*
* 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
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
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
void
AtEOXact_portals()
{
- HashTableWalk(PortalHashTable, CollectNamedPortals, 0);
+ HashTableWalk(PortalHashTable, (HashtFunc) CollectNamedPortals, 0);
CollectNamedPortals(NULL, 1);
}
*/
#ifdef NOT_USED
static void
-PortalDump(Portal *thisP)
+PortalDump(Portal *thisP, int dummy)
{
/* XXX state/argument checking here */
{
/* XXX state checking here */
- HashTableWalk(PortalHashTable, PortalDump, 0);
+ HashTableWalk(PortalHashTable, (HashtFunc) PortalDump, 0);
}
#endif
/*
* Each portal must free its non-memory resources specially.
*/
- HashTableWalk(PortalHashTable, PortalDrop, 0);
+ HashTableWalk(PortalHashTable, (HashtFunc) PortalDrop, 0);
hash_destroy(PortalHashTable);
PortalHashTable = NULL;
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
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);
extern void FreeTupleDesc(TupleDesc tupdesc);
+extern bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);
+
extern bool TupleDescInitEntry(TupleDesc desc,
AttrNumber attributeNumber,
char *attributeName,
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "utils/hsearch.h"
-typedef void (*HashtFunc) ();
+typedef void (*HashtFunc) (void *hashitem, int arg);
extern void HashTableWalk(HTAB *hashtable, HashtFunc function, int arg);
/*-------------------------------------------------------------------------
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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.
typedef LockInfoData *LockInfo;
+/*
+ * Likewise, this struct really belongs to trigger.h, but for convenience
+ * we put it here.
+ */
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];
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
{
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;
#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.
/*
* RelationGetForm
- * Returns relation attribute values for a relation.
+ * Returns pg_class tuple for a relation.
*
* Note:
* Assumes relation descriptor is valid.
/*
* 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)
*
* 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), \
*/
#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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
/*
* 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);