]> granicus.if.org Git - postgresql/commitdiff
Fix problems seen in parallel regress tests when SI buffer overruns (causing
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 31 Jan 2000 04:35:57 +0000 (04:35 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 31 Jan 2000 04:35:57 +0000 (04:35 +0000)
syscache and relcache flushes).  Relcache entry rebuild now preserves
original tupledesc, rewrite rules, and triggers if possible, so that pointers
to these things remain valid --- if these things change while relcache entry
has positive refcount, we elog(ERROR) to avoid later crash.  Arrange for
xact-local rels to be rebuilt when an SI inval message is seen for them,
so that they are updated by CommandCounterIncrement the same as regular rels.
(This is useful because of Hiroshi's recent changes to process our own SI
messages at CommandCounterIncrement time.)  This allows simplification of
some routines that previously hacked around the lack of an automatic update.
catcache now keeps its own copy of tupledesc for its relation, rather than
depending on the relcache's copy; this avoids needing to reinitialize catcache
during a cache flush, which saves some cycles and eliminates nasty circularity
problems that occur if a cache flush happens while trying to initialize a
catcache.
Eliminate a number of permanent memory leaks that used to happen during
catcache or relcache flush; not least of which was that catcache never
freed any cached tuples!  (Rule parsetree storage is still leaked, however;
will fix that separately.)
Nothing done yet about code that uses tuples retrieved by SearchSysCache
for longer than is safe.

15 files changed:
src/backend/access/common/tupdesc.c
src/backend/catalog/heap.c
src/backend/commands/trigger.c
src/backend/lib/hasht.c
src/backend/utils/cache/catcache.c
src/backend/utils/cache/inval.c
src/backend/utils/cache/rel.c
src/backend/utils/cache/relcache.c
src/backend/utils/mmgr/aset.c
src/backend/utils/mmgr/portalmem.c
src/include/access/tupdesc.h
src/include/commands/trigger.h
src/include/lib/hasht.h
src/include/utils/rel.h
src/include/utils/relcache.h

index 567fcab1cd8e7c128714972c75036293bb6e8343..b2af4ff932ecac4ba53f1dd9e78e9b8b04e5bd1e 100644 (file)
@@ -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
  *
index 79957e7e8c2eeb15227c304940cae208dd382457..89c20ce5fa70ec2023087dceeba0f4ff39bce5ef 100644 (file)
@@ -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
index 86bacf1be5c14b4ee7f44a4645851445c4e3554b..f3c919a1ed9ac506564af98a30d7ce0133571878 100644 (file)
@@ -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"
 
 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)
index ad3aa660e27445bc0be9c191aa436d8f2ed4b3ef..5caeabd281ab3530dea037a2827f9622677be8d2 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
  *             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);
        }
 }
index e5e22a7ab31ad857f2d1f5cdd187c738c6792fdd..f96a3956053159c4aad44a15de66b27718aea066 100644 (file)
@@ -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;
index 473978bd410343e3bc3d68e4d2aab4fab1dd852d..17071f8e2352849c3da6a0a9557888f4121589e9 100644 (file)
@@ -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();
 }
 
 /* --------------------------------
index d24c1ca0c9cfa1c0b2cd8d9a74d005aaff941e87..50edb4224684db452848232b3e7ac86a41bf56e5 100644 (file)
@@ -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"
 /*
  *             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,
index 4a6c86d84d9f60e745aa160fa3e489c7a1ee3456..7c993d3d73f12c6c675ffe608bc55d60c1fbe488 100644 (file)
@@ -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"
 #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 = 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;
        }
 
        /* ----------------
@@ -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();
index 1ee38a928b0e999db02a74cc19ddd263637a0c9b..afc6da38eb4c771e5fa04dd400e4573d4c7d0563 100644 (file)
@@ -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
index f19e1c2d468c5b044478f61d4e3078a3e7d3c47e..78da0bc9edb95d0e5ebda9f3c9a37acfc183f93d 100644 (file)
@@ -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;
 
index 727fee212aa96de53b57e1eccf746245f750073e..525cd6267e114e904d9bbd1ab1f1becddf774518 100644 (file)
@@ -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,
index ddb9f7ca5b45e160bdcd1f0ceb9058b56d745b25..b2c258c2f8322d44aa2250a52d15c4a8ca9fab46 100644 (file)
@@ -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);
index 6f64022e23ae3fabd4070fa5de73d81f5a051ed3..78318f954d46592506ff6e5df3ba2636e7fef722 100644 (file)
@@ -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);
 
index 867ffa604d5ba3208b094f33b49388b9131078db..c8238008021160a5d637d1f40c9038e9ad3b8c5e 100644 (file)
@@ -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 */
index cb14e1b6d3d0476fb2421170bafe0a868036c93e..073c846e4b304ce46b61beac96b98bf7c05c1534 100644 (file)
@@ -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);