]> granicus.if.org Git - postgresql/commitdiff
A bunch of changes aimed at reducing backend startup time...
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 19 Feb 2002 20:11:20 +0000 (20:11 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 19 Feb 2002 20:11:20 +0000 (20:11 +0000)
Improve 'pg_internal.init' relcache entry preload mechanism so that it is
safe to use for all system catalogs, and arrange to preload a realistic
set of system-catalog entries instead of only the three nailed-in-cache
indexes that were formerly loaded this way.  Fix mechanism for deleting
out-of-date pg_internal.init files: this must be synchronized with transaction
commit, not just done at random times within transactions.  Drive it off
relcache invalidation mechanism so that no special-case tests are needed.

Cache additional information in relcache entries for indexes (their pg_index
tuples and index-operator OIDs) to eliminate repeated lookups.  Also cache
index opclass info at the per-opclass level to avoid repeated lookups during
relcache load.

Generalize 'systable scan' utilities originally developed by Hiroshi,
move them into genam.c, use in a number of places where there was formerly
ugly code for choosing either heap or index scan.  In particular this allows
simplification of the logic that prevents infinite recursion between syscache
and relcache during startup: we can easily switch to heapscans in relcache.c
when and where needed to avoid recursion, so IndexScanOK becomes simpler and
does not need any expensive initialization.

Eliminate useless opening of a heapscan data structure while doing an indexscan
(this saves an mdnblocks call and thus at least one kernel call).

33 files changed:
src/backend/access/index/genam.c
src/backend/access/index/istrat.c
src/backend/catalog/heap.c
src/backend/catalog/index.c
src/backend/catalog/indexing.c
src/backend/commands/cluster.c
src/backend/commands/command.c
src/backend/commands/trigger.c
src/backend/commands/vacuum.c
src/backend/executor/execAmi.c
src/backend/executor/execUtils.c
src/backend/executor/nodeIndexscan.c
src/backend/executor/nodeSeqscan.c
src/backend/executor/nodeTidscan.c
src/backend/optimizer/util/plancat.c
src/backend/parser/parse_func.c
src/backend/parser/parse_oper.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/cache/catcache.c
src/backend/utils/cache/inval.c
src/backend/utils/cache/relcache.c
src/backend/utils/cache/syscache.c
src/backend/utils/init/postinit.c
src/include/access/genam.h
src/include/access/istrat.h
src/include/catalog/index.h
src/include/catalog/indexing.h
src/include/executor/executor.h
src/include/storage/lwlock.h
src/include/utils/catcache.h
src/include/utils/rel.h
src/include/utils/relcache.h
src/include/utils/syscache.h

index 5c3a6dc81ce890f514bcfba8f124a5a71668b9ca..e36a1450db38f08b61c8b2a5075c71e126da53ff 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.30 2001/10/28 06:25:41 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.31 2002/02/19 20:11:10 tgl Exp $
  *
  * NOTES
  *       many of the old access method routines have been turned into
  *             next item pointer using the flags.
  * ----------------------------------------------------------------
  */
-
 #include "postgres.h"
-#include "access/genam.h"
 
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "miscadmin.h"
 #include "pgstat.h"
 
+
 /* ----------------------------------------------------------------
  *             general access method routines
  *
@@ -242,3 +244,156 @@ IndexScanRestorePosition(IndexScanDesc scan)
 }
 
 #endif
+
+
+/* ----------------------------------------------------------------
+ *             heap-or-index-scan access to system catalogs
+ *
+ *             These functions support system catalog accesses that normally use
+ *             an index but need to be capable of being switched to heap scans
+ *             if the system indexes are unavailable.  The interface is
+ *             as easy to use as a heap scan, and hides all the extra cruft of
+ *             the present indexscan API.
+ *
+ *             The specified scan keys must be compatible with the named index.
+ *             Generally this means that they must constrain either all columns
+ *             of the index, or the first K columns of an N-column index.
+ *
+ *             These routines would work fine with non-system tables, actually,
+ *             but they're only useful when there is a known index to use with
+ *             the given scan keys, so in practice they're only good for
+ *             predetermined types of scans of system catalogs.
+ * ----------------------------------------------------------------
+ */
+
+/*
+ * systable_beginscan --- set up for heap-or-index scan
+ *
+ *     rel: catalog to scan, already opened and suitably locked
+ *     indexRelname: name of index to conditionally use
+ *     indexOK: if false, forces a heap scan (see notes below)
+ *     snapshot: time qual to use (usually should be SnapshotNow)
+ *     nkeys, key: scan keys
+ *
+ * The attribute numbers in the scan key should be set for the heap case.
+ * If we choose to index, we reset them to 1..n to reference the index
+ * columns.  Note this means there must be one scankey qualification per
+ * index column!  This is checked by the Asserts in the normal, index-using
+ * case, but won't be checked if the heapscan path is taken.
+ *
+ * The routine checks the normal cases for whether an indexscan is safe,
+ * but caller can make additional checks and pass indexOK=false if needed.
+ * In standard case indexOK can simply be constant TRUE.
+ */
+SysScanDesc
+systable_beginscan(Relation rel,
+                                  const char *indexRelname,
+                                  bool indexOK,
+                                  Snapshot snapshot,
+                                  unsigned nkeys, ScanKey key)
+{
+       SysScanDesc sysscan;
+
+       sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData));
+       sysscan->heap_rel = rel;
+       sysscan->snapshot = snapshot;
+       sysscan->tuple.t_datamcxt = NULL;
+       sysscan->tuple.t_data = NULL;
+       sysscan->buffer = InvalidBuffer;
+
+       if (indexOK &&
+               rel->rd_rel->relhasindex &&
+               !IsIgnoringSystemIndexes())
+       {
+               Relation        irel;
+               unsigned        i;
+
+               sysscan->irel = irel = index_openr(indexRelname);
+               /*
+                * Change attribute numbers to be index column numbers.
+                *
+                * This code could be generalized to search for the index key numbers
+                * to substitute, but for now there's no need.
+                */
+               for (i = 0; i < nkeys; i++)
+               {
+                       Assert(key[i].sk_attno == irel->rd_index->indkey[i]);
+                       key[i].sk_attno = i+1;
+               }
+               sysscan->iscan = index_beginscan(irel, false, nkeys, key);
+               sysscan->scan = NULL;
+       }
+       else
+       {
+               sysscan->irel = (Relation) NULL;
+               sysscan->scan = heap_beginscan(rel, false, snapshot, nkeys, key);
+               sysscan->iscan = NULL;
+       }
+
+       return sysscan;
+}
+
+/*
+ * systable_getnext --- get next tuple in a heap-or-index scan
+ *
+ * Returns NULL if no more tuples available.
+ *
+ * Note that returned tuple is a reference to data in a disk buffer;
+ * it must not be modified, and should be presumed inaccessible after
+ * next getnext() or endscan() call.
+ */
+HeapTuple
+systable_getnext(SysScanDesc sysscan)
+{
+       HeapTuple       htup = (HeapTuple) NULL;
+
+       if (sysscan->irel)
+       {
+               RetrieveIndexResult indexRes;
+
+               if (BufferIsValid(sysscan->buffer))
+               {
+                       ReleaseBuffer(sysscan->buffer);
+                       sysscan->buffer = InvalidBuffer;
+               }
+
+               while ((indexRes = index_getnext(sysscan->iscan, ForwardScanDirection)) != NULL)
+               {
+                       sysscan->tuple.t_self = indexRes->heap_iptr;
+                       pfree(indexRes);
+                       heap_fetch(sysscan->heap_rel, sysscan->snapshot,
+                                          &sysscan->tuple, &sysscan->buffer,
+                                          sysscan->iscan);
+                       if (sysscan->tuple.t_data != NULL)
+                       {
+                               htup = &sysscan->tuple;
+                               break;
+                       }
+               }
+       }
+       else
+               htup = heap_getnext(sysscan->scan, 0);
+
+       return htup;
+}
+
+/*
+ * systable_endscan --- close scan, release resources
+ *
+ * Note that it's still up to the caller to close the heap relation.
+ */
+void
+systable_endscan(SysScanDesc sysscan)
+{
+       if (sysscan->irel)
+       {
+               if (BufferIsValid(sysscan->buffer))
+                       ReleaseBuffer(sysscan->buffer);
+               index_endscan(sysscan->iscan);
+               index_close(sysscan->irel);
+       }
+       else
+               heap_endscan(sysscan->scan);
+
+       pfree(sysscan);
+}
index 9e0fb8fe13371fb5ec5d823c8bb971022c6caf43..9366534bbac439bdefac895cde9828a1ef410e7b 100644 (file)
@@ -9,29 +9,19 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.56 2001/11/05 17:46:24 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.57 2002/02/19 20:11:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
-#include "access/heapam.h"
 #include "access/istrat.h"
-#include "catalog/catname.h"
-#include "catalog/pg_amop.h"
-#include "catalog/pg_amproc.h"
-#include "catalog/pg_index.h"
-#include "catalog/pg_operator.h"
-#include "miscadmin.h"
-#include "utils/fmgroids.h"
-#include "utils/syscache.h"
+
 
 #ifdef USE_ASSERT_CHECKING
 static bool StrategyEvaluationIsValid(StrategyEvaluation evaluation);
 static bool StrategyExpressionIsValid(StrategyExpression expression,
                                                  StrategyNumber maxStrategy);
-static ScanKey StrategyMapGetScanKeyEntry(StrategyMap map,
-                                                  StrategyNumber strategyNumber);
 static bool StrategyOperatorIsValid(StrategyOperator operator,
                                                StrategyNumber maxStrategy);
 static bool StrategyTermIsValid(StrategyTerm term,
@@ -63,7 +53,7 @@ static bool StrategyTermIsValid(StrategyTerm term,
  *             Assumes that the index strategy number is valid.
  *             Bounds checking should be done outside this routine.
  */
-static ScanKey
+ScanKey
 StrategyMapGetScanKeyEntry(StrategyMap map,
                                                   StrategyNumber strategyNumber)
 {
@@ -453,161 +443,6 @@ RelationInvokeStrategy(Relation relation,
 }
 #endif
 
-/* ----------------
- *             FillScanKeyEntry
- *
- * Initialize a ScanKey entry for the given operator OID.
- * ----------------
- */
-static void
-FillScanKeyEntry(Oid operatorObjectId, ScanKey entry)
-{
-       HeapTuple       tuple;
-
-       tuple = SearchSysCache(OPEROID,
-                                                  ObjectIdGetDatum(operatorObjectId),
-                                                  0, 0, 0);
-
-       if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "FillScanKeyEntry: unknown operator %u",
-                        operatorObjectId);
-
-       MemSet(entry, 0, sizeof(*entry));
-       entry->sk_flags = 0;
-       entry->sk_procedure = ((Form_pg_operator) GETSTRUCT(tuple))->oprcode;
-
-       ReleaseSysCache(tuple);
-
-       if (!RegProcedureIsValid(entry->sk_procedure))
-               elog(ERROR, "FillScanKeyEntry: no procedure for operator %u",
-                        operatorObjectId);
-
-       /*
-        * Mark entry->sk_func invalid, until and unless someone sets it up.
-        */
-       entry->sk_func.fn_oid = InvalidOid;
-}
-
-
-/*
- * IndexSupportInitialize
- *             Initializes an index strategy and associated support procedures.
- *
- * Data is returned into *indexStrategy, *indexSupport, and *isUnique,
- * all of which are objects allocated by the caller.
- *
- * The primary input keys are indexObjectId and accessMethodObjectId.
- * The caller also passes maxStrategyNumber, maxSupportNumber, and
- * maxAttributeNumber, since these indicate the size of the indexStrategy
- * and indexSupport arrays it has allocated --- but in practice these
- * numbers must always match those obtainable from the system catalog
- * entries for the index and access method.
- */
-void
-IndexSupportInitialize(IndexStrategy indexStrategy,
-                                          RegProcedure *indexSupport,
-                                          bool *isUnique,
-                                          Oid indexObjectId,
-                                          Oid accessMethodObjectId,
-                                          StrategyNumber maxStrategyNumber,
-                                          StrategyNumber maxSupportNumber,
-                                          AttrNumber maxAttributeNumber)
-{
-       HeapTuple       tuple;
-       Form_pg_index iform;
-       int                     attIndex;
-       Oid                     operatorClassObjectId[INDEX_MAX_KEYS];
-
-       maxStrategyNumber = AMStrategies(maxStrategyNumber);
-
-       tuple = SearchSysCache(INDEXRELID,
-                                                  ObjectIdGetDatum(indexObjectId),
-                                                  0, 0, 0);
-       if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "IndexSupportInitialize: no pg_index entry for index %u",
-                        indexObjectId);
-       iform = (Form_pg_index) GETSTRUCT(tuple);
-
-       *isUnique = iform->indisunique;
-
-       /*
-        * XXX note that the following assumes the INDEX tuple is well formed
-        * and that the *key and *class are 0 terminated.
-        */
-       for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
-       {
-               if (iform->indkey[attIndex] == InvalidAttrNumber ||
-                       !OidIsValid(iform->indclass[attIndex]))
-                       elog(ERROR, "IndexSupportInitialize: bogus pg_index tuple");
-               operatorClassObjectId[attIndex] = iform->indclass[attIndex];
-       }
-
-       ReleaseSysCache(tuple);
-
-       /* if support routines exist for this access method, load them */
-       if (maxSupportNumber > 0)
-       {
-               for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
-               {
-                       Oid                     opclass = operatorClassObjectId[attIndex];
-                       RegProcedure *loc;
-                       StrategyNumber support;
-
-                       loc = &indexSupport[attIndex * maxSupportNumber];
-
-                       for (support = 0; support < maxSupportNumber; ++support)
-                       {
-                               tuple = SearchSysCache(AMPROCNUM,
-                                                                          ObjectIdGetDatum(opclass),
-                                                                          Int16GetDatum(support + 1),
-                                                                          0, 0);
-                               if (HeapTupleIsValid(tuple))
-                               {
-                                       Form_pg_amproc amprocform;
-
-                                       amprocform = (Form_pg_amproc) GETSTRUCT(tuple);
-                                       loc[support] = amprocform->amproc;
-                                       ReleaseSysCache(tuple);
-                               }
-                               else
-                                       loc[support] = InvalidOid;
-                       }
-               }
-       }
-
-       /* Now load the strategy information for the index operators */
-       for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
-       {
-               Oid                     opclass = operatorClassObjectId[attIndex];
-               StrategyMap map;
-               StrategyNumber strategy;
-
-               map = IndexStrategyGetStrategyMap(indexStrategy,
-                                                                                 maxStrategyNumber,
-                                                                                 attIndex + 1);
-
-               for (strategy = 1; strategy <= maxStrategyNumber; strategy++)
-               {
-                       ScanKey         mapentry = StrategyMapGetScanKeyEntry(map, strategy);
-
-                       tuple = SearchSysCache(AMOPSTRATEGY,
-                                                                  ObjectIdGetDatum(opclass),
-                                                                  Int16GetDatum(strategy),
-                                                                  0, 0);
-                       if (HeapTupleIsValid(tuple))
-                       {
-                               Form_pg_amop amopform;
-
-                               amopform = (Form_pg_amop) GETSTRUCT(tuple);
-                               FillScanKeyEntry(amopform->amopopr, mapentry);
-                               ReleaseSysCache(tuple);
-                       }
-                       else
-                               ScanKeyEntrySetIllegal(mapentry);
-               }
-       }
-}
-
 /* ----------------
  *             IndexStrategyDisplay
  * ----------------
index 809702ddec900014d89c9e1fa7295dcf4964341b..ad192dca5082372ad8a74ac650ce74b088bedea7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.181 2001/11/12 00:00:55 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.182 2002/02/19 20:11:11 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -912,32 +912,21 @@ RelationRemoveInheritance(Relation relation)
 static void
 RelationRemoveIndexes(Relation relation)
 {
-       Relation        indexRelation;
-       HeapTuple       tuple;
-       HeapScanDesc scan;
-       ScanKeyData entry;
-
-       indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
+       List       *indexoidlist,
+                          *indexoidscan;
 
-       ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_index_indrelid,
-                                                  F_OIDEQ,
-                                                  ObjectIdGetDatum(RelationGetRelid(relation)));
-
-       scan = heap_beginscan(indexRelation,
-                                                 false,
-                                                 SnapshotNow,
-                                                 1,
-                                                 &entry);
+       indexoidlist = RelationGetIndexList(relation);
 
-       while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
+       foreach(indexoidscan, indexoidlist)
        {
-               index_drop(((Form_pg_index) GETSTRUCT(tuple))->indexrelid);
+               Oid                     indexoid = lfirsti(indexoidscan);
+
+               index_drop(indexoid);
                /* advance cmd counter to make catalog changes visible */
                CommandCounterIncrement();
        }
 
-       heap_endscan(scan);
-       heap_close(indexRelation, RowExclusiveLock);
+       freeList(indexoidlist);
 }
 
 /* --------------------------------
@@ -984,17 +973,21 @@ RelationTruncateIndexes(Oid heapId)
 {
        Relation        indexRelation;
        ScanKeyData entry;
-       HeapScanDesc scan;
+       SysScanDesc     scan;
        HeapTuple       indexTuple;
 
        /* Scan pg_index to find indexes on specified heap */
        indexRelation = heap_openr(IndexRelationName, AccessShareLock);
-       ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, F_OIDEQ,
+       ScanKeyEntryInitialize(&entry, 0,
+                                                  Anum_pg_index_indrelid,
+                                                  F_OIDEQ,
                                                   ObjectIdGetDatum(heapId));
-       scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
+       scan = systable_beginscan(indexRelation, IndexIndrelidIndex, true,
+                                                         SnapshotNow, 1, &entry);
 
-       while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
+       while (HeapTupleIsValid(indexTuple = systable_getnext(scan)))
        {
+               Form_pg_index indexform = (Form_pg_index) GETSTRUCT(indexTuple);
                Oid                     indexId;
                IndexInfo  *indexInfo;
                Relation        heapRelation,
@@ -1003,8 +996,8 @@ RelationTruncateIndexes(Oid heapId)
                /*
                 * For each index, fetch info needed for index_build
                 */
-               indexId = ((Form_pg_index) GETSTRUCT(indexTuple))->indexrelid;
-               indexInfo = BuildIndexInfo(indexTuple);
+               indexId = indexform->indexrelid;
+               indexInfo = BuildIndexInfo(indexform);
 
                /*
                 * We have to re-open the heap rel each time through this loop
@@ -1041,7 +1034,7 @@ RelationTruncateIndexes(Oid heapId)
        }
 
        /* Complete the scan and close pg_index */
-       heap_endscan(scan);
+       systable_endscan(scan);
        heap_close(indexRelation, AccessShareLock);
 }
 
index ed57db68707e1c346840cceccdf47d75c4b8feea..bd6bd1de38aa56675c768a17bae1b2c761fc3af9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.171 2002/01/06 00:37:44 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.172 2002/02/19 20:11:11 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -333,67 +333,6 @@ ConstructTupleDescriptor(Relation heapRelation,
        return indexTupDesc;
 }
 
-/* ----------------------------------------------------------------
- * AccessMethodObjectIdGetForm
- *             Returns an access method tuple given its object identifier,
- *             or NULL if no such AM tuple can be found.
- *
- * Scanning is done using CurrentMemoryContext as working storage,
- * but the returned tuple will be allocated in resultCxt (which is
- * typically CacheMemoryContext).
- *
- * There was a note here about adding indexing, but I don't see a need
- * for it.     There are so few tuples in pg_am that an indexscan would
- * surely be slower.
- * ----------------------------------------------------------------
- */
-Form_pg_am
-AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
-                                                       MemoryContext resultCxt)
-{
-       Relation        pg_am_desc;
-       HeapScanDesc pg_am_scan;
-       HeapTuple       pg_am_tuple;
-       ScanKeyData key;
-       Form_pg_am      aform;
-
-       /*
-        * form a scan key for the pg_am relation
-        */
-       ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
-                                                  F_OIDEQ,
-                                                  ObjectIdGetDatum(accessMethodObjectId));
-
-       /*
-        * fetch the desired access method tuple
-        */
-       pg_am_desc = heap_openr(AccessMethodRelationName, AccessShareLock);
-       pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
-
-       pg_am_tuple = heap_getnext(pg_am_scan, 0);
-
-       /*
-        * return NULL if not found
-        */
-       if (!HeapTupleIsValid(pg_am_tuple))
-       {
-               heap_endscan(pg_am_scan);
-               heap_close(pg_am_desc, AccessShareLock);
-               return NULL;
-       }
-
-       /*
-        * if found AM tuple, then copy it into resultCxt and return the copy
-        */
-       aform = (Form_pg_am) MemoryContextAlloc(resultCxt, sizeof *aform);
-       memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
-
-       heap_endscan(pg_am_scan);
-       heap_close(pg_am_desc, AccessShareLock);
-
-       return aform;
-}
-
 /* ----------------------------------------------------------------
  *             ConstructIndexReldesc
  * ----------------------------------------------------------------
@@ -401,12 +340,6 @@ AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
 static void
 ConstructIndexReldesc(Relation indexRelation, Oid amoid)
 {
-       /*
-        * Fill in a copy of relevant pg_am entry
-        */
-       indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
-                                                                                                        CacheMemoryContext);
-
        /*
         * Set up some additional fields of the index' pg_class entry. In
         * particular, initialize knowledge of whether the index is shared.
@@ -953,9 +886,8 @@ index_drop(Oid indexId)
  * ----------------
  */
 IndexInfo *
-BuildIndexInfo(HeapTuple indexTuple)
+BuildIndexInfo(Form_pg_index indexStruct)
 {
-       Form_pg_index indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
        IndexInfo  *ii = makeNode(IndexInfo);
        int                     i;
        int                     numKeys;
@@ -1337,9 +1269,6 @@ setNewRelfilenode(Relation relation)
        }
        /* schedule unlinking old relfilenode */
        smgrunlink(DEFAULT_SMGR, relation);
-       /* cleanup pg_internal.init if necessary */
-       if (relation->rd_isnailed)
-               unlink(RELCACHE_INIT_FILENAME);
        /* create another storage file. Is it a little ugly ? */
        memcpy((char *) &workrel, relation, sizeof(RelationData));
        workrel.rd_node.relNode = newrelfilenode;
@@ -1863,11 +1792,7 @@ bool
 reindex_index(Oid indexId, bool force, bool inplace)
 {
        Relation        iRel,
-                               indexRelation,
                                heapRelation;
-       ScanKeyData entry;
-       HeapScanDesc scan;
-       HeapTuple       indexTuple;
        IndexInfo  *indexInfo;
        Oid                     heapId;
        bool            old;
@@ -1899,23 +1824,10 @@ reindex_index(Oid indexId, bool force, bool inplace)
 
        old = SetReindexProcessing(true);
 
-       /* Scan pg_index to find the index's pg_index entry */
-       indexRelation = heap_openr(IndexRelationName, AccessShareLock);
-       ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indexrelid, F_OIDEQ,
-                                                  ObjectIdGetDatum(indexId));
-       scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
-       indexTuple = heap_getnext(scan, 0);
-       if (!HeapTupleIsValid(indexTuple))
-               elog(ERROR, "reindex_index: index %u not found in pg_index", indexId);
-
        /* Get OID of index's parent table */
-       heapId = ((Form_pg_index) GETSTRUCT(indexTuple))->indrelid;
+       heapId = iRel->rd_index->indrelid;
        /* Fetch info needed for index_build */
-       indexInfo = BuildIndexInfo(indexTuple);
-
-       /* Complete the scan and close pg_index */
-       heap_endscan(scan);
-       heap_close(indexRelation, AccessShareLock);
+       indexInfo = BuildIndexInfo(iRel->rd_index);
 
        /* Open the parent heap relation */
        heapRelation = heap_open(heapId, ExclusiveLock);
index 28b8516947354dcb2c02cad2b391265fdf9ad505..e600eab6a30e3e0ac640b20410c6bda26f019f95 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.82 2001/08/21 16:36:01 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.83 2002/02/19 20:11:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -80,12 +80,6 @@ char    *Name_pg_description_indices[Num_pg_description_indices] =
 
 
 
-static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
-                                          Relation idesc,
-                                          ScanKey skey,
-                                          int16 num_keys);
-
-
 /*
  * Changes (appends) to catalogs can and do happen at various places
  * throughout the code.  We need a generic routine that will open all of
@@ -151,18 +145,10 @@ CatalogIndexInsert(Relation *idescs,
 
        for (i = 0; i < nIndices; i++)
        {
-               HeapTuple       index_tup;
                IndexInfo  *indexInfo;
                InsertIndexResult indexRes;
 
-               index_tup = SearchSysCache(INDEXRELID,
-                                                                  ObjectIdGetDatum(idescs[i]->rd_id),
-                                                                  0, 0, 0);
-               if (!HeapTupleIsValid(index_tup))
-                       elog(ERROR, "CatalogIndexInsert: index %u not found",
-                                idescs[i]->rd_id);
-               indexInfo = BuildIndexInfo(index_tup);
-               ReleaseSysCache(index_tup);
+               indexInfo = BuildIndexInfo(idescs[i]->rd_index);
 
                FormIndexDatum(indexInfo,
                                           heapTuple,
@@ -178,127 +164,3 @@ CatalogIndexInsert(Relation *idescs,
                pfree(indexInfo);
        }
 }
-
-
-/*
- *     CatalogIndexFetchTuple() -- Get a tuple that satisfies a scan key
- *                                                             from a catalog relation.
- *
- *             Since the index may contain pointers to dead tuples, we need to
- *             iterate until we find a tuple that's valid and satisfies the scan
- *             key.
- */
-static HeapTuple
-CatalogIndexFetchTuple(Relation heapRelation,
-                                          Relation idesc,
-                                          ScanKey skey,
-                                          int16 num_keys)
-{
-       IndexScanDesc sd;
-       RetrieveIndexResult indexRes;
-       HeapTupleData tuple;
-       HeapTuple       result = NULL;
-       Buffer          buffer;
-
-       sd = index_beginscan(idesc, false, num_keys, skey);
-       tuple.t_datamcxt = CurrentMemoryContext;
-       tuple.t_data = NULL;
-       while ((indexRes = index_getnext(sd, ForwardScanDirection)))
-       {
-               tuple.t_self = indexRes->heap_iptr;
-               heap_fetch(heapRelation, SnapshotNow, &tuple, &buffer, sd);
-               pfree(indexRes);
-               if (tuple.t_data != NULL)
-                       break;
-       }
-
-       if (tuple.t_data != NULL)
-       {
-               result = heap_copytuple(&tuple);
-               ReleaseBuffer(buffer);
-       }
-
-       index_endscan(sd);
-
-       return result;
-}
-
-
-/*---------------------------------------------------------------------
- *                                              Class-specific index lookups
- *---------------------------------------------------------------------
- */
-
-/*
- * The remainder of the file is for individual index scan routines.
- * These routines provide canned scanning code for certain widely-used
- * indexes.  Most indexes don't need one of these.
- */
-
-
-HeapTuple
-AttributeRelidNumIndexScan(Relation heapRelation,
-                                                  Datum relid,
-                                                  Datum attnum)
-{
-       Relation        idesc;
-       ScanKeyData skey[2];
-       HeapTuple       tuple;
-
-       ScanKeyEntryInitialize(&skey[0],
-                                                  (bits16) 0x0,
-                                                  (AttrNumber) 1,
-                                                  (RegProcedure) F_OIDEQ,
-                                                  relid);
-
-       ScanKeyEntryInitialize(&skey[1],
-                                                  (bits16) 0x0,
-                                                  (AttrNumber) 2,
-                                                  (RegProcedure) F_INT2EQ,
-                                                  attnum);
-
-       idesc = index_openr(AttributeRelidNumIndex);
-       tuple = CatalogIndexFetchTuple(heapRelation, idesc, skey, 2);
-       index_close(idesc);
-       return tuple;
-}
-
-
-HeapTuple
-ClassNameIndexScan(Relation heapRelation, Datum relName)
-{
-       Relation        idesc;
-       ScanKeyData skey[1];
-       HeapTuple       tuple;
-
-       ScanKeyEntryInitialize(&skey[0],
-                                                  (bits16) 0x0,
-                                                  (AttrNumber) 1,
-                                                  (RegProcedure) F_NAMEEQ,
-                                                  relName);
-
-       idesc = index_openr(ClassNameIndex);
-       tuple = CatalogIndexFetchTuple(heapRelation, idesc, skey, 1);
-       index_close(idesc);
-       return tuple;
-}
-
-
-HeapTuple
-ClassOidIndexScan(Relation heapRelation, Datum relId)
-{
-       Relation        idesc;
-       ScanKeyData skey[1];
-       HeapTuple       tuple;
-
-       ScanKeyEntryInitialize(&skey[0],
-                                                  (bits16) 0x0,
-                                                  (AttrNumber) 1,
-                                                  (RegProcedure) F_OIDEQ,
-                                                  relId);
-
-       idesc = index_openr(ClassOidIndex);
-       tuple = CatalogIndexFetchTuple(heapRelation, idesc, skey, 1);
-       index_close(idesc);
-       return tuple;
-}
index 663a2b22008b4c8cf4fbc12c6feb43394a2c5082..f37394874264a6279565bf3a96cd3b01b08dea52 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.71 2002/01/06 00:37:44 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.72 2002/02/19 20:11:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,7 +61,6 @@ cluster(char *oldrelname, char *oldindexname)
                                OIDNewHeap;
        Relation        OldHeap,
                                OldIndex;
-       HeapTuple       tuple;
        bool            istemp;
        char            NewHeapName[NAMEDATALEN];
        char            NewIndexName[NAMEDATALEN];
@@ -90,16 +89,9 @@ cluster(char *oldrelname, char *oldindexname)
        /*
         * Check that index is in fact an index on the given relation
         */
-       tuple = SearchSysCache(INDEXRELID,
-                                                  ObjectIdGetDatum(OIDOldIndex),
-                                                  0, 0, 0);
-       if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "CLUSTER: no pg_index entry for index %u",
-                        OIDOldIndex);
-       if (((Form_pg_index) GETSTRUCT(tuple))->indrelid != OIDOldHeap)
+       if (OldIndex->rd_index->indrelid != OIDOldHeap)
                elog(ERROR, "CLUSTER: \"%s\" is not an index for table \"%s\"",
                         saveoldindexname, saveoldrelname);
-       ReleaseSysCache(tuple);
 
        /* Drop relcache refcnts, but do NOT give up the locks */
        heap_close(OldHeap, NoLock);
@@ -188,10 +180,6 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName)
 {
        Relation        OldIndex,
                                NewHeap;
-       HeapTuple       Old_pg_index_Tuple,
-                               Old_pg_index_relation_Tuple;
-       Form_pg_index Old_pg_index_Form;
-       Form_pg_class Old_pg_index_relation_Form;
        IndexInfo  *indexInfo;
 
        NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
@@ -206,33 +194,18 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName)
         * its parent table is, so we don't need to do anything special for
         * the temp-table case here.
         */
-       Old_pg_index_Tuple = SearchSysCache(INDEXRELID,
-                                                                               ObjectIdGetDatum(OIDOldIndex),
-                                                                               0, 0, 0);
-       Assert(Old_pg_index_Tuple);
-       Old_pg_index_Form = (Form_pg_index) GETSTRUCT(Old_pg_index_Tuple);
-
-       indexInfo = BuildIndexInfo(Old_pg_index_Tuple);
-
-       Old_pg_index_relation_Tuple = SearchSysCache(RELOID,
-                                                                                  ObjectIdGetDatum(OIDOldIndex),
-                                                                                                0, 0, 0);
-       Assert(Old_pg_index_relation_Tuple);
-       Old_pg_index_relation_Form = (Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple);
+       indexInfo = BuildIndexInfo(OldIndex->rd_index);
 
        index_create(RelationGetRelationName(NewHeap),
                                 NewIndexName,
                                 indexInfo,
-                                Old_pg_index_relation_Form->relam,
-                                Old_pg_index_Form->indclass,
-                                Old_pg_index_Form->indisprimary,
+                                OldIndex->rd_rel->relam,
+                                OldIndex->rd_index->indclass,
+                                OldIndex->rd_index->indisprimary,
                                 allowSystemTableMods);
 
        setRelhasindex(OIDNewHeap, true,
-                                  Old_pg_index_Form->indisprimary, InvalidOid);
-
-       ReleaseSysCache(Old_pg_index_Tuple);
-       ReleaseSysCache(Old_pg_index_relation_Tuple);
+                                  OldIndex->rd_index->indisprimary, InvalidOid);
 
        index_close(OldIndex);
        heap_close(NewHeap, NoLock);
index 9b1a33673c737eb2b7012f92ee8018bed7ef136c..f01cf4498fdd88bcdb8f95d3e257543394436429 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.153 2002/02/14 15:24:06 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.154 2002/02/19 20:11:12 tgl Exp $
  *
  * NOTES
  *       The PerformAddAttribute() code, like most of the relation
@@ -29,6 +29,7 @@
 #include "catalog/pg_attrdef.h"
 #include "catalog/pg_index.h"
 #include "catalog/pg_opclass.h"
+#include "catalog/pg_relcheck.h"
 #include "catalog/pg_type.h"
 #include "commands/command.h"
 #include "commands/trigger.h"
@@ -820,92 +821,8 @@ AlterTableAlterColumnStatistics(const char *relationName,
 #ifdef _DROP_COLUMN_HACK__
 /*
  *     ALTER TABLE DROP COLUMN trial implementation
- *
  */
 
-/*
- *     system table scan(index scan/sequential scan)
- */
-typedef struct SysScanDescData
-{
-       Relation        heap_rel;
-       Relation        irel;
-       HeapScanDesc scan;
-       IndexScanDesc iscan;
-       HeapTupleData tuple;
-       Buffer          buffer;
-}      SysScanDescData, *SysScanDesc;
-
-static void *
-systable_beginscan(Relation rel, const char *indexRelname, int nkeys, ScanKey entry)
-{
-       bool            hasindex = (rel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
-       SysScanDesc sysscan;
-
-       sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData));
-       sysscan->heap_rel = rel;
-       sysscan->irel = (Relation) NULL;
-       sysscan->tuple.t_datamcxt = NULL;
-       sysscan->tuple.t_data = NULL;
-       sysscan->buffer = InvalidBuffer;
-       if (hasindex)
-       {
-               sysscan->irel = index_openr((char *) indexRelname);
-               sysscan->iscan = index_beginscan(sysscan->irel, false, nkeys, entry);
-       }
-       else
-               sysscan->scan = heap_beginscan(rel, false, SnapshotNow, nkeys, entry);
-       return (void *) sysscan;
-}
-
-static void
-systable_endscan(void *scan)
-{
-       SysScanDesc sysscan = (SysScanDesc) scan;
-
-       if (sysscan->irel)
-       {
-               if (BufferIsValid(sysscan->buffer))
-                       ReleaseBuffer(sysscan->buffer);
-               index_endscan(sysscan->iscan);
-               index_close(sysscan->irel);
-       }
-       else
-               heap_endscan(sysscan->scan);
-       pfree(scan);
-}
-
-static HeapTuple
-systable_getnext(void *scan)
-{
-       SysScanDesc sysscan = (SysScanDesc) scan;
-       HeapTuple       htup = (HeapTuple) NULL;
-       RetrieveIndexResult indexRes;
-
-       if (sysscan->irel)
-       {
-               if (BufferIsValid(sysscan->buffer))
-               {
-                       ReleaseBuffer(sysscan->buffer);
-                       sysscan->buffer = InvalidBuffer;
-               }
-               while (indexRes = index_getnext(sysscan->iscan, ForwardScanDirection), indexRes != NULL)
-               {
-                       sysscan->tuple.t_self = indexRes->heap_iptr;
-                       heap_fetch(sysscan->heap_rel, SnapshotNow, &sysscan->tuple, &(sysscan->buffer));
-                       pfree(indexRes);
-                       if (sysscan->tuple.t_data != NULL)
-                       {
-                               htup = &sysscan->tuple;
-                               break;
-                       }
-               }
-       }
-       else
-               htup = heap_getnext(sysscan->scan, 0);
-       return htup;
-}
-
 /*
  *     find a specified attribute in a node entry
  */
@@ -957,10 +874,15 @@ RemoveColumnReferences(Oid reloid, int attnum, bool checkonly, HeapTuple reltup)
        /*
         * Remove/check constraints here
         */
-       ScanKeyEntryInitialize(&entry, (bits16) 0x0, Anum_pg_relcheck_rcrelid,
-                                          (RegProcedure) F_OIDEQ, ObjectIdGetDatum(reloid));
+       ScanKeyEntryInitialize(&entry, (bits16) 0x0,
+                                                  Anum_pg_relcheck_rcrelid,
+                                                  (RegProcedure) F_OIDEQ,
+                                                  ObjectIdGetDatum(reloid));
+
        rcrel = heap_openr(RelCheckRelationName, RowExclusiveLock);
-       sysscan = systable_beginscan(rcrel, RelCheckIndex, 1, &entry);
+       sysscan = systable_beginscan(rcrel, RelCheckIndex, true,
+                                                                SnapshotNow,
+                                                                1, &entry);
 
        while (HeapTupleIsValid(htup = systable_getnext(sysscan)))
        {
@@ -987,6 +909,7 @@ RemoveColumnReferences(Oid reloid, int attnum, bool checkonly, HeapTuple reltup)
                        }
                }
        }
+
        systable_endscan(sysscan);
        heap_close(rcrel, NoLock);
 
index 528e53ee47ddd7bf5f38ebb30be28bec22cfbca2..402ff51e4bc267ac8e643fda1afb8902a275c06a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.101 2002/01/15 16:52:47 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.102 2002/02/19 20:11:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,7 +56,7 @@ CreateTrigger(CreateTrigStmt *stmt)
        char            nulls[Natts_pg_trigger];
        Relation        rel;
        Relation        tgrel;
-       HeapScanDesc tgscan;
+       SysScanDesc     tgscan;
        ScanKeyData key;
        Relation        pgrel;
        HeapTuple       tuple;
@@ -151,8 +151,9 @@ CreateTrigger(CreateTrigStmt *stmt)
        ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
                                                   F_OIDEQ,
                                                   ObjectIdGetDatum(RelationGetRelid(rel)));
-       tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
-       while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0)))
+       tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
+                                                               SnapshotNow, 1, &key);
+       while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
        {
                Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
 
@@ -161,7 +162,7 @@ CreateTrigger(CreateTrigStmt *stmt)
                                 stmt->trigname, stmt->relname);
                found++;
        }
-       heap_endscan(tgscan);
+       systable_endscan(tgscan);
 
        /*
         * Find and validate the trigger function.
@@ -311,7 +312,7 @@ DropTrigger(DropTrigStmt *stmt)
 {
        Relation        rel;
        Relation        tgrel;
-       HeapScanDesc tgscan;
+       SysScanDesc     tgscan;
        ScanKeyData key;
        Relation        pgrel;
        HeapTuple       tuple;
@@ -343,8 +344,9 @@ DropTrigger(DropTrigStmt *stmt)
        ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
                                                   F_OIDEQ,
                                                   ObjectIdGetDatum(RelationGetRelid(rel)));
-       tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
-       while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0)))
+       tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
+                                                               SnapshotNow, 1, &key);
+       while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
        {
                Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
 
@@ -359,14 +361,15 @@ DropTrigger(DropTrigStmt *stmt)
                else
                        found++;
        }
+       systable_endscan(tgscan);
+       heap_close(tgrel, RowExclusiveLock);
+
        if (tgfound == 0)
                elog(ERROR, "DropTrigger: there is no trigger %s on relation %s",
                         stmt->trigname, stmt->relname);
        if (tgfound > 1)
                elog(NOTICE, "DropTrigger: found (and deleted) %d triggers %s on relation %s",
                         tgfound, stmt->trigname, stmt->relname);
-       heap_endscan(tgscan);
-       heap_close(tgrel, RowExclusiveLock);
 
        /*
         * Update relation's pg_class entry.  Crucial side-effect: other
@@ -406,7 +409,7 @@ void
 RelationRemoveTriggers(Relation rel)
 {
        Relation        tgrel;
-       HeapScanDesc tgscan;
+       SysScanDesc     tgscan;
        ScanKeyData key;
        HeapTuple       tup;
        bool            found = false;
@@ -415,10 +418,10 @@ RelationRemoveTriggers(Relation rel)
        ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
                                                   F_OIDEQ,
                                                   ObjectIdGetDatum(RelationGetRelid(rel)));
+       tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
+                                                               SnapshotNow, 1, &key);
 
-       tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
-
-       while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0)))
+       while (HeapTupleIsValid(tup = systable_getnext(tgscan)))
        {
                /* Delete any comments associated with this trigger */
                DeleteComments(tup->t_data->t_oid, RelationGetRelid(tgrel));
@@ -428,7 +431,7 @@ RelationRemoveTriggers(Relation rel)
                found = true;
        }
 
-       heap_endscan(tgscan);
+       systable_endscan(tgscan);
 
        /*
         * If we deleted any triggers, must update pg_class entry and advance
@@ -468,9 +471,10 @@ RelationRemoveTriggers(Relation rel)
        ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgconstrrelid,
                                                   F_OIDEQ,
                                                   ObjectIdGetDatum(RelationGetRelid(rel)));
+       tgscan = systable_beginscan(tgrel, TriggerConstrRelidIndex, true,
+                                                               SnapshotNow, 1, &key);
 
-       tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
-       while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0)))
+       while (HeapTupleIsValid(tup = systable_getnext(tgscan)))
        {
                Form_pg_trigger pg_trigger;
                Relation        refrel;
@@ -500,7 +504,7 @@ RelationRemoveTriggers(Relation rel)
                pfree(stmt.relname);
                pfree(stmt.trigname);
        }
-       heap_endscan(tgscan);
+       systable_endscan(tgscan);
 
        heap_close(tgrel, RowExclusiveLock);
 }
@@ -518,69 +522,33 @@ RelationBuildTriggers(Relation relation)
        TriggerDesc *trigdesc;
        int                     ntrigs = relation->rd_rel->reltriggers;
        Trigger    *triggers = NULL;
-       Trigger    *build;
+       int                     found = 0;
        Relation        tgrel;
-       Form_pg_trigger pg_trigger;
-       Relation        irel = (Relation) NULL;
        ScanKeyData skey;
-       HeapTupleData tuple;
-       IndexScanDesc sd = (IndexScanDesc) NULL;
-       HeapScanDesc tgscan = (HeapScanDesc) NULL;
+       SysScanDesc     tgscan;
        HeapTuple       htup;
-       RetrieveIndexResult indexRes;
-       Buffer          buffer;
        struct varlena *val;
        bool            isnull;
-       int                     found;
-       bool            hasindex;
-
-       trigdesc = (TriggerDesc *) MemoryContextAlloc(CacheMemoryContext,
-                                                                                                 sizeof(TriggerDesc));
-       MemSet(trigdesc, 0, sizeof(TriggerDesc));
 
        ScanKeyEntryInitialize(&skey,
                                                   (bits16) 0x0,
-                                                  (AttrNumber) 1,
+                                                  (AttrNumber) Anum_pg_trigger_tgrelid,
                                                   (RegProcedure) F_OIDEQ,
                                                   ObjectIdGetDatum(RelationGetRelid(relation)));
 
        tgrel = heap_openr(TriggerRelationName, AccessShareLock);
-       hasindex = (tgrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
-       if (hasindex)
-       {
-               irel = index_openr(TriggerRelidIndex);
-               sd = index_beginscan(irel, false, 1, &skey);
-       }
-       else
-               tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey);
+       tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
+                                                               SnapshotNow, 1, &skey);
 
-       for (found = 0;;)
+       while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
        {
-               if (hasindex)
-               {
-                       indexRes = index_getnext(sd, ForwardScanDirection);
-                       if (!indexRes)
-                               break;
+               Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
+               Trigger    *build;
 
-                       tuple.t_self = indexRes->heap_iptr;
-                       heap_fetch(tgrel, SnapshotNow, &tuple, &buffer, sd);
-                       pfree(indexRes);
-                       if (!tuple.t_data)
-                               continue;
-                       htup = &tuple;
-               }
-               else
-               {
-                       htup = heap_getnext(tgscan, 0);
-                       if (!HeapTupleIsValid(htup))
-                               break;
-               }
                if (found == ntrigs)
                        elog(ERROR, "RelationBuildTriggers: unexpected record found for rel %s",
                                 RelationGetRelationName(relation));
 
-               pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
-
                if (triggers == NULL)
                        triggers = (Trigger *) MemoryContextAlloc(CacheMemoryContext,
                                                                                                          sizeof(Trigger));
@@ -628,25 +596,20 @@ RelationBuildTriggers(Relation relation)
                        build->tgargs = NULL;
 
                found++;
-               if (hasindex)
-                       ReleaseBuffer(buffer);
        }
 
-       if (found < ntrigs)
+       systable_endscan(tgscan);
+       heap_close(tgrel, AccessShareLock);
+
+       if (found != ntrigs)
                elog(ERROR, "RelationBuildTriggers: %d record(s) not found for rel %s",
                         ntrigs - found,
                         RelationGetRelationName(relation));
 
-       if (hasindex)
-       {
-               index_endscan(sd);
-               index_close(irel);
-       }
-       else
-               heap_endscan(tgscan);
-       heap_close(tgrel, AccessShareLock);
-
        /* Build trigdesc */
+       trigdesc = (TriggerDesc *) MemoryContextAlloc(CacheMemoryContext,
+                                                                                                 sizeof(TriggerDesc));
+       MemSet(trigdesc, 0, sizeof(TriggerDesc));
        trigdesc->triggers = triggers;
        trigdesc->numtriggers = ntrigs;
        for (found = 0; found < ntrigs; found++)
@@ -1741,14 +1704,12 @@ void
 DeferredTriggerSetState(ConstraintsSetStmt *stmt)
 {
        Relation        tgrel;
-       Relation        irel = (Relation) NULL;
        List       *l;
        List       *ls;
        List       *loid = NIL;
        MemoryContext oldcxt;
        bool            found;
        DeferredTriggerStatus state;
-       bool            hasindex;
 
        /*
         * Handle SET CONSTRAINTS ALL ...
@@ -1817,21 +1778,12 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
         * ----------
         */
        tgrel = heap_openr(TriggerRelationName, AccessShareLock);
-       hasindex = (tgrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
-       if (hasindex)
-               irel = index_openr(TriggerConstrNameIndex);
 
        foreach(l, stmt->constraints)
        {
                ScanKeyData skey;
-               HeapTupleData tuple;
-               IndexScanDesc sd = (IndexScanDesc) NULL;
-               HeapScanDesc tgscan = (HeapScanDesc) NULL;
+               SysScanDesc     tgscan;
                HeapTuple       htup;
-               RetrieveIndexResult indexRes;
-               Buffer          buffer;
-               Form_pg_trigger pg_trigger;
-               Oid                     constr_oid;
 
                /*
                 * Check that only named constraints are set explicitly
@@ -1844,47 +1796,28 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
                 */
                ScanKeyEntryInitialize(&skey,
                                                           (bits16) 0x0,
-                                                          (AttrNumber) 1,
+                                                          (AttrNumber) Anum_pg_trigger_tgconstrname,
                                                           (RegProcedure) F_NAMEEQ,
                                                           PointerGetDatum((char *) lfirst(l)));
 
-               if (hasindex)
-                       sd = index_beginscan(irel, false, 1, &skey);
-               else
-                       tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey);
+               tgscan = systable_beginscan(tgrel, TriggerConstrNameIndex, true,
+                                                                       SnapshotNow, 1, &skey);
 
                /*
                 * ... and search for the constraint trigger row
                 */
                found = false;
-               for (;;)
-               {
-                       if (hasindex)
-                       {
-                               indexRes = index_getnext(sd, ForwardScanDirection);
-                               if (!indexRes)
-                                       break;
 
-                               tuple.t_self = indexRes->heap_iptr;
-                               heap_fetch(tgrel, SnapshotNow, &tuple, &buffer, sd);
-                               pfree(indexRes);
-                               if (!tuple.t_data)
-                                       continue;
-                               htup = &tuple;
-                       }
-                       else
-                       {
-                               htup = heap_getnext(tgscan, 0);
-                               if (!HeapTupleIsValid(htup))
-                                       break;
-                       }
+               while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
+               {
+                       Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
+                       Oid                     constr_oid;
 
                        /*
                         * If we found some, check that they fit the deferrability but
                         * skip ON <event> RESTRICT ones, since they are silently
                         * never deferrable.
                         */
-                       pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
                        if (stmt->deferred && !pg_trigger->tgdeferrable &&
                                pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_UPD &&
                                pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_DEL)
@@ -1894,24 +1827,16 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
                        constr_oid = htup->t_data->t_oid;
                        loid = lappendi(loid, constr_oid);
                        found = true;
-
-                       if (hasindex)
-                               ReleaseBuffer(buffer);
                }
 
+               systable_endscan(tgscan);
+
                /*
                 * Not found ?
                 */
                if (!found)
                        elog(ERROR, "Constraint '%s' does not exist", (char *) lfirst(l));
-
-               if (hasindex)
-                       index_endscan(sd);
-               else
-                       heap_endscan(tgscan);
        }
-       if (hasindex)
-               index_close(irel);
        heap_close(tgrel, AccessShareLock);
 
        if (!IsTransactionBlock())
index 894a7e328559092b43b94eabfe35f2cc6874a260..a36ae25b3f840302bd1e40824acb45bcef3ce27e 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.213 2002/01/06 00:37:44 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.214 2002/02/19 20:11:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -315,20 +315,6 @@ vacuum_shutdown(VacuumStmt *vacstmt)
                vac_truncate_clog(initialOldestXmin, initialFreezeLimit);
        }
 
-       /*
-        * If we did a complete vacuum or analyze, then flush the init file
-        * that relcache.c uses to save startup time. The next backend startup
-        * will rebuild the init file with up-to-date information from
-        * pg_class. This lets the optimizer see the stats that we've
-        * collected for certain critical system indexes.  See relcache.c for
-        * more details.
-        *
-        * Ignore any failure to unlink the file, since it might not be there if
-        * no backend has been started since the last vacuum.
-        */
-       if (vacstmt->vacrel == NULL)
-               unlink(RELCACHE_INIT_FILENAME);
-
        /*
         * Clean up working storage --- note we must do this after
         * StartTransactionCommand, else we might be trying to delete the
@@ -535,8 +521,15 @@ vac_update_relstats(Oid relid, BlockNumber num_pages, double num_tuples,
        if (!hasindex)
                pgcform->relhaspkey = false;
 
-       /* invalidate the tuple in the cache and write the buffer */
+       /*
+        * Invalidate the tuple in the catcaches; this also arranges to flush
+        * the relation's relcache entry.  (If we fail to commit for some reason,
+        * no flush will occur, but no great harm is done since there are no
+        * noncritical state updates here.)
+        */
        RelationInvalidateHeapTuple(rd, &rtup);
+
+       /* Write the buffer */
        WriteBuffer(buffer);
 
        heap_close(rd, RowExclusiveLock);
@@ -2816,10 +2809,6 @@ vac_close_indexes(int nindexes, Relation *Irel)
 bool
 vac_is_partial_index(Relation indrel)
 {
-       bool            result;
-       HeapTuple       cachetuple;
-       Form_pg_index indexStruct;
-
        /*
         * If the index's AM doesn't support nulls, it's partial for our
         * purposes
@@ -2828,18 +2817,7 @@ vac_is_partial_index(Relation indrel)
                return true;
 
        /* Otherwise, look to see if there's a partial-index predicate */
-       cachetuple = SearchSysCache(INDEXRELID,
-                                                         ObjectIdGetDatum(RelationGetRelid(indrel)),
-                                                               0, 0, 0);
-       if (!HeapTupleIsValid(cachetuple))
-               elog(ERROR, "vac_is_partial_index: index %u not found",
-                        RelationGetRelid(indrel));
-       indexStruct = (Form_pg_index) GETSTRUCT(cachetuple);
-
-       result = (VARSIZE(&indexStruct->indpred) > VARHDRSZ);
-
-       ReleaseSysCache(cachetuple);
-       return result;
+       return (VARSIZE(&indrel->rd_index->indpred) > VARHDRSZ);
 }
 
 
index af0e190d396d42a65a773e62c9d5e9c38766183d..e7a335916bdfe99a922b65c5028ec761f9803b1d 100644 (file)
@@ -6,25 +6,12 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Id: execAmi.c,v 1.60 2001/10/25 05:49:27 momjian Exp $
+ *     $Id: execAmi.c,v 1.61 2002/02/19 20:11:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-/*
- *      INTERFACE ROUTINES
- *
- *             ExecOpenScanR   \                                                         / amopen
- *             ExecBeginScan    \                                                       /      ambeginscan
- *             ExecCloseR                \                                                     /       amclose
- *             ExecInsert                 \  executor interface   /    aminsert
- *             ExecReScanR                /  to access methods    \    amrescan
- *             ExecMarkPos               /                                                     \       ammarkpos
- *             ExecRestrPos     /                                                       \      amrestpos
- */
-
 #include "postgres.h"
 
-
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "catalog/heap.h"
 #include "executor/nodeSubqueryscan.h"
 #include "executor/nodeUnique.h"
 
-static Pointer ExecBeginScan(Relation relation, int nkeys, ScanKey skeys,
-                         bool isindex, ScanDirection dir, Snapshot snapshot);
-
-/* ----------------------------------------------------------------
- *             ExecOpenScanR
- *
- * old comments:
- *             Parameters:
- *               relation -- relation to be opened and scanned.
- *               nkeys    -- number of keys
- *               skeys    -- keys to restrict scanning
- *                      isindex  -- if this is true, the relation is the relid of
- *                                              an index relation, else it is a heap relation.
- *             Returns the relation as(relDesc scanDesc)
- * ----------------------------------------------------------------
- */
-void
-ExecOpenScanR(Oid relOid,
-                         int nkeys,
-                         ScanKey skeys,
-                         bool isindex,
-                         ScanDirection dir,
-                         Snapshot snapshot,
-                         Relation *returnRelation, /* return */
-                         Pointer *returnScanDesc)      /* return */
-{
-       Relation        relation;
-       Pointer         scanDesc;
-
-       /*
-        * note: scanDesc returned by ExecBeginScan can be either a
-        * HeapScanDesc or an IndexScanDesc so for now we make it a Pointer.
-        * There should be a better scan abstraction someday -cim 9/9/89
-        */
-
-       /*
-        * Open the relation with the correct call depending on whether this
-        * is a heap relation or an index relation.
-        *
-        * For a table, acquire AccessShareLock for the duration of the query
-        * execution.  For indexes, acquire no lock here; the index machinery
-        * does its own locks and unlocks.      (We rely on having some kind of
-        * lock on the parent table to ensure the index won't go away!)
-        */
-       if (isindex)
-               relation = index_open(relOid);
-       else
-               relation = heap_open(relOid, AccessShareLock);
-
-       scanDesc = ExecBeginScan(relation,
-                                                        nkeys,
-                                                        skeys,
-                                                        isindex,
-                                                        dir,
-                                                        snapshot);
-
-       if (returnRelation != NULL)
-               *returnRelation = relation;
-       if (scanDesc != NULL)
-               *returnScanDesc = scanDesc;
-}
-
-/* ----------------------------------------------------------------
- *             ExecBeginScan
- *
- *             beginscans a relation in current direction.
- *
- *             XXX fix parameters to AMbeginscan (and btbeginscan)
- *                             currently we need to pass a flag stating whether
- *                             or not the scan should begin at an endpoint of
- *                             the relation.. Right now we always pass false
- *                             -cim 9/14/89
- * ----------------------------------------------------------------
- */
-static Pointer
-ExecBeginScan(Relation relation,
-                         int nkeys,
-                         ScanKey skeys,
-                         bool isindex,
-                         ScanDirection dir,
-                         Snapshot snapshot)
-{
-       Pointer         scanDesc;
-
-       /*
-        * open the appropriate type of scan.
-        *
-        * Note: ambeginscan()'s second arg is a boolean indicating that the scan
-        * should be done in reverse..  That is, if you pass it true, then the
-        * scan is backward.
-        */
-       if (isindex)
-       {
-               scanDesc = (Pointer) index_beginscan(relation,
-                                                                                        false,         /* see above comment */
-                                                                                        nkeys,
-                                                                                        skeys);
-       }
-       else
-       {
-               scanDesc = (Pointer) heap_beginscan(relation,
-                                                                                       ScanDirectionIsBackward(dir),
-                                                                                       snapshot,
-                                                                                       nkeys,
-                                                                                       skeys);
-       }
-
-       if (scanDesc == NULL)
-               elog(DEBUG, "ExecBeginScan: scanDesc = NULL, heap_beginscan failed.");
-
-       return scanDesc;
-}
-
-/* ----------------------------------------------------------------
- *             ExecCloseR
- *
- *             closes the relation and scan descriptor for a scan node.
- *             Also closes index relations and scans for index scans.
- * ----------------------------------------------------------------
- */
-void
-ExecCloseR(Plan *node)
-{
-       CommonScanState *state;
-       Relation        relation;
-       HeapScanDesc scanDesc;
-
-       /*
-        * get state for node and shut down the heap scan, if any
-        */
-       switch (nodeTag(node))
-       {
-               case T_SeqScan:
-                       state = ((SeqScan *) node)->scanstate;
-                       break;
-
-               case T_IndexScan:
-                       state = ((IndexScan *) node)->scan.scanstate;
-                       break;
-
-               case T_TidScan:
-                       state = ((TidScan *) node)->scan.scanstate;
-                       break;
-
-               default:
-                       elog(DEBUG, "ExecCloseR: not a scan node!");
-                       return;
-       }
-
-       relation = state->css_currentRelation;
-       scanDesc = state->css_currentScanDesc;
-
-       if (scanDesc != NULL)
-               heap_endscan(scanDesc);
-
-       /*
-        * if this is an index scan then we have to take care of the index
-        * relations as well.
-        */
-       if (IsA(node, IndexScan))
-       {
-               IndexScan  *iscan = (IndexScan *) node;
-               IndexScanState *indexstate = iscan->indxstate;
-               int                     numIndices;
-               RelationPtr indexRelationDescs;
-               IndexScanDescPtr indexScanDescs;
-               int                     i;
-
-               numIndices = indexstate->iss_NumIndices;
-               indexRelationDescs = indexstate->iss_RelationDescs;
-               indexScanDescs = indexstate->iss_ScanDescs;
-
-               for (i = 0; i < numIndices; i++)
-               {
-                       /*
-                        * shut down each of the index scans and close each of the
-                        * index relations
-                        */
-                       if (indexScanDescs[i] != NULL)
-                               index_endscan(indexScanDescs[i]);
-
-                       if (indexRelationDescs[i] != NULL)
-                               index_close(indexRelationDescs[i]);
-               }
-       }
-
-       /*
-        * Finally, close the heap relation.
-        *
-        * Currently, we do not release the AccessShareLock acquired by
-        * ExecOpenScanR.  This lock should be held till end of transaction.
-        * (There is a faction that considers this too much locking, however.)
-        */
-       if (relation != NULL)
-               heap_close(relation, NoLock);
-}
 
 /* ----------------------------------------------------------------
  *             ExecReScan
@@ -374,27 +165,6 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
        }
 }
 
-/* ----------------------------------------------------------------
- *             ExecReScanR
- *
- *             XXX this does not do the right thing with indices yet.
- * ----------------------------------------------------------------
- */
-HeapScanDesc
-ExecReScanR(Relation relDesc,  /* LLL relDesc unused  */
-                       HeapScanDesc scanDesc,
-                       ScanDirection direction,
-                       int nkeys,                      /* LLL nkeys unused  */
-                       ScanKey skeys)
-{
-       if (scanDesc != NULL)
-               heap_rescan(scanDesc,   /* scan desc */
-                                       ScanDirectionIsBackward(direction), /* backward flag */
-                                       skeys);         /* scan keys */
-
-       return scanDesc;
-}
-
 /* ----------------------------------------------------------------
  *             ExecMarkPos
  *
index d710c8270334cb0350702e055fae22537c630dee..5b0719487792960068bd816bf28cd616abd0c163 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.78 2001/10/25 05:49:27 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.79 2002/02/19 20:11:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -496,7 +496,6 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
        {
                Oid                     indexOid = lfirsti(indexoidscan);
                Relation        indexDesc;
-               HeapTuple       indexTuple;
                IndexInfo  *ii;
 
                /*
@@ -525,20 +524,9 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
                        LockRelation(indexDesc, AccessExclusiveLock);
 
                /*
-                * Get the pg_index tuple for the index
+                * extract index key information from the index's pg_index tuple
                 */
-               indexTuple = SearchSysCache(INDEXRELID,
-                                                                       ObjectIdGetDatum(indexOid),
-                                                                       0, 0, 0);
-               if (!HeapTupleIsValid(indexTuple))
-                       elog(ERROR, "ExecOpenIndices: index %u not found", indexOid);
-
-               /*
-                * extract the index key information from the tuple
-                */
-               ii = BuildIndexInfo(indexTuple);
-
-               ReleaseSysCache(indexTuple);
+               ii = BuildIndexInfo(indexDesc->rd_index);
 
                relationDescs[i] = indexDesc;
                indexInfoArray[i] = ii;
index bde5bce334dbc9b1d2aa66379a1ef79bef3fd795..3ab73f62f9a9746d77e6eb0d4eea8dda256f3643 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.66 2002/02/11 20:10:48 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.67 2002/02/19 20:11:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -359,14 +359,20 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
                        int                     n_keys;
                        ScanKey         scan_keys;
                        int                *run_keys;
+                       List       *listscan;
 
                        indxqual = lnext(indxqual);
                        n_keys = numScanKeys[i];
                        scan_keys = scanKeys[i];
                        run_keys = runtimeKeyInfo[i];
 
+                       listscan = qual;
                        for (j = 0; j < n_keys; j++)
                        {
+                               Expr       *clause = lfirst(listscan);
+
+                               listscan = lnext(listscan);
+
                                /*
                                 * If we have a run-time key, then extract the run-time
                                 * expression and evaluate it with respect to the current
@@ -382,7 +388,6 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
                                 */
                                if (run_keys[j] != NO_OP)
                                {
-                                       Expr       *clause = nth(j, qual);
                                        Node       *scanexpr;
                                        Datum           scanvalue;
                                        bool            isNull;
@@ -448,6 +453,9 @@ ExecEndIndexScan(IndexScan *node)
        List       *indxqual;
        int                *numScanKeys;
        int                     numIndices;
+       Relation        relation;
+       RelationPtr indexRelationDescs;
+       IndexScanDescPtr indexScanDescs;
        int                     i;
 
        scanstate = node->scan.scanstate;
@@ -461,6 +469,9 @@ ExecEndIndexScan(IndexScan *node)
        numIndices = indexstate->iss_NumIndices;
        scanKeys = indexstate->iss_ScanKeys;
        numScanKeys = indexstate->iss_NumScanKeys;
+       indexRelationDescs = indexstate->iss_RelationDescs;
+       indexScanDescs = indexstate->iss_ScanDescs;
+       relation = scanstate->css_currentRelation;
 
        /*
         * Free the projection info and the scan attribute info
@@ -475,9 +486,25 @@ ExecEndIndexScan(IndexScan *node)
                FreeExprContext(indexstate->iss_RuntimeContext);
 
        /*
-        * close the heap and index relations
+        * close the index relations
+        */
+       for (i = 0; i < numIndices; i++)
+       {
+               if (indexScanDescs[i] != NULL)
+                       index_endscan(indexScanDescs[i]);
+
+               if (indexRelationDescs[i] != NULL)
+                       index_close(indexRelationDescs[i]);
+       }
+
+       /*
+        * close the heap relation.
+        *
+        * Currently, we do not release the AccessShareLock acquired by
+        * ExecInitIndexScan.  This lock should be held till end of transaction.
+        * (There is a faction that considers this too much locking, however.)
         */
-       ExecCloseR((Plan *) node);
+       heap_close(relation, NoLock);
 
        /*
         * free the scan keys used in scanning the indices
@@ -589,6 +616,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
        CommonScanState *scanstate;
        List       *indxqual;
        List       *indxid;
+       List       *listscan;
        int                     i;
        int                     numIndices;
        int                     indexPtr;
@@ -603,7 +631,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
        Index           relid;
        Oid                     reloid;
        Relation        currentRelation;
-       HeapScanDesc currentScanDesc;
        ScanDirection direction;
 
        /*
@@ -709,6 +736,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
                 * for each opclause in the given qual, convert each qual's
                 * opclause into a single scan key
                 */
+               listscan = qual;
                for (j = 0; j < n_keys; j++)
                {
                        Expr       *clause; /* one clause of index qual */
@@ -725,7 +753,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
                        /*
                         * extract clause information from the qualification
                         */
-                       clause = nth(j, qual);
+                       clause = lfirst(listscan);
+                       listscan = lnext(listscan);
 
                        op = (Oper *) clause->oper;
                        if (!IsA(clause, Expr) ||!IsA(op, Oper))
@@ -989,25 +1018,19 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
        direction = estate->es_direction;
 
        /*
-        * open the base relation
+        * open the base relation and acquire AccessShareLock on it.
         */
        relid = node->scan.scanrelid;
        rtentry = rt_fetch(relid, rangeTable);
        reloid = rtentry->relid;
 
-       ExecOpenScanR(reloid,           /* relation */
-                                 0,                    /* nkeys */
-                                 (ScanKey) NULL,               /* scan key */
-                                 false,                /* is index */
-                                 direction,    /* scan direction */
-                                 estate->es_snapshot,  /* */
-                                 &currentRelation,             /* return: rel desc */
-                                 (Pointer *) &currentScanDesc);                /* return: scan desc */
+       currentRelation = heap_open(reloid, AccessShareLock);
 
        if (!RelationGetForm(currentRelation)->relhasindex)
                elog(ERROR, "indexes of the relation %u was inactivated", reloid);
+
        scanstate->css_currentRelation = currentRelation;
-       scanstate->css_currentScanDesc = currentScanDesc;
+       scanstate->css_currentScanDesc = NULL; /* no heap scan here */
 
        /*
         * get the scan type from the relation descriptor.
@@ -1017,24 +1040,30 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
 
        /*
         * open the index relations and initialize relation and scan
-        * descriptors.
+        * descriptors.  Note we acquire no locks here; the index machinery
+        * does its own locks and unlocks.      (We rely on having AccessShareLock
+        * on the parent table to ensure the index won't go away!)
         */
+       listscan = indxid;
        for (i = 0; i < numIndices; i++)
        {
-               Oid                     indexOid = (Oid) nthi(i, indxid);
+               Oid                     indexOid = (Oid) lfirsti(listscan);
 
                if (indexOid != 0)
                {
-                       ExecOpenScanR(indexOid,         /* relation */
-                                                 numScanKeys[i],               /* nkeys */
-                                                 scanKeys[i],  /* scan key */
-                                                 true, /* is index */
-                                                 direction,    /* scan direction */
-                                                 estate->es_snapshot,
-                                                 &(relationDescs[i]),  /* return: rel desc */
-                                                 (Pointer *) &(scanDescs[i]));
-                       /* return: scan desc */
+                       relationDescs[i] = index_open(indexOid);
+
+                       /*
+                        * Note: index_beginscan()'s second arg is a boolean indicating
+                        * that the scan should be done in reverse.  That is, if you pass
+                        * it true, then the scan is backward.
+                        */
+                       scanDescs[i] = index_beginscan(relationDescs[i],
+                                                                                  false, /* see above comment */
+                                                                                  numScanKeys[i],
+                                                                                  scanKeys[i]);
                }
+               listscan = lnext(listscan);
        }
 
        indexstate->iss_RelationDescs = relationDescs;
index d7ebec4985f8d80783d9f4d3ff84f4fea0b77d31..957a1bb2b722813b2f888cc0969616ed7a4b7d46 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.33 2001/10/28 06:25:43 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.34 2002/02/19 20:11:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -154,7 +154,9 @@ InitScanRelation(SeqScan *node, EState *estate,
 
        /*
         * get the relation object id from the relid'th entry in the range
-        * table, open that relation and initialize the scan state...
+        * table, open that relation and initialize the scan state.
+        *
+        * We acquire AccessShareLock for the duration of the scan.
         */
        relid = node->scanrelid;
        rangeTable = estate->es_range_table;
@@ -162,14 +164,13 @@ InitScanRelation(SeqScan *node, EState *estate,
        reloid = rtentry->relid;
        direction = estate->es_direction;
 
-       ExecOpenScanR(reloid,           /* relation */
-                                 0,                    /* nkeys */
-                                 NULL,                 /* scan key */
-                                 false,                /* is index */
-                                 direction,    /* scan direction */
-                                 estate->es_snapshot,
-                                 &currentRelation,             /* return: rel desc */
-                                 (Pointer *) &currentScanDesc);                /* return: scan desc */
+       currentRelation = heap_open(reloid, AccessShareLock);
+
+       currentScanDesc = heap_beginscan(currentRelation,
+                                                                        ScanDirectionIsBackward(direction),
+                                                                        estate->es_snapshot,
+                                                                        0,
+                                                                        NULL);
 
        scanstate->css_currentRelation = currentRelation;
        scanstate->css_currentScanDesc = currentScanDesc;
@@ -189,7 +190,6 @@ ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
 {
        CommonScanState *scanstate;
        Oid                     reloid;
-       HeapScanDesc scandesc;
 
        /*
         * Once upon a time it was possible to have an outerPlan of a SeqScan,
@@ -229,7 +229,6 @@ ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
         */
        reloid = InitScanRelation(node, estate, scanstate);
 
-       scandesc = scanstate->css_currentScanDesc;
        scanstate->cstate.cs_TupFromTlist = false;
 
        /*
@@ -259,11 +258,15 @@ void
 ExecEndSeqScan(SeqScan *node)
 {
        CommonScanState *scanstate;
+       Relation        relation;
+       HeapScanDesc scanDesc;
 
        /*
         * get information from node
         */
        scanstate = node->scanstate;
+       relation = scanstate->css_currentRelation;
+       scanDesc = scanstate->css_currentScanDesc;
 
        /*
         * Free the projection info and the scan attribute info
@@ -276,9 +279,18 @@ ExecEndSeqScan(SeqScan *node)
        ExecFreeExprContext(&scanstate->cstate);
 
        /*
-        * close scan relation
+        * close heap scan
+        */
+       heap_endscan(scanDesc);
+
+       /*
+        * close the heap relation.
+        *
+        * Currently, we do not release the AccessShareLock acquired by
+        * InitScanRelation.  This lock should be held till end of transaction.
+        * (There is a faction that considers this too much locking, however.)
         */
-       ExecCloseR((Plan *) node);
+       heap_close(relation, NoLock);
 
        /*
         * clean out the tuple table
@@ -303,7 +315,6 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
 {
        CommonScanState *scanstate;
        EState     *estate;
-       Relation        rel;
        HeapScanDesc scan;
        ScanDirection direction;
 
@@ -317,11 +328,13 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
                estate->es_evTupleNull[node->scanrelid - 1] = false;
                return;
        }
-       rel = scanstate->css_currentRelation;
+
        scan = scanstate->css_currentScanDesc;
        direction = estate->es_direction;
-       scan = ExecReScanR(rel, scan, direction, 0, NULL);
-       scanstate->css_currentScanDesc = scan;
+
+       heap_rescan(scan,                       /* scan desc */
+                               ScanDirectionIsBackward(direction), /* backward flag */
+                               NULL);                  /* new scan keys */
 }
 
 /* ----------------------------------------------------------------
index 08685571cab4acc4863db757e637f285af50f945..5ee222744d3b64d35d2763c043759233a13f932b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.22 2002/02/11 20:10:50 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.23 2002/02/19 20:11:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -300,15 +300,14 @@ ExecEndTidScan(TidScan *node)
        CommonScanState *scanstate;
        TidScanState *tidstate;
 
+       /*
+        * extract information from the node
+        */
        scanstate = node->scan.scanstate;
        tidstate = node->tidstate;
        if (tidstate && tidstate->tss_TidList)
                pfree(tidstate->tss_TidList);
 
-       /*
-        * extract information from the node
-        */
-
        /*
         * Free the projection info and the scan attribute info
         *
@@ -320,9 +319,13 @@ ExecEndTidScan(TidScan *node)
        ExecFreeExprContext(&scanstate->cstate);
 
        /*
-        * close the heap and tid relations
+        * close the heap relation.
+        *
+        * Currently, we do not release the AccessShareLock acquired by
+        * ExecInitTidScan.  This lock should be held till end of transaction.
+        * (There is a faction that considers this too much locking, however.)
         */
-       ExecCloseR((Plan *) node);
+       heap_close(scanstate->css_currentRelation, NoLock);
 
        /*
         * clear out tuple table slots
@@ -460,14 +463,17 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
 
        /*
         * open the base relation
+        *
+        * We acquire AccessShareLock for the duration of the scan.
         */
        relid = node->scan.scanrelid;
        rtentry = rt_fetch(relid, rangeTable);
        reloid = rtentry->relid;
 
        currentRelation = heap_open(reloid, AccessShareLock);
+
        scanstate->css_currentRelation = currentRelation;
-       scanstate->css_currentScanDesc = 0;
+       scanstate->css_currentScanDesc = NULL; /* no heap scan here */
 
        /*
         * get the scan type from the relation descriptor.
index 86ebb09ff677eb38749965668e9217a1b3fac0eb..447b3e61f2b8b9ccd871edb491bfc3c22c986023 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.69 2001/10/25 05:49:34 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.70 2002/02/19 20:11:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -98,20 +98,15 @@ find_secondary_indexes(Oid relationObjectId)
        foreach(indexoidscan, indexoidlist)
        {
                Oid                     indexoid = lfirsti(indexoidscan);
-               HeapTuple       indexTuple;
+               Relation        indexRelation;
                Form_pg_index index;
                IndexOptInfo *info;
                int                     i;
-               Relation        indexRelation;
                int16           amorderstrategy;
 
-               indexTuple = SearchSysCache(INDEXRELID,
-                                                                       ObjectIdGetDatum(indexoid),
-                                                                       0, 0, 0);
-               if (!HeapTupleIsValid(indexTuple))
-                       elog(ERROR, "find_secondary_indexes: index %u not found",
-                                indexoid);
-               index = (Form_pg_index) GETSTRUCT(indexTuple);
+               /* Extract info from the relation descriptor for the index */
+               indexRelation = index_open(indexoid);
+
                info = makeNode(IndexOptInfo);
 
                /*
@@ -123,6 +118,7 @@ find_secondary_indexes(Oid relationObjectId)
                info->ordering = (Oid *) palloc(sizeof(Oid) * (INDEX_MAX_KEYS + 1));
 
                /* Extract info from the pg_index tuple */
+               index = indexRelation->rd_index;
                info->indexoid = index->indexrelid;
                info->indproc = index->indproc; /* functional index ?? */
                if (VARSIZE(&index->indpred) > VARHDRSZ)                /* partial index ?? */
@@ -156,14 +152,11 @@ find_secondary_indexes(Oid relationObjectId)
                info->indexkeys[i] = 0;
                info->nkeys = i;
 
-               /* Extract info from the relation descriptor for the index */
-               indexRelation = index_open(index->indexrelid);
                info->relam = indexRelation->rd_rel->relam;
                info->pages = indexRelation->rd_rel->relpages;
                info->tuples = indexRelation->rd_rel->reltuples;
                info->amcostestimate = index_cost_estimator(indexRelation);
                amorderstrategy = indexRelation->rd_am->amorderstrategy;
-               index_close(indexRelation);
 
                /*
                 * Fetch the ordering operators associated with the index, if any.
@@ -171,26 +164,16 @@ find_secondary_indexes(Oid relationObjectId)
                MemSet(info->ordering, 0, sizeof(Oid) * (INDEX_MAX_KEYS + 1));
                if (amorderstrategy != 0)
                {
+                       int             oprindex = amorderstrategy - 1;
+
                        for (i = 0; i < info->ncolumns; i++)
                        {
-                               HeapTuple       amopTuple;
-                               Form_pg_amop amop;
-
-                               amopTuple =
-                                       SearchSysCache(AMOPSTRATEGY,
-                                                                  ObjectIdGetDatum(index->indclass[i]),
-                                                                  Int16GetDatum(amorderstrategy),
-                                                                  0, 0);
-                               if (!HeapTupleIsValid(amopTuple))
-                                       elog(ERROR, "find_secondary_indexes: no amop %u %d",
-                                                index->indclass[i], (int) amorderstrategy);
-                               amop = (Form_pg_amop) GETSTRUCT(amopTuple);
-                               info->ordering[i] = amop->amopopr;
-                               ReleaseSysCache(amopTuple);
+                               info->ordering[i] = indexRelation->rd_operator[oprindex];
+                               oprindex += indexRelation->rd_am->amstrategies;
                        }
                }
 
-               ReleaseSysCache(indexTuple);
+               index_close(indexRelation);
 
                indexinfos = lcons(info, indexinfos);
        }
index 7739185133874b4f3b948c1e289ade2370e7c715..766a5daad55b8fcaa5780896c20324535ec984f9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.115 2001/12/12 03:28:49 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.116 2002/02/19 20:11:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -547,11 +547,9 @@ agg_get_candidates(char *aggname,
                                   Oid typeId,
                                   CandidateList *candidates)
 {
-       CandidateList current_candidate;
        Relation        pg_aggregate_desc;
-       HeapScanDesc pg_aggregate_scan;
+       SysScanDesc     pg_aggregate_scan;
        HeapTuple       tup;
-       Form_pg_aggregate agg;
        int                     ncandidates = 0;
        ScanKeyData aggKey[1];
 
@@ -563,15 +561,15 @@ agg_get_candidates(char *aggname,
                                                   NameGetDatum(aggname));
 
        pg_aggregate_desc = heap_openr(AggregateRelationName, AccessShareLock);
-       pg_aggregate_scan = heap_beginscan(pg_aggregate_desc,
-                                                                          0,
-                                                                          SnapshotSelf,        /* ??? */
-                                                                          1,
-                                                                          aggKey);
+       pg_aggregate_scan = systable_beginscan(pg_aggregate_desc,
+                                                                                  AggregateNameTypeIndex, true,
+                                                                                  SnapshotNow,
+                                                                                  1, aggKey);
 
-       while (HeapTupleIsValid(tup = heap_getnext(pg_aggregate_scan, 0)))
+       while (HeapTupleIsValid(tup = systable_getnext(pg_aggregate_scan)))
        {
-               agg = (Form_pg_aggregate) GETSTRUCT(tup);
+               Form_pg_aggregate agg = (Form_pg_aggregate) GETSTRUCT(tup);
+               CandidateList current_candidate;
 
                current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
                current_candidate->args = (Oid *) palloc(sizeof(Oid));
@@ -582,7 +580,7 @@ agg_get_candidates(char *aggname,
                ncandidates++;
        }
 
-       heap_endscan(pg_aggregate_scan);
+       systable_endscan(pg_aggregate_scan);
        heap_close(pg_aggregate_desc, AccessShareLock);
 
        return ncandidates;
@@ -680,62 +678,46 @@ static CandidateList
 func_get_candidates(char *funcname, int nargs)
 {
        Relation        heapRelation;
-       Relation        idesc;
-       ScanKeyData skey;
-       HeapTupleData tuple;
-       IndexScanDesc sd;
-       RetrieveIndexResult indexRes;
-       Form_pg_proc pgProcP;
+       ScanKeyData skey[2];
+       HeapTuple       tuple;
+       SysScanDesc     funcscan;
        CandidateList candidates = NULL;
-       CandidateList current_candidate;
        int                     i;
 
        heapRelation = heap_openr(ProcedureRelationName, AccessShareLock);
-       ScanKeyEntryInitialize(&skey,
+
+       ScanKeyEntryInitialize(&skey[0],
                                                   (bits16) 0x0,
                                                   (AttrNumber) Anum_pg_proc_proname,
                                                   (RegProcedure) F_NAMEEQ,
                                                   PointerGetDatum(funcname));
+       ScanKeyEntryInitialize(&skey[1],
+                                                  (bits16) 0x0,
+                                                  (AttrNumber) Anum_pg_proc_pronargs,
+                                                  (RegProcedure) F_INT2EQ,
+                                                  Int16GetDatum(nargs));
 
-       idesc = index_openr(ProcedureNameIndex);
-
-       sd = index_beginscan(idesc, false, 1, &skey);
+       funcscan = systable_beginscan(heapRelation, ProcedureNameIndex, true,
+                                                                 SnapshotNow, 2, skey);
 
-       do
+       while (HeapTupleIsValid(tuple = systable_getnext(funcscan)))
        {
-               indexRes = index_getnext(sd, ForwardScanDirection);
-               if (indexRes)
-               {
-                       Buffer          buffer;
-
-                       tuple.t_datamcxt = NULL;
-                       tuple.t_data = NULL;
-                       tuple.t_self = indexRes->heap_iptr;
-                       heap_fetch(heapRelation, SnapshotNow, &tuple, &buffer, sd);
-                       pfree(indexRes);
-                       if (tuple.t_data != NULL)
-                       {
-                               pgProcP = (Form_pg_proc) GETSTRUCT(&tuple);
-                               if (pgProcP->pronargs == nargs)
-                               {
-                                       current_candidate = (CandidateList)
-                                               palloc(sizeof(struct _CandidateList));
-                                       current_candidate->args = (Oid *)
-                                               palloc(FUNC_MAX_ARGS * sizeof(Oid));
-                                       MemSet(current_candidate->args, 0, FUNC_MAX_ARGS * sizeof(Oid));
-                                       for (i = 0; i < nargs; i++)
-                                               current_candidate->args[i] = pgProcP->proargtypes[i];
-
-                                       current_candidate->next = candidates;
-                                       candidates = current_candidate;
-                               }
-                               ReleaseBuffer(buffer);
-                       }
-               }
-       } while (indexRes);
+               Form_pg_proc pgProcP = (Form_pg_proc) GETSTRUCT(tuple);
+               CandidateList current_candidate;
+
+               current_candidate = (CandidateList)
+                       palloc(sizeof(struct _CandidateList));
+               current_candidate->args = (Oid *)
+                       palloc(FUNC_MAX_ARGS * sizeof(Oid));
+               MemSet(current_candidate->args, 0, FUNC_MAX_ARGS * sizeof(Oid));
+               for (i = 0; i < nargs; i++)
+                       current_candidate->args[i] = pgProcP->proargtypes[i];
+
+               current_candidate->next = candidates;
+               candidates = current_candidate;
+       }
 
-       index_endscan(sd);
-       index_close(idesc);
+       systable_endscan(funcscan);
        heap_close(heapRelation, AccessShareLock);
 
        return candidates;
index 15a39dc84bc4a99aa9a13fb4b32e844ede30c8c0..318f1b9eb7e26f6bc2a23b01205437a6c7de6d0d 100644 (file)
@@ -8,15 +8,17 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.51 2001/10/25 05:49:40 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.52 2002/02/19 20:11:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
+#include "access/genam.h"
 #include "access/heapam.h"
 #include "catalog/catname.h"
+#include "catalog/indexing.h"
 #include "catalog/pg_operator.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_func.h"
@@ -80,13 +82,11 @@ static int
 binary_oper_get_candidates(char *opname,
                                                   CandidateList *candidates)
 {
-       CandidateList current_candidate;
        Relation        pg_operator_desc;
-       HeapScanDesc pg_operator_scan;
+       SysScanDesc     pg_operator_scan;
        HeapTuple       tup;
-       Form_pg_operator oper;
        int                     ncandidates = 0;
-       ScanKeyData opKey[2];
+       ScanKeyData opKey[1];
 
        *candidates = NULL;
 
@@ -95,38 +95,94 @@ binary_oper_get_candidates(char *opname,
                                                   F_NAMEEQ,
                                                   NameGetDatum(opname));
 
-       ScanKeyEntryInitialize(&opKey[1], 0,
-                                                  Anum_pg_operator_oprkind,
-                                                  F_CHAREQ,
-                                                  CharGetDatum('b'));
-
        pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
-       pg_operator_scan = heap_beginscan(pg_operator_desc,
-                                                                         0,
-                                                                         SnapshotSelf,         /* ??? */
-                                                                         2,
-                                                                         opKey);
+       pg_operator_scan = systable_beginscan(pg_operator_desc,
+                                                                                 OperatorNameIndex, true,
+                                                                                 SnapshotNow,
+                                                                                 1, opKey);
 
-       while (HeapTupleIsValid(tup = heap_getnext(pg_operator_scan, 0)))
+       while (HeapTupleIsValid(tup = systable_getnext(pg_operator_scan)))
        {
-               oper = (Form_pg_operator) GETSTRUCT(tup);
+               Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tup);
+
+               if (oper->oprkind == 'b')
+               {
+                       CandidateList current_candidate;
 
-               current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
-               current_candidate->args = (Oid *) palloc(2 * sizeof(Oid));
+                       current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
+                       current_candidate->args = (Oid *) palloc(2 * sizeof(Oid));
 
-               current_candidate->args[0] = oper->oprleft;
-               current_candidate->args[1] = oper->oprright;
-               current_candidate->next = *candidates;
-               *candidates = current_candidate;
-               ncandidates++;
+                       current_candidate->args[0] = oper->oprleft;
+                       current_candidate->args[1] = oper->oprright;
+                       current_candidate->next = *candidates;
+                       *candidates = current_candidate;
+                       ncandidates++;
+               }
        }
 
-       heap_endscan(pg_operator_scan);
+       systable_endscan(pg_operator_scan);
        heap_close(pg_operator_desc, AccessShareLock);
 
        return ncandidates;
 }      /* binary_oper_get_candidates() */
 
+/* unary_oper_get_candidates()
+ *     given opname, find all possible types for which
+ *     a right/left unary operator named opname exists.
+ *     Build a list of the candidate input types.
+ *     Returns number of candidates found.
+ */
+static int
+unary_oper_get_candidates(char *opname,
+                                                 CandidateList *candidates,
+                                                 char rightleft)
+{
+       Relation        pg_operator_desc;
+       SysScanDesc     pg_operator_scan;
+       HeapTuple       tup;
+       int                     ncandidates = 0;
+       ScanKeyData opKey[1];
+
+       *candidates = NULL;
+
+       ScanKeyEntryInitialize(&opKey[0], 0,
+                                                  Anum_pg_operator_oprname,
+                                                  F_NAMEEQ,
+                                                  NameGetDatum(opname));
+
+       pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
+       pg_operator_scan = systable_beginscan(pg_operator_desc,
+                                                                                 OperatorNameIndex, true,
+                                                                                 SnapshotNow,
+                                                                                 1, opKey);
+
+       while (HeapTupleIsValid(tup = systable_getnext(pg_operator_scan)))
+       {
+               Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tup);
+
+               if (oper->oprkind == rightleft)
+               {
+                       CandidateList current_candidate;
+
+                       current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
+                       current_candidate->args = (Oid *) palloc(sizeof(Oid));
+
+                       if (rightleft == 'r')
+                               current_candidate->args[0] = oper->oprleft;
+                       else
+                               current_candidate->args[0] = oper->oprright;
+                       current_candidate->next = *candidates;
+                       *candidates = current_candidate;
+                       ncandidates++;
+               }
+       }
+
+       systable_endscan(pg_operator_scan);
+       heap_close(pg_operator_desc, AccessShareLock);
+
+       return ncandidates;
+}      /* unary_oper_get_candidates() */
+
 
 /* oper_select_candidate()
  * Given the input argtype array and one or more candidates
@@ -739,66 +795,6 @@ compatible_oper_funcid(char *op, Oid arg1, Oid arg2, bool noError)
        return InvalidOid;
 }
 
-/* unary_oper_get_candidates()
- *     given opname, find all possible types for which
- *     a right/left unary operator named opname exists.
- *     Build a list of the candidate input types.
- *     Returns number of candidates found.
- */
-static int
-unary_oper_get_candidates(char *opname,
-                                                 CandidateList *candidates,
-                                                 char rightleft)
-{
-       CandidateList current_candidate;
-       Relation        pg_operator_desc;
-       HeapScanDesc pg_operator_scan;
-       HeapTuple       tup;
-       Form_pg_operator oper;
-       int                     ncandidates = 0;
-       ScanKeyData opKey[2];
-
-       *candidates = NULL;
-
-       ScanKeyEntryInitialize(&opKey[0], 0,
-                                                  Anum_pg_operator_oprname,
-                                                  F_NAMEEQ,
-                                                  NameGetDatum(opname));
-
-       ScanKeyEntryInitialize(&opKey[1], 0,
-                                                  Anum_pg_operator_oprkind,
-                                                  F_CHAREQ,
-                                                  CharGetDatum(rightleft));
-
-       pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
-       pg_operator_scan = heap_beginscan(pg_operator_desc,
-                                                                         0,
-                                                                         SnapshotSelf,         /* ??? */
-                                                                         2,
-                                                                         opKey);
-
-       while (HeapTupleIsValid(tup = heap_getnext(pg_operator_scan, 0)))
-       {
-               oper = (Form_pg_operator) GETSTRUCT(tup);
-
-               current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
-               current_candidate->args = (Oid *) palloc(sizeof(Oid));
-
-               if (rightleft == 'r')
-                       current_candidate->args[0] = oper->oprleft;
-               else
-                       current_candidate->args[0] = oper->oprright;
-               current_candidate->next = *candidates;
-               *candidates = current_candidate;
-               ncandidates++;
-       }
-
-       heap_endscan(pg_operator_scan);
-       heap_close(pg_operator_desc, AccessShareLock);
-
-       return ncandidates;
-}      /* unary_oper_get_candidates() */
-
 
 /* Given unary right operator (operator on right), return oper struct
  *
index 27abf6ace505ed9bc418a642dfdff1b3584819d2..95e217b9a4fae4de388ab63a6dbdf999ba0d4ae0 100644 (file)
@@ -3,7 +3,7 @@
  *                             back to source text
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.89 2001/11/26 21:15:14 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.90 2002/02/19 20:11:16 tgl Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -341,6 +341,7 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
        HeapTuple       ht_idx;
        HeapTuple       ht_idxrel;
        HeapTuple       ht_indrel;
+       HeapTuple       ht_am;
        Form_pg_index idxrec;
        Form_pg_class idxrelrec;
        Form_pg_class indrelrec;
@@ -383,13 +384,13 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
 
        /*
         * Fetch the pg_am tuple of the index' access method
-        *
-        * There is no syscache for this, so use index.c subroutine.
         */
-       amrec = AccessMethodObjectIdGetForm(idxrelrec->relam,
-                                                                               CurrentMemoryContext);
-       if (!amrec)
-               elog(ERROR, "lookup for AM %u failed", idxrelrec->relam);
+       ht_am = SearchSysCache(AMOID,
+                                                  ObjectIdGetDatum(idxrelrec->relam),
+                                                  0, 0, 0);
+       if (!HeapTupleIsValid(ht_am))
+               elog(ERROR, "syscache lookup for AM %u failed", idxrelrec->relam);
+       amrec = (Form_pg_am) GETSTRUCT(ht_am);
 
        /*
         * Start the index definition
@@ -504,10 +505,11 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
 
        pfree(buf.data);
        pfree(keybuf.data);
-       pfree(amrec);
+
        ReleaseSysCache(ht_idx);
        ReleaseSysCache(ht_idxrel);
        ReleaseSysCache(ht_indrel);
+       ReleaseSysCache(ht_am);
 
        PG_RETURN_TEXT_P(indexdef);
 }
index cab6291acd08a6b3af97b560150826e611b736ac..47ab410cfc235c5be152d071cd8248b7a8fbb67b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.86 2001/11/05 17:46:30 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.87 2002/02/19 20:11:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "catalog/catname.h"
 #include "catalog/indexing.h"
 #include "miscadmin.h"
+#ifdef CATCACHE_STATS
+#include "storage/ipc.h"               /* for on_proc_exit */
+#endif
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/catcache.h"
+#include "utils/relcache.h"
 #include "utils/syscache.h"
 
 
@@ -94,6 +98,9 @@ static Index CatalogCacheComputeTupleHashIndex(CatCache *cache,
                                                                  HeapTuple tuple);
 static void CatalogCacheInitializeCache(CatCache *cache);
 static Datum cc_hashname(PG_FUNCTION_ARGS);
+#ifdef CATCACHE_STATS
+static void CatCachePrintStats(void);
+#endif
 
 
 /*
@@ -147,6 +154,46 @@ cc_hashname(PG_FUNCTION_ARGS)
 }
 
 
+#ifdef CATCACHE_STATS
+
+static void
+CatCachePrintStats(void)
+{
+       CatCache   *cache;
+       long            cc_searches = 0;
+       long            cc_hits = 0;
+       long            cc_newloads = 0;
+
+       elog(DEBUG, "Catcache stats dump: %d/%d tuples in catcaches",
+                CacheHdr->ch_ntup, CacheHdr->ch_maxtup);
+
+       for (cache = CacheHdr->ch_caches; cache; cache = cache->cc_next)
+       {
+               if (cache->cc_ntup == 0 && cache->cc_searches == 0)
+                       continue;                       /* don't print unused caches */
+               elog(DEBUG, "Catcache %s/%s: %d tup, %ld srch, %ld hits, %ld loads, %ld not found",
+                        cache->cc_relname,
+                        cache->cc_indname,
+                        cache->cc_ntup,
+                        cache->cc_searches,
+                        cache->cc_hits,
+                        cache->cc_newloads,
+                        cache->cc_searches - cache->cc_hits - cache->cc_newloads);
+               cc_searches += cache->cc_searches;
+               cc_hits += cache->cc_hits;
+               cc_newloads += cache->cc_newloads;
+       }
+       elog(DEBUG, "Catcache totals: %d tup, %ld srch, %ld hits, %ld loads, %ld not found",
+                CacheHdr->ch_ntup,
+                cc_searches,
+                cc_hits,
+                cc_newloads,
+                cc_searches - cc_hits - cc_newloads);
+}
+
+#endif /* CATCACHE_STATS */
+
+
 /*
  * Standard routine for creating cache context if it doesn't exist yet
  *
@@ -289,6 +336,30 @@ CatalogCacheInitializeCache(CatCache *cache)
        cache->cc_tupdesc = tupdesc;
 }
 
+/*
+ * InitCatCachePhase2 -- external interface for CatalogCacheInitializeCache
+ *
+ * The only reason to call this routine is to ensure that the relcache
+ * has created entries for all the catalogs and indexes referenced by
+ * catcaches.  Therefore, open the index too.  An exception is the indexes
+ * on pg_am, which we don't use (cf. IndexScanOK).
+ */
+void
+InitCatCachePhase2(CatCache *cache)
+{
+       if (cache->cc_tupdesc == NULL)
+               CatalogCacheInitializeCache(cache);
+
+       if (cache->id != AMOID &&
+               cache->id != AMNAME)
+       {
+               Relation        idesc;
+
+               idesc = index_openr(cache->cc_indname);
+               index_close(idesc);
+       }
+}
+
 /*
  *             CatalogCacheComputeHashIndex
  */
@@ -644,11 +715,11 @@ CatalogCacheFlushRelation(Oid relId)
                                {
                                        bool            isNull;
 
-                                       tupRelid = DatumGetObjectId(
-                                                                                               fastgetattr(&ct->tuple,
-                                                                                                       cache->cc_reloidattr,
-                                                                                                          cache->cc_tupdesc,
-                                                                                                                       &isNull));
+                                       tupRelid =
+                                               DatumGetObjectId(fastgetattr(&ct->tuple,
+                                                                                                        cache->cc_reloidattr,
+                                                                                                        cache->cc_tupdesc,
+                                                                                                        &isNull));
                                        Assert(!isNull);
                                }
 
@@ -717,20 +788,19 @@ InitCatCache(int id,
                CacheHdr->ch_ntup = 0;
                CacheHdr->ch_maxtup = MAXCCTUPLES;
                DLInitList(&CacheHdr->ch_lrulist);
+#ifdef CATCACHE_STATS
+               on_proc_exit(CatCachePrintStats, 0);
+#endif
        }
 
        /*
         * allocate a new cache structure
+        *
+        * Note: we assume zeroing initializes the bucket headers correctly
         */
        cp = (CatCache *) palloc(sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist));
        MemSet((char *) cp, 0, sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist));
 
-       /*
-        * initialize the cache buckets (each bucket is a list header)
-        */
-       for (i = 0; i < NCCBUCKETS; ++i)
-               DLInitList(&cp->cc_bucket[i]);
-
        /*
         * initialize the cache's relation information for the relation
         * corresponding to this cache, and initialize some of the new cache's
@@ -777,57 +847,44 @@ InitCatCache(int id,
  *             certain system indexes that support critical syscaches.
  *             We can't use an indexscan to fetch these, else we'll get into
  *             infinite recursion.  A plain heap scan will work, however.
+ *
+ *             Once we have completed relcache initialization (signaled by
+ *             criticalRelcachesBuilt), we don't have to worry anymore.
  */
 static bool
 IndexScanOK(CatCache *cache, ScanKey cur_skey)
 {
        if (cache->id == INDEXRELID)
        {
-               static Oid      indexSelfOid = InvalidOid;
-
-               /* One-time lookup of the OID of pg_index_indexrelid_index */
-               if (!OidIsValid(indexSelfOid))
-               {
-                       Relation        rel;
-                       ScanKeyData key;
-                       HeapScanDesc sd;
-                       HeapTuple       ntp;
-
-                       rel = heap_openr(RelationRelationName, AccessShareLock);
-                       ScanKeyEntryInitialize(&key, 0, Anum_pg_class_relname,
-                                                                  F_NAMEEQ,
-                                                                  PointerGetDatum(IndexRelidIndex));
-                       sd = heap_beginscan(rel, false, SnapshotNow, 1, &key);
-                       ntp = heap_getnext(sd, 0);
-                       if (!HeapTupleIsValid(ntp))
-                               elog(ERROR, "IndexScanOK: %s not found in %s",
-                                        IndexRelidIndex, RelationRelationName);
-                       indexSelfOid = ntp->t_data->t_oid;
-                       heap_endscan(sd);
-                       heap_close(rel, AccessShareLock);
-               }
-
-               /* Looking for pg_index_indexrelid_index? */
-               if (DatumGetObjectId(cur_skey[0].sk_argument) == indexSelfOid)
+               /*
+                * Since the OIDs of indexes aren't hardwired, it's painful to
+                * figure out which is which.  Just force all pg_index searches
+                * to be heap scans while building the relcaches.
+                */
+               if (!criticalRelcachesBuilt)
                        return false;
        }
-       else if (cache->id == AMOPSTRATEGY ||
-                        cache->id == AMPROCNUM)
+       else if (cache->id == AMOID ||
+                        cache->id == AMNAME)
        {
-               /* Looking for an OID or INT2 btree operator or function? */
-               Oid                     lookup_oid = DatumGetObjectId(cur_skey[0].sk_argument);
-
-               if (lookup_oid == OID_BTREE_OPS_OID ||
-                       lookup_oid == INT2_BTREE_OPS_OID)
-                       return false;
+               /*
+                * Always do heap scans in pg_am, because it's so small there's
+                * not much point in an indexscan anyway.  We *must* do this when
+                * initially building critical relcache entries, but we might as
+                * well just always do it.
+                */
+               return false;
        }
        else if (cache->id == OPEROID)
        {
-               /* Looking for an OID comparison function? */
-               Oid                     lookup_oid = DatumGetObjectId(cur_skey[0].sk_argument);
+               if (!criticalRelcachesBuilt)
+               {
+                       /* Looking for an OID comparison function? */
+                       Oid             lookup_oid = DatumGetObjectId(cur_skey[0].sk_argument);
 
-               if (lookup_oid >= MIN_OIDCMP && lookup_oid <= MAX_OIDCMP)
-                       return false;
+                       if (lookup_oid >= MIN_OIDCMP && lookup_oid <= MAX_OIDCMP)
+                               return false;
+               }
        }
 
        /* Normal case, allow index scan */
@@ -861,6 +918,10 @@ SearchCatCache(CatCache *cache,
        if (cache->cc_tupdesc == NULL)
                CatalogCacheInitializeCache(cache);
 
+#ifdef CATCACHE_STATS
+       cache->cc_searches++;
+#endif
+
        /*
         * initialize the search key information
         */
@@ -919,6 +980,10 @@ SearchCatCache(CatCache *cache,
                                        cache->cc_relname, hash);
 #endif   /* CACHEDEBUG */
 
+#ifdef CATCACHE_STATS
+               cache->cc_hits++;
+#endif
+
                return &ct->tuple;
        }
 
@@ -1046,6 +1111,10 @@ SearchCatCache(CatCache *cache,
        DLAddHead(&CacheHdr->ch_lrulist, &ct->lrulist_elem);
        DLAddHead(&cache->cc_bucket[hash], &ct->cache_elem);
 
+#ifdef CATCACHE_STATS
+       cache->cc_newloads++;
+#endif
+
        /*
         * If we've exceeded the desired size of the caches, try to throw away
         * the least recently used entry.
index 40d79942d5e0203e137d5bed7ff14e0207c9cb28..0e383b32c8417bfd9e1c123d7b8f33081cba92a8 100644 (file)
  *     (XXX is it worth testing likewise for duplicate catcache flush entries?
  *     Probably not.)
  *
+ *     If a relcache flush is issued for a system relation that we preload
+ *     from the relcache init file, we must also delete the init file so that
+ *     it will be rebuilt during the next backend restart.  The actual work of
+ *     manipulating the init file is in relcache.c, but we keep track of the
+ *     need for it here.
+ *
  *     All the request lists are kept in TopTransactionContext memory, since
  *     they need not live beyond the end of the current transaction.
  *
@@ -56,7 +62,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.47 2001/11/16 23:30:35 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.48 2002/02/19 20:11:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -107,6 +113,8 @@ typedef struct InvalidationListHeader
  */
 static InvalidationListHeader GlobalInvalidMsgs;
 
+static bool RelcacheInitFileInval; /* init file must be invalidated? */
+
 /*
  * head of invalidation message list for the current command
  * eaten by AtCommit_LocalCache() in CommandCounterIncrement()
@@ -339,6 +347,13 @@ RegisterRelcacheInvalidation(Oid dbId, Oid relId)
                                                                   dbId, relId);
        AddRelcacheInvalidationMessage(&LocalInvalidMsgs,
                                                                   dbId, relId);
+
+       /*
+        * If the relation being invalidated is one of those cached in the
+        * relcache init file, mark that we need to zap that file at commit.
+        */
+       if (RelationIdIsInInitFile(relId))
+               RelcacheInitFileInval = true;
 }
 
 /*
@@ -418,8 +433,8 @@ InvalidateSystemCaches(void)
 
 /*
  * PrepareForTupleInvalidation
- *             Invoke functions for the tuple which register invalidation
- *             of catalog/relation cache.
+ *             Detect whether invalidation of this tuple implies invalidation
+ *             of catalog/relation cache entries; if so, register inval events.
  */
 static void
 PrepareForTupleInvalidation(Relation relation, HeapTuple tuple,
@@ -525,8 +540,19 @@ AtEOXactInvalidationMessages(bool isCommit)
 {
        if (isCommit)
        {
+               /*
+                * Relcache init file invalidation requires processing both
+                * before and after we send the SI messages.  However, we need
+                * not do anything unless we committed.
+                */
+               if (RelcacheInitFileInval)
+                       RelationCacheInitFileInvalidate(true);
+
                ProcessInvalidationMessages(&GlobalInvalidMsgs,
                                                                        SendSharedInvalidMessage);
+
+               if (RelcacheInitFileInval)
+                       RelationCacheInitFileInvalidate(false);
        }
        else
        {
@@ -534,6 +560,8 @@ AtEOXactInvalidationMessages(bool isCommit)
                                                                        LocalExecuteInvalidationMessage);
        }
 
+       RelcacheInitFileInval = false;
+
        DiscardInvalidationMessages(&GlobalInvalidMsgs, false);
        DiscardInvalidationMessages(&LocalInvalidMsgs, false);
        DiscardInvalidationMessages(&RollbackMsgs, false);
index 16a38df83d3cd60d894569e2be43d2521e0ed0f0..cd5162ac81c2e12579e2e76a9433075190a72fed 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.151 2002/01/16 17:34:42 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.152 2002/02/19 20:11:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "catalog/catname.h"
 #include "catalog/index.h"
 #include "catalog/indexing.h"
+#include "catalog/pg_amop.h"
+#include "catalog/pg_amproc.h"
 #include "catalog/pg_attrdef.h"
+#include "catalog/pg_attribute.h"
 #include "catalog/pg_index.h"
+#include "catalog/pg_opclass.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_relcheck.h"
 #include "catalog/pg_rewrite.h"
 #include "utils/builtins.h"
 #include "utils/catcache.h"
 #include "utils/fmgroids.h"
-#include "utils/hsearch.h"
-#include "utils/memutils.h"
+#include "utils/inval.h"
+#include "utils/lsyscache.h"
 #include "utils/relcache.h"
+#include "utils/syscache.h"
 #include "utils/temprel.h"
 
 
+/*
+ * name of relcache init file, used to speed up backend startup
+ */
+#define RELCACHE_INIT_FILENAME "pg_internal.init"
+
 /*
  *             hardcoded tuple descriptors.  see lib/backend/catalog/pg_attribute.h
  */
@@ -88,14 +98,33 @@ static HTAB *RelationNodeCache;
  *       relations created during this transaction. We need to keep track of
  *       these.
  */
-static List *newlyCreatedRelns = NULL;
+static List *newlyCreatedRelns = NIL;
 
 /*
  * This flag is false until we have prepared the critical relcache entries
  * that are needed to do indexscans on the tables read by relcache building.
  */
-static bool criticalRelcachesBuilt = false;
+bool criticalRelcachesBuilt = false;
+
+/*
+ * This flag is set if we discover that we need to write a new relcache
+ * cache file at the end of startup.
+ */
+static bool needNewCacheFile = false;
+
+/*
+ * This counter counts relcache inval events received since backend startup
+ * (but only for rels that are actually in cache).  Presently, we use it only
+ * to detect whether data about to be written by write_relcache_init_file()
+ * might already be obsolete.
+ */
+static long relcacheInvalsReceived = 0L;
 
+/*
+ * This list remembers the OIDs of the relations cached in the relcache
+ * init file.
+ */
+static List *initFileRelationIds = NIL;
 
 /*
  *             RelationBuildDescInfo exists so code can be shared
@@ -220,6 +249,24 @@ do { \
                elog(NOTICE, "trying to delete a reldesc that does not exist."); \
 } while(0)
 
+
+/*
+ * Special cache for opclass-related information
+ */
+typedef struct opclasscacheent
+{
+       Oid                     opclassoid;             /* lookup key: OID of opclass */
+       bool            valid;                  /* set TRUE after successful fill-in */
+       StrategyNumber numStrats;       /* max # of strategies (from pg_am) */
+       StrategyNumber numSupport;      /* max # of support procs (from pg_am) */
+       Oid                *operatorOids;       /* strategy operators' OIDs */
+       RegProcedure *operatorProcs; /* strategy operators' procs */
+       RegProcedure *supportProcs;     /* support procs */
+} OpClassCacheEnt;
+
+static HTAB *OpClassCache = NULL;
+
+
 /* non-export function prototypes */
 
 static void RelationClearRelation(Relation relation, bool rebuildIt);
@@ -229,28 +276,31 @@ static void RelationReloadClassinfo(Relation relation);
 #endif   /* ENABLE_REINDEX_NAILED_RELATIONS */
 static void RelationFlushRelation(Relation relation);
 static Relation RelationNameCacheGetRelation(const char *relationName);
-static void init_irels(void);
-static void write_irels(void);
+static bool load_relcache_init_file(void);
+static void write_relcache_init_file(void);
 
 static void formrdesc(char *relationName, int natts,
                  FormData_pg_attribute *att);
-static void fixrdesc(char *relationName);
 
 static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo);
-static HeapTuple scan_pg_rel_seq(RelationBuildDescInfo buildinfo);
-static HeapTuple scan_pg_rel_ind(RelationBuildDescInfo buildinfo);
 static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);
 static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
                                           Relation relation);
-static void build_tupdesc_seq(RelationBuildDescInfo buildinfo,
-                                 Relation relation);
-static void build_tupdesc_ind(RelationBuildDescInfo buildinfo,
-                                 Relation relation);
 static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo,
                                  Relation oldrelation);
 static void AttrDefaultFetch(Relation relation);
 static void RelCheckFetch(Relation relation);
 static List *insert_ordered_oid(List *list, Oid datum);
+static void IndexSupportInitialize(Form_pg_index iform,
+                                                                  IndexStrategy indexStrategy,
+                                                                  Oid *indexOperator,
+                                                                  RegProcedure *indexSupport,
+                                                                  StrategyNumber maxStrategyNumber,
+                                                                  StrategyNumber maxSupportNumber,
+                                                                  AttrNumber maxAttributeNumber);
+static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
+                                                                                 StrategyNumber numStrats,
+                                                                                 StrategyNumber numSupport);
 
 
 /*
@@ -271,26 +321,11 @@ static List *insert_ordered_oid(List *list, Oid datum);
  */
 static HeapTuple
 ScanPgRelation(RelationBuildDescInfo buildinfo)
-{
-       /*
-        * If this is bootstrap time (initdb), then we can't use the system
-        * catalog indices, because they may not exist yet.  Otherwise, we
-        * can, and do.
-        */
-
-       if (IsIgnoringSystemIndexes() || !criticalRelcachesBuilt)
-               return scan_pg_rel_seq(buildinfo);
-       else
-               return scan_pg_rel_ind(buildinfo);
-}
-
-static HeapTuple
-scan_pg_rel_seq(RelationBuildDescInfo buildinfo)
 {
        HeapTuple       pg_class_tuple;
-       HeapTuple       return_tuple;
        Relation        pg_class_desc;
-       HeapScanDesc pg_class_scan;
+       const char *indexRelname;
+       SysScanDesc pg_class_scan;
        ScanKeyData key;
 
        /*
@@ -303,6 +338,7 @@ scan_pg_rel_seq(RelationBuildDescInfo buildinfo)
                                                                   ObjectIdAttributeNumber,
                                                                   F_OIDEQ,
                                                                   ObjectIdGetDatum(buildinfo.i.info_id));
+                       indexRelname = ClassOidIndex;
                        break;
 
                case INFO_RELNAME:
@@ -310,83 +346,38 @@ scan_pg_rel_seq(RelationBuildDescInfo buildinfo)
                                                                   Anum_pg_class_relname,
                                                                   F_NAMEEQ,
                                                                   NameGetDatum(buildinfo.i.info_name));
+                       indexRelname = ClassNameIndex;
                        break;
 
                default:
                        elog(ERROR, "ScanPgRelation: bad buildinfo");
-                       return NULL;
+                       return NULL;            /* keep compiler quiet */
        }
 
        /*
-        * open pg_class and fetch a tuple
+        * Open pg_class and fetch a tuple.  Force heap scan if we haven't
+        * yet built the critical relcache entries (this includes initdb
+        * and startup without a pg_internal.init file).
         */
        pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
-       pg_class_scan = heap_beginscan(pg_class_desc, 0, SnapshotNow, 1, &key);
-       pg_class_tuple = heap_getnext(pg_class_scan, 0);
-
-       /*
-        * get set to return tuple
-        */
-       if (!HeapTupleIsValid(pg_class_tuple))
-               return_tuple = pg_class_tuple;
-       else
-       {
-               /*
-                * a satanic bug used to live here: pg_class_tuple used to be
-                * returned here without having the corresponding buffer pinned.
-                * so when the buffer gets replaced, all hell breaks loose. this
-                * bug is discovered and killed by wei on 9/27/91.
-                */
-               return_tuple = heap_copytuple(pg_class_tuple);
-       }
-
-       /* all done */
-       heap_endscan(pg_class_scan);
-       heap_close(pg_class_desc, AccessShareLock);
-
-       return return_tuple;
-}
+       pg_class_scan = systable_beginscan(pg_class_desc, indexRelname,
+                                                                          criticalRelcachesBuilt,
+                                                                          SnapshotNow,
+                                                                          1, &key);
 
-static HeapTuple
-scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
-{
-       Relation        pg_class_desc;
-       HeapTuple       return_tuple;
-
-       pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
+       pg_class_tuple = systable_getnext(pg_class_scan);
 
        /*
-        * If the indexes of pg_class are deactivated we have to call
-        * scan_pg_rel_seq() instead.
+        * Must copy tuple before releasing buffer.
         */
-       if (!pg_class_desc->rd_rel->relhasindex)
-       {
-               heap_close(pg_class_desc, AccessShareLock);
-               return scan_pg_rel_seq(buildinfo);
-       }
-
-       switch (buildinfo.infotype)
-       {
-               case INFO_RELID:
-                       return_tuple = ClassOidIndexScan(pg_class_desc,
-                                                                 ObjectIdGetDatum(buildinfo.i.info_id));
-                       break;
-
-               case INFO_RELNAME:
-                       return_tuple = ClassNameIndexScan(pg_class_desc,
-                                                                PointerGetDatum(buildinfo.i.info_name));
-                       break;
-
-               default:
-                       elog(ERROR, "ScanPgRelation: bad buildinfo");
-                       return_tuple = NULL;    /* keep compiler quiet */
-       }
+       if (HeapTupleIsValid(pg_class_tuple))
+               pg_class_tuple = heap_copytuple(pg_class_tuple);
 
+       /* all done */
+       systable_endscan(pg_class_scan);
        heap_close(pg_class_desc, AccessShareLock);
 
-       /* The xxxIndexScan routines will have returned a palloc'd tuple. */
-
-       return return_tuple;
+       return pg_class_tuple;
 }
 
 /*
@@ -452,75 +443,16 @@ AllocateRelationDesc(Relation relation, Form_pg_class relp)
  *             RelationBuildTupleDesc
  *
  *             Form the relation's tuple descriptor from information in
- *             the pg_attribute, pg_attrdef & pg_relcheck system cataloges.
+ *             the pg_attribute, pg_attrdef & pg_relcheck system catalogs.
  */
 static void
 RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
                                           Relation relation)
-{
-       /*
-        * If this is bootstrap time (initdb), then we can't use the system
-        * catalog indices, because they may not exist yet.  Otherwise, we
-        * can, and do.
-        */
-
-       if (IsIgnoringSystemIndexes() || !criticalRelcachesBuilt)
-               build_tupdesc_seq(buildinfo, relation);
-       else
-               build_tupdesc_ind(buildinfo, relation);
-}
-
-static void
-SetConstrOfRelation(Relation relation,
-                                       TupleConstr *constr,
-                                       int ndef,
-                                       AttrDefault *attrdef)
-{
-       if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks)
-       {
-               relation->rd_att->constr = constr;
-
-               if (ndef > 0)                   /* DEFAULTs */
-               {
-                       if (ndef < relation->rd_rel->relnatts)
-                               constr->defval = (AttrDefault *)
-                                       repalloc(attrdef, ndef * sizeof(AttrDefault));
-                       else
-                               constr->defval = attrdef;
-                       constr->num_defval = ndef;
-                       AttrDefaultFetch(relation);
-               }
-               else
-                       constr->num_defval = 0;
-
-               if (relation->rd_rel->relchecks > 0)    /* CHECKs */
-               {
-                       constr->num_check = relation->rd_rel->relchecks;
-                       constr->check = (ConstrCheck *)
-                               MemoryContextAlloc(CacheMemoryContext,
-                                                               constr->num_check * sizeof(ConstrCheck));
-                       MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck));
-                       RelCheckFetch(relation);
-               }
-               else
-                       constr->num_check = 0;
-       }
-       else
-       {
-               pfree(constr);
-               relation->rd_att->constr = NULL;
-       }
-}
-
-static void
-build_tupdesc_seq(RelationBuildDescInfo buildinfo,
-                                 Relation relation)
 {
        HeapTuple       pg_attribute_tuple;
        Relation        pg_attribute_desc;
-       HeapScanDesc pg_attribute_scan;
-       Form_pg_attribute attp;
-       ScanKeyData key;
+       SysScanDesc pg_attribute_scan;
+       ScanKeyData skey[2];
        int                     need;
        TupleConstr *constr;
        AttrDefault *attrdef = NULL;
@@ -531,73 +463,89 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
        constr->has_not_null = false;
 
        /*
-        * form a scan key
+        * Form a scan key that selects only user attributes (attnum > 0).
+        * (Eliminating system attribute rows at the index level is lots
+        * faster than fetching them.)
         */
-       ScanKeyEntryInitialize(&key, 0,
+       ScanKeyEntryInitialize(&skey[0], 0,
                                                   Anum_pg_attribute_attrelid,
                                                   F_OIDEQ,
                                                   ObjectIdGetDatum(RelationGetRelid(relation)));
+       ScanKeyEntryInitialize(&skey[1], 0,
+                                                  Anum_pg_attribute_attnum,
+                                                  F_INT2GT,
+                                                  Int16GetDatum(0));
 
        /*
-        * open pg_attribute and begin a scan
+        * Open pg_attribute and begin a scan.  Force heap scan if we haven't
+        * yet built the critical relcache entries (this includes initdb
+        * and startup without a pg_internal.init file).
         */
        pg_attribute_desc = heap_openr(AttributeRelationName, AccessShareLock);
-       pg_attribute_scan = heap_beginscan(pg_attribute_desc, 0, SnapshotNow, 1, &key);
+       pg_attribute_scan = systable_beginscan(pg_attribute_desc,
+                                                                                  AttributeRelidNumIndex,
+                                                                                  criticalRelcachesBuilt,
+                                                                                  SnapshotNow,
+                                                                                  2, skey);
 
        /*
         * add attribute data to relation->rd_att
         */
        need = relation->rd_rel->relnatts;
 
-       pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
-       while (HeapTupleIsValid(pg_attribute_tuple) && need > 0)
+       while (HeapTupleIsValid(pg_attribute_tuple = systable_getnext(pg_attribute_scan)))
        {
+               Form_pg_attribute attp;
+
                attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
 
-               if (attp->attnum > 0)
-               {
-                       relation->rd_att->attrs[attp->attnum - 1] =
-                               (Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext,
+               if (attp->attnum <= 0 ||
+                       attp->attnum > relation->rd_rel->relnatts)
+                       elog(ERROR, "Bogus attribute number %d for %s",
+                                attp->attnum, RelationGetRelationName(relation));
+
+               relation->rd_att->attrs[attp->attnum - 1] =
+                       (Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext,
                                                                                                   ATTRIBUTE_TUPLE_SIZE);
 
-                       memcpy((char *) (relation->rd_att->attrs[attp->attnum - 1]),
-                                  (char *) attp,
-                                  ATTRIBUTE_TUPLE_SIZE);
-                       need--;
+               memcpy((char *) (relation->rd_att->attrs[attp->attnum - 1]),
+                          (char *) attp,
+                          ATTRIBUTE_TUPLE_SIZE);
 
-                       /* Update if this attribute have a constraint */
-                       if (attp->attnotnull)
-                               constr->has_not_null = true;
+               /* Update constraint/default info */
+               if (attp->attnotnull)
+                       constr->has_not_null = true;
 
-                       if (attp->atthasdef)
+               if (attp->atthasdef)
+               {
+                       if (attrdef == NULL)
                        {
-                               if (attrdef == NULL)
-                               {
-                                       attrdef = (AttrDefault *)
-                                               MemoryContextAlloc(CacheMemoryContext,
-                                                                                  relation->rd_rel->relnatts *
-                                                                                  sizeof(AttrDefault));
-                                       MemSet(attrdef, 0,
+                               attrdef = (AttrDefault *)
+                                       MemoryContextAlloc(CacheMemoryContext,
+                                                                          relation->rd_rel->relnatts *
+                                                                          sizeof(AttrDefault));
+                               MemSet(attrdef, 0,
                                           relation->rd_rel->relnatts * sizeof(AttrDefault));
-                               }
-                               attrdef[ndef].adnum = attp->attnum;
-                               attrdef[ndef].adbin = NULL;
-                               ndef++;
                        }
+                       attrdef[ndef].adnum = attp->attnum;
+                       attrdef[ndef].adbin = NULL;
+                       ndef++;
                }
-               pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
+               need--;
+               if (need == 0)
+                       break;
        }
 
-       if (need > 0)
-               elog(ERROR, "catalog is missing %d attribute%s for relid %u",
-                        need, (need == 1 ? "" : "s"), RelationGetRelid(relation));
-
        /*
         * end the scan and close the attribute relation
         */
-       heap_endscan(pg_attribute_scan);
+       systable_endscan(pg_attribute_scan);
        heap_close(pg_attribute_desc, AccessShareLock);
 
+       if (need != 0)
+               elog(ERROR, "catalog is missing %d attribute(s) for relid %u",
+                        need, RelationGetRelid(relation));
+
        /*
         * The attcacheoff values we read from pg_attribute should all be -1
         * ("unknown").  Verify this if assert checking is on.  They will be
@@ -620,110 +568,43 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
         */
        relation->rd_att->attrs[0]->attcacheoff = 0;
 
-       SetConstrOfRelation(relation, constr, ndef, attrdef);
-}
-
-static void
-build_tupdesc_ind(RelationBuildDescInfo buildinfo,
-                                 Relation relation)
-{
-       Relation        attrel;
-       HeapTuple       atttup;
-       Form_pg_attribute attp;
-       TupleConstr *constr;
-       AttrDefault *attrdef = NULL;
-       int                     ndef = 0;
-       int                     i;
-
-       constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext,
-                                                                                               sizeof(TupleConstr));
-       constr->has_not_null = false;
-
-       attrel = heap_openr(AttributeRelationName, AccessShareLock);
-
-       for (i = 1; i <= relation->rd_rel->relnatts; i++)
+       /*
+        * Set up constraint/default info
+        */
+       if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks)
        {
-#ifdef _DROP_COLUMN_HACK__
-               bool            columnDropped = false;
-#endif   /* _DROP_COLUMN_HACK__ */
-
-               atttup = AttributeRelidNumIndexScan(attrel,
-                                                       ObjectIdGetDatum(RelationGetRelid(relation)),
-                                                                                       Int32GetDatum(i));
+               relation->rd_att->constr = constr;
 
-               if (!HeapTupleIsValid(atttup))
+               if (ndef > 0)                   /* DEFAULTs */
                {
-#ifdef _DROP_COLUMN_HACK__
-                       atttup = AttributeRelidNumIndexScan(attrel,
-                                                       ObjectIdGetDatum(RelationGetRelid(relation)),
-                                                                Int32GetDatum(DROPPED_COLUMN_INDEX(i)));
-                       if (!HeapTupleIsValid(atttup))
-#endif   /* _DROP_COLUMN_HACK__ */
-                               elog(ERROR, "cannot find attribute %d of relation %s", i,
-                                        RelationGetRelationName(relation));
-#ifdef _DROP_COLUMN_HACK__
-                       columnDropped = true;
-#endif   /* _DROP_COLUMN_HACK__ */
+                       if (ndef < relation->rd_rel->relnatts)
+                               constr->defval = (AttrDefault *)
+                                       repalloc(attrdef, ndef * sizeof(AttrDefault));
+                       else
+                               constr->defval = attrdef;
+                       constr->num_defval = ndef;
+                       AttrDefaultFetch(relation);
                }
+               else
+                       constr->num_defval = 0;
 
-               relation->rd_att->attrs[i - 1] = attp =
-                       (Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext,
-                                                                                                  ATTRIBUTE_TUPLE_SIZE);
-
-               memcpy((char *) attp,
-                          (char *) (Form_pg_attribute) GETSTRUCT(atttup),
-                          ATTRIBUTE_TUPLE_SIZE);
-
-               /* don't forget to free the tuple returned from xxxIndexScan */
-               heap_freetuple(atttup);
-
-#ifdef _DROP_COLUMN_HACK__
-               if (columnDropped)
-                       continue;
-#endif   /* _DROP_COLUMN_HACK__ */
-
-               /* Update if this attribute have a constraint */
-               if (attp->attnotnull)
-                       constr->has_not_null = true;
-
-               if (attp->atthasdef)
+               if (relation->rd_rel->relchecks > 0)    /* CHECKs */
                {
-                       if (attrdef == NULL)
-                       {
-                               attrdef = (AttrDefault *)
-                                       MemoryContextAlloc(CacheMemoryContext,
-                                                                          relation->rd_rel->relnatts *
-                                                                          sizeof(AttrDefault));
-                               MemSet(attrdef, 0,
-                                          relation->rd_rel->relnatts * sizeof(AttrDefault));
-                       }
-                       attrdef[ndef].adnum = i;
-                       attrdef[ndef].adbin = NULL;
-                       ndef++;
+                       constr->num_check = relation->rd_rel->relchecks;
+                       constr->check = (ConstrCheck *)
+                               MemoryContextAlloc(CacheMemoryContext,
+                                                               constr->num_check * sizeof(ConstrCheck));
+                       MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck));
+                       RelCheckFetch(relation);
                }
+               else
+                       constr->num_check = 0;
+       }
+       else
+       {
+               pfree(constr);
+               relation->rd_att->constr = NULL;
        }
-
-       heap_close(attrel, AccessShareLock);
-
-       /*
-        * The attcacheoff values we read from pg_attribute should all be -1
-        * ("unknown").  Verify this if assert checking is on.  They will be
-        * computed when and if needed during tuple access.
-        */
-#ifdef USE_ASSERT_CHECKING
-       for (i = 0; i < relation->rd_rel->relnatts; i++)
-               Assert(relation->rd_att->attrs[i]->attcacheoff == -1);
-#endif
-
-       /*
-        * However, we can easily set the attcacheoff value for the first
-        * attribute: it must be zero.  This eliminates the need for special
-        * cases for attnum=1 that used to exist in fastgetattr() and
-        * index_getattr().
-        */
-       relation->rd_att->attrs[0]->attcacheoff = 0;
-
-       SetConstrOfRelation(relation, constr, ndef, attrdef);
 }
 
 /*
@@ -749,7 +630,7 @@ RelationBuildRuleLock(Relation relation)
        HeapTuple       pg_rewrite_tuple;
        Relation        pg_rewrite_desc;
        TupleDesc       pg_rewrite_tupdesc;
-       HeapScanDesc pg_rewrite_scan;
+       SysScanDesc pg_rewrite_scan;
        ScanKeyData key;
        RuleLock   *rulelock;
        int                     numlocks;
@@ -786,12 +667,16 @@ RelationBuildRuleLock(Relation relation)
 
        /*
         * open pg_rewrite and begin a scan
+        *
+        * XXX: there is no suitable index for this scan.  FIXME.
         */
        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);
+       pg_rewrite_scan = systable_beginscan(pg_rewrite_desc, NULL, false,
+                                                                                SnapshotNow,
+                                                                                1, &key);
 
-       while (HeapTupleIsValid(pg_rewrite_tuple = heap_getnext(pg_rewrite_scan, 0)))
+       while (HeapTupleIsValid(pg_rewrite_tuple = systable_getnext(pg_rewrite_scan)))
        {
                bool            isnull;
                Datum           ruleaction;
@@ -854,7 +739,7 @@ RelationBuildRuleLock(Relation relation)
        /*
         * end the scan and close the attribute relation
         */
-       heap_endscan(pg_rewrite_scan);
+       systable_endscan(pg_rewrite_scan);
        heap_close(pg_rewrite_desc, AccessShareLock);
 
        /*
@@ -930,25 +815,6 @@ equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
  *             recycling the given old relation object.  The latter case
  *             supports rebuilding a relcache entry without invalidating
  *             pointers to it.
- *
- *             To build a relation descriptor, we have to allocate space,
- *             open the underlying unix file and initialize the following
- *             fields:
- *
- *     File                               rd_fd;                open file descriptor
- *     BlockNumber                        rd_nblocks;   number of blocks in rel
- *                                                                              it will be set in ambeginscan()
- *     int                                        rd_refcnt;    reference count
- *     Form_pg_am                         rd_am;                AM tuple
- *     Form_pg_class              rd_rel;               RELATION tuple
- *     Oid                                        rd_id;                relation's object id
- *     LockInfoData               rd_lockInfo;  lock manager's info
- *     TupleDesc                          rd_att;               tuple descriptor
- *
- *             Note: rd_ismem (rel is in-memory only) is currently unused
- *             by any part of the system.      someday this will indicate that
- *             the relation lives only in the main-memory buffer pool
- *             -cim 2/4/91
  * --------------------------------
  */
 static Relation
@@ -957,7 +823,6 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
 {
        Relation        relation;
        Oid                     relid;
-       Oid                     relam;
        HeapTuple       pg_class_tuple;
        Form_pg_class relp;
        MemoryContext oldcxt;
@@ -1005,14 +870,6 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
         */
        relation->rd_isnailed = false;
 
-       /*
-        * initialize the access method information (relation->rd_am)
-        */
-       relam = relation->rd_rel->relam;
-       if (OidIsValid(relam))
-               relation->rd_am = AccessMethodObjectIdGetForm(relam,
-                                                                                                         CacheMemoryContext);
-
        /*
         * initialize the tuple descriptor (relation->rd_att).
         */
@@ -1035,9 +892,9 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
                relation->trigdesc = NULL;
 
        /*
-        * initialize index strategy and support information for this relation
+        * if it's an index, initialize index-related information
         */
-       if (OidIsValid(relam))
+       if (OidIsValid(relation->rd_rel->relam))
                RelationInitIndexAccessInfo(relation);
 
        /*
@@ -1051,24 +908,8 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
                relation->rd_node.tblNode = MyDatabaseId;
        relation->rd_node.relNode = relation->rd_rel->relfilenode;
 
-       /*
-        * Open the relation and assign the file descriptor returned by the
-        * storage manager code to rd_fd.
-        *
-        * We do not raise a hard error if we fail to open the relation at this
-        * point.  If we did, it would be impossible to drop a relation whose
-        * underlying physical file had disappeared.
-        */
-       if (relation->rd_rel->relkind != RELKIND_VIEW)
-       {
-               relation->rd_fd = smgropen(DEFAULT_SMGR, relation, true);
-               Assert(relation->rd_fd >= -1);
-               if (relation->rd_fd == -1)
-                       elog(NOTICE, "RelationBuildDesc: can't open %s: %m",
-                                RelationGetRelationName(relation));
-       }
-       else
-               relation->rd_fd = -1;
+       /* make sure relation is marked as having no open file yet */
+       relation->rd_fd = -1;
 
        /*
         * insert newly created relation into proper relcaches, restore memory
@@ -1087,18 +928,55 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
 void
 RelationInitIndexAccessInfo(Relation relation)
 {
+       HeapTuple       tuple;
+       Size            iformsize;
+       Form_pg_index iform;
+       Form_pg_am      aform;
        MemoryContext indexcxt;
        IndexStrategy strategy;
+       Oid                *operator;
        RegProcedure *support;
        FmgrInfo   *supportinfo;
        int                     natts;
        uint16          amstrategies;
        uint16          amsupport;
-       Size            stratSize;
+
+       /*
+        * Make a copy of the pg_index entry for the index.  Note that this
+        * is a variable-length tuple.
+        */
+       tuple = SearchSysCache(INDEXRELID,
+                                                  ObjectIdGetDatum(RelationGetRelid(relation)),
+                                                  0, 0, 0);
+       if (!HeapTupleIsValid(tuple))
+               elog(ERROR, "RelationInitIndexAccessInfo: no pg_index entry for index %u",
+                        RelationGetRelid(relation));
+       iformsize = tuple->t_len - tuple->t_data->t_hoff;
+       iform = (Form_pg_index) MemoryContextAlloc(CacheMemoryContext, iformsize);
+       memcpy(iform, GETSTRUCT(tuple), iformsize);
+       ReleaseSysCache(tuple);
+       relation->rd_index = iform;
+
+       /* this field is now kinda redundant... */
+       relation->rd_uniqueindex = iform->indisunique;
+
+       /*
+        * Make a copy of the pg_am entry for the index's access method
+        */
+       tuple = SearchSysCache(AMOID,
+                                                  ObjectIdGetDatum(relation->rd_rel->relam),
+                                                  0, 0, 0);
+       if (!HeapTupleIsValid(tuple))
+               elog(ERROR, "RelationInitIndexAccessInfo: cache lookup failed for AM %u",
+                        relation->rd_rel->relam);
+       aform = (Form_pg_am) MemoryContextAlloc(CacheMemoryContext, sizeof *aform);
+       memcpy(aform, GETSTRUCT(tuple), sizeof *aform);
+       ReleaseSysCache(tuple);
+       relation->rd_am = aform;
 
        natts = relation->rd_rel->relnatts;
-       amstrategies = relation->rd_am->amstrategies;
-       amsupport = relation->rd_am->amsupport;
+       amstrategies = aform->amstrategies;
+       amsupport = aform->amsupport;
 
        /*
         * Make the private context to hold index access info.  The reason we
@@ -1118,8 +996,23 @@ RelationInitIndexAccessInfo(Relation relation)
        /*
         * Allocate arrays to hold data
         */
-       stratSize = AttributeNumberGetIndexStrategySize(natts, amstrategies);
-       strategy = (IndexStrategy) MemoryContextAlloc(indexcxt, stratSize);
+       if (amstrategies > 0)
+       {
+               int                     noperators = natts * amstrategies;
+               Size            stratSize;
+
+               stratSize = AttributeNumberGetIndexStrategySize(natts, amstrategies);
+               strategy = (IndexStrategy) MemoryContextAlloc(indexcxt, stratSize);
+               MemSet(strategy, 0, stratSize);
+               operator = (Oid *)
+                       MemoryContextAlloc(indexcxt, noperators * sizeof(Oid));
+               MemSet(operator, 0, noperators * sizeof(Oid));
+       }
+       else
+       {
+               strategy = NULL;
+               operator = NULL;
+       }
 
        if (amsupport > 0)
        {
@@ -1127,6 +1020,7 @@ RelationInitIndexAccessInfo(Relation relation)
 
                support = (RegProcedure *)
                        MemoryContextAlloc(indexcxt, nsupport * sizeof(RegProcedure));
+               MemSet(support, 0, nsupport * sizeof(RegProcedure));
                supportinfo = (FmgrInfo *)
                        MemoryContextAlloc(indexcxt, nsupport * sizeof(FmgrInfo));
                MemSet(supportinfo, 0, nsupport * sizeof(FmgrInfo));
@@ -1137,31 +1031,301 @@ RelationInitIndexAccessInfo(Relation relation)
                supportinfo = NULL;
        }
 
+       relation->rd_istrat = strategy;
+       relation->rd_operator = operator;
+       relation->rd_support = support;
+       relation->rd_supportinfo = supportinfo;
+
        /*
         * Fill the strategy map and the support RegProcedure arrays.
         * (supportinfo is left as zeroes, and is filled on-the-fly when used)
         */
-       IndexSupportInitialize(strategy, support,
-                                                  &relation->rd_uniqueindex,
-                                                  RelationGetRelid(relation),
-                                                  relation->rd_rel->relam,
+       IndexSupportInitialize(iform,
+                                                  strategy, operator, support,
                                                   amstrategies, amsupport, natts);
-
-       relation->rd_istrat = strategy;
-       relation->rd_support = support;
-       relation->rd_supportinfo = supportinfo;
 }
 
 /*
- *             formrdesc
+ * IndexSupportInitialize
+ *             Initializes an index strategy and associated support procedures,
+ *             given the index's pg_index tuple.
  *
- *             This is a special cut-down version of RelationBuildDesc()
- *             used by RelationCacheInitialize() in initializing the relcache.
- *             The relation descriptor is built just from the supplied parameters,
+ * Data is returned into *indexStrategy, *indexOperator, and *indexSupport,
+ * all of which are objects allocated by the caller.
+ *
+ * The caller also passes maxStrategyNumber, maxSupportNumber, and
+ * maxAttributeNumber, since these indicate the size of the arrays
+ * it has allocated --- but in practice these numbers must always match
+ * those obtainable from the system catalog entries for the index and
+ * access method.
+ */
+static void
+IndexSupportInitialize(Form_pg_index iform,
+                                          IndexStrategy indexStrategy,
+                                          Oid *indexOperator,
+                                          RegProcedure *indexSupport,
+                                          StrategyNumber maxStrategyNumber,
+                                          StrategyNumber maxSupportNumber,
+                                          AttrNumber maxAttributeNumber)
+{
+       int                     attIndex;
+
+       maxStrategyNumber = AMStrategies(maxStrategyNumber);
+
+       /*
+        * XXX note that the following assumes the INDEX tuple is well formed
+        * and that the *key and *class are 0 terminated.
+        */
+       for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
+       {
+               OpClassCacheEnt *opcentry;
+
+               if (iform->indkey[attIndex] == InvalidAttrNumber ||
+                       !OidIsValid(iform->indclass[attIndex]))
+                       elog(ERROR, "IndexSupportInitialize: bogus pg_index tuple");
+
+               /* look up the info for this opclass, using a cache */
+               opcentry = LookupOpclassInfo(iform->indclass[attIndex],
+                                                                        maxStrategyNumber,
+                                                                        maxSupportNumber);
+
+               /* load the strategy information for the index operators */
+               if (maxStrategyNumber > 0)
+               {
+                       StrategyMap map;
+                       Oid                *opers;
+                       StrategyNumber strategy;
+
+                       map = IndexStrategyGetStrategyMap(indexStrategy,
+                                                                                         maxStrategyNumber,
+                                                                                         attIndex + 1);
+                       opers = &indexOperator[attIndex * maxStrategyNumber];
+
+                       for (strategy = 0; strategy < maxStrategyNumber; strategy++)
+                       {
+                               ScanKey         mapentry;
+
+                               mapentry = StrategyMapGetScanKeyEntry(map, strategy + 1);
+                               if (RegProcedureIsValid(opcentry->operatorProcs[strategy]))
+                               {
+                                       MemSet(mapentry, 0, sizeof(*mapentry));
+                                       mapentry->sk_flags = 0;
+                                       mapentry->sk_procedure = opcentry->operatorProcs[strategy];
+                                       /*
+                                        * Mark mapentry->sk_func invalid, until and unless
+                                        * someone sets it up.
+                                        */
+                                       mapentry->sk_func.fn_oid = InvalidOid;
+                               }
+                               else
+                                       ScanKeyEntrySetIllegal(mapentry);
+                               opers[strategy] = opcentry->operatorOids[strategy];
+                       }
+               }
+
+               /* if support routines exist for this access method, load them */
+               if (maxSupportNumber > 0)
+               {
+                       RegProcedure *procs;
+                       StrategyNumber support;
+
+                       procs = &indexSupport[attIndex * maxSupportNumber];
+
+                       for (support = 0; support < maxSupportNumber; ++support)
+                               procs[support] = opcentry->supportProcs[support];
+               }
+       }
+}
+
+/*
+ * LookupOpclassInfo
+ *
+ * This routine maintains a per-opclass cache of the information needed
+ * by IndexSupportInitialize().  This is more efficient than relying on
+ * the catalog cache, because we can load all the info about a particular
+ * opclass in a single indexscan of pg_amproc or pg_amop.
+ *
+ * The information from pg_am about expected range of strategy and support
+ * numbers is passed in, rather than being looked up, mainly because the
+ * caller will have it already.
+ *
+ * XXX There isn't any provision for flushing the cache.  However, there
+ * isn't any provision for flushing relcache entries when opclass info
+ * changes, either :-(
+ */
+static OpClassCacheEnt *
+LookupOpclassInfo(Oid operatorClassOid,
+                                 StrategyNumber numStrats,
+                                 StrategyNumber numSupport)
+{
+       OpClassCacheEnt *opcentry;
+       bool            found;
+       Relation        pg_amop_desc;
+       Relation        pg_amproc_desc;
+       SysScanDesc pg_amop_scan;
+       SysScanDesc pg_amproc_scan;
+       ScanKeyData key;
+       HeapTuple       htup;
+       bool            indexOK;
+
+       if (OpClassCache == NULL)
+       {
+               /* First time through: initialize the opclass cache */
+               HASHCTL         ctl;
+
+               if (!CacheMemoryContext)
+                       CreateCacheMemoryContext();
+
+               MemSet(&ctl, 0, sizeof(ctl));
+               ctl.keysize = sizeof(Oid);
+               ctl.entrysize = sizeof(OpClassCacheEnt);
+               ctl.hash = tag_hash;
+               OpClassCache = hash_create("Operator class cache", 64,
+                                                                  &ctl, HASH_ELEM | HASH_FUNCTION);
+       }
+
+       opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,
+                                                                                          (void *) &operatorClassOid,
+                                                                                          HASH_ENTER, &found);
+       if (opcentry == NULL)
+               elog(ERROR, "out of memory for operator class cache");
+
+       if (found && opcentry->valid)
+       {
+               /* Already made an entry for it */
+               Assert(numStrats == opcentry->numStrats);
+               Assert(numSupport == opcentry->numSupport);
+               return opcentry;
+       }
+
+       /* Need to fill in new entry */
+       opcentry->valid = false;        /* until known OK */
+       opcentry->numStrats = numStrats;
+       opcentry->numSupport = numSupport;
+
+       if (numStrats > 0)
+       {
+               opcentry->operatorOids = (Oid *)
+                       MemoryContextAlloc(CacheMemoryContext,
+                                                          numStrats * sizeof(Oid));
+               MemSet(opcentry->operatorOids, 0, numStrats * sizeof(Oid));
+               opcentry->operatorProcs = (RegProcedure *)
+                       MemoryContextAlloc(CacheMemoryContext,
+                                                          numStrats * sizeof(RegProcedure));
+               MemSet(opcentry->operatorProcs, 0, numStrats * sizeof(RegProcedure));
+       }
+       else
+       {
+               opcentry->operatorOids = NULL;
+               opcentry->operatorProcs = NULL;
+       }
+
+       if (numSupport > 0)
+       {
+               opcentry->supportProcs = (RegProcedure *)
+                       MemoryContextAlloc(CacheMemoryContext,
+                                                          numSupport * sizeof(RegProcedure));
+               MemSet(opcentry->supportProcs, 0, numSupport * sizeof(RegProcedure));
+       }
+       else
+               opcentry->supportProcs = NULL;
+
+       /*
+        * To avoid infinite recursion during startup, force a heap scan if
+        * we're looking up info for the opclasses used by the indexes we
+        * would like to reference here.
+        */
+       indexOK = criticalRelcachesBuilt ||
+               (operatorClassOid != OID_BTREE_OPS_OID &&
+                operatorClassOid != INT2_BTREE_OPS_OID);
+
+       /*
+        * Scan pg_amop to obtain operators for the opclass
+        */
+       if (numStrats > 0)
+       {
+               ScanKeyEntryInitialize(&key, 0,
+                                                          Anum_pg_amop_amopclaid,
+                                                          F_OIDEQ,
+                                                          ObjectIdGetDatum(operatorClassOid));
+               pg_amop_desc = heap_openr(AccessMethodOperatorRelationName,
+                                                                 AccessShareLock);
+               pg_amop_scan = systable_beginscan(pg_amop_desc,
+                                                                                 AccessMethodStrategyIndex,
+                                                                                 indexOK,
+                                                                                 SnapshotNow,
+                                                                                 1, &key);
+
+               while (HeapTupleIsValid(htup = systable_getnext(pg_amop_scan)))
+               {
+                       Form_pg_amop amopform = (Form_pg_amop) GETSTRUCT(htup);
+
+                       if (amopform->amopstrategy <= 0 ||
+                               (StrategyNumber) amopform->amopstrategy > numStrats)
+                               elog(ERROR, "Bogus amopstrategy number %d for opclass %u",
+                                        amopform->amopstrategy, operatorClassOid);
+                       opcentry->operatorOids[amopform->amopstrategy - 1] =
+                               amopform->amopopr;
+                       opcentry->operatorProcs[amopform->amopstrategy - 1] =
+                               get_opcode(amopform->amopopr);
+               }
+
+               systable_endscan(pg_amop_scan);
+               heap_close(pg_amop_desc, AccessShareLock);
+       }
+
+       /*
+        * Scan pg_amproc to obtain support procs for the opclass
+        */
+       if (numSupport > 0)
+       {
+               ScanKeyEntryInitialize(&key, 0,
+                                                          Anum_pg_amproc_amopclaid,
+                                                          F_OIDEQ,
+                                                          ObjectIdGetDatum(operatorClassOid));
+               pg_amproc_desc = heap_openr(AccessMethodProcedureRelationName,
+                                                                       AccessShareLock);
+               pg_amproc_scan = systable_beginscan(pg_amproc_desc,
+                                                                                       AccessMethodProcedureIndex,
+                                                                                       indexOK,
+                                                                                       SnapshotNow,
+                                                                                       1, &key);
+
+               while (HeapTupleIsValid(htup = systable_getnext(pg_amproc_scan)))
+               {
+                       Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(htup);
+
+                       if (amprocform->amprocnum <= 0 ||
+                               (StrategyNumber) amprocform->amprocnum > numSupport)
+                               elog(ERROR, "Bogus amproc number %d for opclass %u",
+                                        amprocform->amprocnum, operatorClassOid);
+
+                       opcentry->supportProcs[amprocform->amprocnum - 1] =
+                               amprocform->amproc;
+               }
+
+               systable_endscan(pg_amproc_scan);
+               heap_close(pg_amproc_desc, AccessShareLock);
+       }
+
+       opcentry->valid = true;
+       return opcentry;
+}
+
+
+/*
+ *             formrdesc
+ *
+ *             This is a special cut-down version of RelationBuildDesc()
+ *             used by RelationCacheInitialize() in initializing the relcache.
+ *             The relation descriptor is built just from the supplied parameters,
  *             without actually looking at any system table entries.  We cheat
  *             quite a lot since we only need to work for a few basic system
  *             catalogs...
  *
+ * Note that these catalogs can't have constraints, default values,
+ * rules, or triggers, since we don't cope with any of that.
+ *
  * NOTE: we assume we are already switched into CacheMemoryContext.
  */
 static void
@@ -1223,6 +1387,10 @@ formrdesc(char *relationName,
 
        /*
         * initialize attribute tuple form
+        *
+        * Unlike the case with the relation tuple, this data had better be
+        * right because it will never be replaced.  The input values must be
+        * correctly defined by macros in src/include/catalog/ headers.
         */
        relation->rd_att = CreateTemplateTupleDesc(natts);
 
@@ -1235,8 +1403,13 @@ formrdesc(char *relationName,
                memcpy((char *) relation->rd_att->attrs[i],
                           (char *) &att[i],
                           ATTRIBUTE_TUPLE_SIZE);
+               /* make sure attcacheoff is valid */
+               relation->rd_att->attrs[i]->attcacheoff = -1;
        }
 
+       /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
+       relation->rd_att->attrs[0]->attcacheoff = 0;
+
        /*
         * initialize relation id from info in att array (my, this is ugly)
         */
@@ -1280,52 +1453,6 @@ formrdesc(char *relationName,
 }
 
 
-/*
- *             fixrdesc
- *
- *             Update the phony data inserted by formrdesc() with real info
- *             from pg_class.
- */
-static void
-fixrdesc(char *relationName)
-{
-       RelationBuildDescInfo buildinfo;
-       HeapTuple       pg_class_tuple;
-       Form_pg_class relp;
-       Relation        relation;
-
-       /*
-        * find the tuple in pg_class corresponding to the given relation name
-        */
-       buildinfo.infotype = INFO_RELNAME;
-       buildinfo.i.info_name = relationName;
-
-       pg_class_tuple = ScanPgRelation(buildinfo);
-
-       if (!HeapTupleIsValid(pg_class_tuple))
-               elog(FATAL, "fixrdesc: no pg_class entry for %s",
-                        relationName);
-       relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
-
-       /*
-        * find the pre-made relcache entry (better be there!)
-        */
-       relation = RelationNameCacheGetRelation(relationName);
-       if (!RelationIsValid(relation))
-               elog(FATAL, "fixrdesc: no existing relcache entry for %s",
-                        relationName);
-
-       /*
-        * and copy pg_class_tuple to relation->rd_rel. (See notes in
-        * AllocateRelationDesc())
-        */
-       Assert(relation->rd_rel != NULL);
-       memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
-
-       heap_freetuple(pg_class_tuple);
-}
-
-
 /* ----------------------------------------------------------------
  *                              Relation Descriptor Lookup Interface
  * ----------------------------------------------------------------
@@ -1351,13 +1478,7 @@ RelationIdCacheGetRelation(Oid relationId)
        RelationIdCacheLookup(relationId, rd);
 
        if (RelationIsValid(rd))
-       {
-               /* re-open files if necessary */
-               if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
-                       rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
-
                RelationIncrementReferenceCount(rd);
-       }
 
        return rd;
 }
@@ -1381,13 +1502,7 @@ RelationNameCacheGetRelation(const char *relationName)
        RelationNameCacheLookup(NameStr(name), rd);
 
        if (RelationIsValid(rd))
-       {
-               /* re-open files if necessary */
-               if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
-                       rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
-
                RelationIncrementReferenceCount(rd);
-       }
 
        return rd;
 }
@@ -1400,13 +1515,7 @@ RelationNodeCacheGetRelation(RelFileNode rnode)
        RelationNodeCacheLookup(rnode, rd);
 
        if (RelationIsValid(rd))
-       {
-               /* re-open files if necessary */
-               if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
-                       rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
-
                RelationIncrementReferenceCount(rd);
-       }
 
        return rd;
 }
@@ -1619,6 +1728,8 @@ RelationClearRelation(Relation relation, bool rebuildIt)
         * manager might have pointers into the rewrite rules. So to begin
         * with, we can only get rid of these fields:
         */
+       if (relation->rd_index)
+               pfree(relation->rd_index);
        if (relation->rd_am)
                pfree(relation->rd_am);
        if (relation->rd_rel)
@@ -1805,32 +1916,11 @@ RelationIdInvalidateRelationCacheByRelationId(Oid relationId)
        RelationIdCacheLookup(relationId, relation);
 
        if (PointerIsValid(relation))
-               RelationFlushRelation(relation);
-}
-
-#if NOT_USED
-/* only used by RelationIdInvalidateRelationCacheByAccessMethodId,
- * which is dead code.
- */
-static void
-RelationFlushIndexes(Relation *r,
-                                        Oid accessMethodId)
-{
-       Relation        relation = *r;
-
-       if (!RelationIsValid(relation))
        {
-               elog(NOTICE, "inval call to RFI");
-               return;
-       }
-
-       if (relation->rd_rel->relkind == RELKIND_INDEX &&       /* XXX style */
-               (!OidIsValid(accessMethodId) ||
-                relation->rd_rel->relam == accessMethodId))
+               relcacheInvalsReceived++;
                RelationFlushRelation(relation);
+       }
 }
-#endif
-
 
 /*
  * RelationCacheInvalidate
@@ -1873,6 +1963,8 @@ RelationCacheInvalidate(void)
                if (relation->rd_myxactonly)
                        continue;
 
+               relcacheInvalsReceived++;
+
                if (RelationHasReferenceCountZero(relation))
                {
                        /* Delete this entry immediately */
@@ -2071,7 +2163,12 @@ RelationPurgeLocalRelation(bool xactCommitted)
 /*
  *             RelationCacheInitialize
  *
- *             This initializes the relation descriptor cache.
+ *             This initializes the relation descriptor cache.  At the time
+ *             that this is invoked, we can't do database access yet (mainly
+ *             because the transaction subsystem is not up), so we can't get
+ *             "real" info.  However it's okay to read the pg_internal.init
+ *             cache file, if one is available.  Otherwise we make phony
+ *             entries for the minimum set of nailed-in-cache relations.
  */
 
 #define INITRELCACHESIZE               400
@@ -2091,7 +2188,7 @@ RelationCacheInitialize(void)
        oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
        /*
-        * create global caches
+        * create hashtables that index the relcache
         */
        MemSet(&ctl, 0, sizeof(ctl));
        ctl.keysize = sizeof(NameData);
@@ -2112,22 +2209,24 @@ RelationCacheInitialize(void)
                                                                        &ctl, HASH_ELEM | HASH_FUNCTION);
 
        /*
-        * 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: see also the list in RelationCacheInitializePhase2().
-        */
-       formrdesc(RelationRelationName, Natts_pg_class, Desc_pg_class);
-       formrdesc(AttributeRelationName, Natts_pg_attribute, Desc_pg_attribute);
-       formrdesc(ProcedureRelationName, Natts_pg_proc, Desc_pg_proc);
-       formrdesc(TypeRelationName, Natts_pg_type, Desc_pg_type);
-
-       /*
-        * init_irels() used to be called here. It is changed to be called in
-        * RelationCacheInitializePhase2() now so that transactional control
-        * could guarantee the consistency.
+        * Try to load the relcache cache file.  If successful, we're done
+        * for now.  Otherwise, initialize the cache with pre-made descriptors
+        * for the critical "nailed-in" system catalogs.
         */
+       if (IsBootstrapProcessingMode() ||
+               ! load_relcache_init_file())
+       {
+               formrdesc(RelationRelationName,
+                                 Natts_pg_class, Desc_pg_class);
+               formrdesc(AttributeRelationName,
+                                 Natts_pg_attribute, Desc_pg_attribute);
+               formrdesc(ProcedureRelationName,
+                                 Natts_pg_proc, Desc_pg_proc);
+               formrdesc(TypeRelationName,
+                                 Natts_pg_type, Desc_pg_type);
+
+#define NUM_CRITICAL_RELS      4       /* fix if you change list above */
+       }
 
        MemoryContextSwitchTo(oldcxt);
 }
@@ -2135,40 +2234,145 @@ RelationCacheInitialize(void)
 /*
  *             RelationCacheInitializePhase2
  *
- *             This completes initialization of the relcache after catcache
- *             is functional and we are able to actually load data from pg_class.
+ *             This is called as soon as the catcache and transaction system
+ *             are functional.  At this point we can actually read data from
+ *             the system catalogs.  Update the relcache entries made during
+ *             RelationCacheInitialize, and make sure we have entries for the
+ *             critical system indexes.
  */
 void
 RelationCacheInitializePhase2(void)
 {
+       HASH_SEQ_STATUS status;
+       RelNameCacheEnt *namehentry;
+
+       if (IsBootstrapProcessingMode())
+               return;
+
        /*
-        * Get the real pg_class tuple for each nailed-in-cache relcache entry
-        * that was made by RelationCacheInitialize(), and replace the phony
-        * rd_rel entry made by formrdesc().  This is necessary so that we
-        * have, for example, the correct toast-table info for tables that
-        * have such.
+        * If we didn't get the critical system indexes loaded into relcache,
+        * do so now.  These are critical because the catcache depends on them
+        * for catcache fetches that are done during relcache load.  Thus, we
+        * have an infinite-recursion problem.  We can break the recursion
+        * by doing heapscans instead of indexscans at certain key spots.
+        * To avoid hobbling performance, we only want to do that until we
+        * have the critical indexes loaded into relcache.  Thus, the flag
+        * criticalRelcachesBuilt is used to decide whether to do heapscan
+        * or indexscan at the key spots, and we set it true after we've loaded
+        * the critical indexes.
+        *
+        * The critical indexes are marked as "nailed in cache", partly to make
+        * it easy for load_relcache_init_file to count them, but mainly
+        * because we cannot flush and rebuild them once we've set
+        * criticalRelcachesBuilt to true.  (NOTE: perhaps it would be possible
+        * to reload them by temporarily setting criticalRelcachesBuilt to
+        * false again.  For now, though, we just nail 'em in.)
+        */
+       if (! criticalRelcachesBuilt)
+       {
+               RelationBuildDescInfo buildinfo;
+               Relation        ird;
+
+#define LOAD_CRIT_INDEX(indname) \
+               do { \
+                       buildinfo.infotype = INFO_RELNAME; \
+                       buildinfo.i.info_name = (indname); \
+                       ird = RelationBuildDesc(buildinfo, NULL); \
+                       ird->rd_isnailed = true; \
+                       RelationSetReferenceCount(ird, 1); \
+               } while (0)
+
+               LOAD_CRIT_INDEX(ClassNameIndex);
+               LOAD_CRIT_INDEX(ClassOidIndex);
+               LOAD_CRIT_INDEX(AttributeRelidNumIndex);
+               LOAD_CRIT_INDEX(IndexRelidIndex);
+               LOAD_CRIT_INDEX(AccessMethodStrategyIndex);
+               LOAD_CRIT_INDEX(AccessMethodProcedureIndex);
+               LOAD_CRIT_INDEX(OperatorOidIndex);
+
+#define NUM_CRITICAL_INDEXES   7       /* fix if you change list above */
+
+               criticalRelcachesBuilt = true;
+       }
+
+       /*
+        * Now, scan all the relcache entries and update anything that might
+        * be wrong in the results from formrdesc or the relcache cache file.
+        * If we faked up relcache entries using formrdesc, then read
+        * the real pg_class rows and replace the fake entries with them.
+        * Also, if any of the relcache entries have rules or triggers,
+        * load that info the hard way since it isn't recorded in the cache file.
         */
-       if (!IsBootstrapProcessingMode())
+       hash_seq_init(&status, RelationNameCache);
+
+       while ((namehentry = (RelNameCacheEnt *) hash_seq_search(&status)) != NULL)
        {
+               Relation        relation = namehentry->reldesc;
+
                /*
-                * Initialize critical system index relation descriptors, first.
-                * They are to make building relation descriptors fast.
-                * init_irels() used to be called in RelationCacheInitialize(). It
-                * is changed to be called here to be transaction safe.
+                * If it's a faked-up entry, read the real pg_class tuple.
                 */
-               MemoryContext oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+               if (needNewCacheFile && relation->rd_isnailed)
+               {
+                       HeapTuple       htup;
+                       Form_pg_class relp;
 
-               init_irels();
-               MemoryContextSwitchTo(oldcxt);
+                       htup = SearchSysCache(RELOID,
+                                                                 ObjectIdGetDatum(RelationGetRelid(relation)),
+                                                                 0, 0, 0);
+                       if (!HeapTupleIsValid(htup))
+                               elog(FATAL, "RelationCacheInitializePhase2: no pg_class entry for %s",
+                                        RelationGetRelationName(relation));
+                       relp = (Form_pg_class) GETSTRUCT(htup);
+                       /*
+                        * Copy tuple to relation->rd_rel. (See notes in
+                        * AllocateRelationDesc())
+                        */
+                       Assert(relation->rd_rel != NULL);
+                       memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
 
-               /* fix nailed-in-cache relations */
-               fixrdesc(RelationRelationName);
-               fixrdesc(AttributeRelationName);
-               fixrdesc(ProcedureRelationName);
-               fixrdesc(TypeRelationName);
+                       ReleaseSysCache(htup);
+               }
+
+               /*
+                * Fix data that isn't saved in relcache cache file.
+                */
+               if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
+                       RelationBuildRuleLock(relation);
+               if (relation->rd_rel->reltriggers > 0 && relation->trigdesc == NULL)
+                       RelationBuildTriggers(relation);
        }
 }
 
+/*
+ *             RelationCacheInitializePhase3
+ *
+ *             Final step of relcache initialization: write out a new relcache
+ *             cache file if one is needed.
+ */
+void
+RelationCacheInitializePhase3(void)
+{
+       if (IsBootstrapProcessingMode())
+               return;
+
+       if (needNewCacheFile)
+       {
+               /*
+                * Force all the catcaches to finish initializing and thereby
+                * open the catalogs and indexes they use.  This will preload
+                * the relcache with entries for all the most important system
+                * catalogs and indexes, so that the init file will be most
+                * useful for future backends.
+                */
+               InitCatalogCachePhase2();
+
+               /* now write the file */
+               write_relcache_init_file();
+       }
+}
+
+
 /* used by XLogInitCache */
 void           CreateDummyCaches(void);
 void           DestroyDummyCaches(void);
@@ -2233,63 +2437,31 @@ AttrDefaultFetch(Relation relation)
        AttrDefault *attrdef = relation->rd_att->constr->defval;
        int                     ndef = relation->rd_att->constr->num_defval;
        Relation        adrel;
-       Relation        irel = (Relation) NULL;
+       SysScanDesc adscan;
        ScanKeyData skey;
-       HeapTupleData tuple;
        HeapTuple       htup;
-       Form_pg_attrdef adform;
-       IndexScanDesc sd = (IndexScanDesc) NULL;
-       HeapScanDesc adscan = (HeapScanDesc) NULL;
-       RetrieveIndexResult indexRes;
        Datum           val;
        bool            isnull;
        int                     found;
        int                     i;
-       bool            hasindex;
 
        ScanKeyEntryInitialize(&skey,
                                                   (bits16) 0x0,
-                                                  (AttrNumber) 1,
+                                                  (AttrNumber) Anum_pg_attrdef_adrelid,
                                                   (RegProcedure) F_OIDEQ,
                                                   ObjectIdGetDatum(RelationGetRelid(relation)));
 
        adrel = heap_openr(AttrDefaultRelationName, AccessShareLock);
-       hasindex = (adrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
-       if (hasindex)
-       {
-               irel = index_openr(AttrDefaultIndex);
-               sd = index_beginscan(irel, false, 1, &skey);
-       }
-       else
-               adscan = heap_beginscan(adrel, false, SnapshotNow, 1, &skey);
-       tuple.t_datamcxt = NULL;
-       tuple.t_data = NULL;
+       adscan = systable_beginscan(adrel, AttrDefaultIndex, true,
+                                                               SnapshotNow,
+                                                               1, &skey);
+       found = 0;
 
-       for (found = 0;;)
+       while (HeapTupleIsValid(htup = systable_getnext(adscan)))
        {
-               Buffer          buffer;
+               Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
 
-               if (hasindex)
-               {
-                       indexRes = index_getnext(sd, ForwardScanDirection);
-                       if (!indexRes)
-                               break;
-
-                       tuple.t_self = indexRes->heap_iptr;
-                       heap_fetch(adrel, SnapshotNow, &tuple, &buffer, sd);
-                       pfree(indexRes);
-                       if (tuple.t_data == NULL)
-                               continue;
-                       htup = &tuple;
-               }
-               else
-               {
-                       htup = heap_getnext(adscan, 0);
-                       if (!HeapTupleIsValid(htup))
-                               break;
-               }
                found++;
-               adform = (Form_pg_attrdef) GETSTRUCT(htup);
                for (i = 0; i < ndef; i++)
                {
                        if (adform->adnum != attrdef[i].adnum)
@@ -2312,8 +2484,6 @@ AttrDefaultFetch(Relation relation)
                                                                                                                                 val)));
                        break;
                }
-               if (hasindex)
-                       ReleaseBuffer(buffer);
 
                if (i >= ndef)
                        elog(NOTICE, "AttrDefaultFetch: unexpected record found for attr %d in rel %s",
@@ -2321,18 +2491,12 @@ AttrDefaultFetch(Relation relation)
                                 RelationGetRelationName(relation));
        }
 
-       if (found < ndef)
-               elog(NOTICE, "AttrDefaultFetch: %d record not found for rel %s",
-                        ndef - found, RelationGetRelationName(relation));
-
-       if (hasindex)
-       {
-               index_endscan(sd);
-               index_close(irel);
-       }
-       else
-               heap_endscan(adscan);
+       systable_endscan(adscan);
        heap_close(adrel, AccessShareLock);
+
+       if (found != ndef)
+               elog(NOTICE, "AttrDefaultFetch: %d record(s) not found for rel %s",
+                        ndef - found, RelationGetRelationName(relation));
 }
 
 static void
@@ -2341,60 +2505,28 @@ RelCheckFetch(Relation relation)
        ConstrCheck *check = relation->rd_att->constr->check;
        int                     ncheck = relation->rd_att->constr->num_check;
        Relation        rcrel;
-       Relation        irel = (Relation) NULL;
+       SysScanDesc rcscan;
        ScanKeyData skey;
-       HeapTupleData tuple;
        HeapTuple       htup;
-       IndexScanDesc sd = (IndexScanDesc) NULL;
-       HeapScanDesc rcscan = (HeapScanDesc) NULL;
-       RetrieveIndexResult indexRes;
        Name            rcname;
        Datum           val;
        bool            isnull;
        int                     found;
-       bool            hasindex;
 
        ScanKeyEntryInitialize(&skey,
                                                   (bits16) 0x0,
-                                                  (AttrNumber) 1,
+                                                  (AttrNumber) Anum_pg_relcheck_rcrelid,
                                                   (RegProcedure) F_OIDEQ,
                                                   ObjectIdGetDatum(RelationGetRelid(relation)));
 
        rcrel = heap_openr(RelCheckRelationName, AccessShareLock);
-       hasindex = (rcrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
-       if (hasindex)
-       {
-               irel = index_openr(RelCheckIndex);
-               sd = index_beginscan(irel, false, 1, &skey);
-       }
-       else
-               rcscan = heap_beginscan(rcrel, false, SnapshotNow, 1, &skey);
-       tuple.t_datamcxt = NULL;
-       tuple.t_data = NULL;
+       rcscan = systable_beginscan(rcrel, RelCheckIndex, true,
+                                                               SnapshotNow,
+                                                               1, &skey);
+       found = 0;
 
-       for (found = 0;;)
+       while (HeapTupleIsValid(htup = systable_getnext(rcscan)))
        {
-               Buffer          buffer;
-
-               if (hasindex)
-               {
-                       indexRes = index_getnext(sd, ForwardScanDirection);
-                       if (!indexRes)
-                               break;
-
-                       tuple.t_self = indexRes->heap_iptr;
-                       heap_fetch(rcrel, SnapshotNow, &tuple, &buffer, sd);
-                       pfree(indexRes);
-                       if (tuple.t_data == NULL)
-                               continue;
-                       htup = &tuple;
-               }
-               else
-               {
-                       htup = heap_getnext(rcscan, 0);
-                       if (!HeapTupleIsValid(htup))
-                               break;
-               }
                if (found == ncheck)
                        elog(ERROR, "RelCheckFetch: unexpected record found for rel %s",
                                 RelationGetRelationName(relation));
@@ -2417,22 +2549,14 @@ RelCheckFetch(Relation relation)
                                                         DatumGetCString(DirectFunctionCall1(textout,
                                                                                                                                 val)));
                found++;
-               if (hasindex)
-                       ReleaseBuffer(buffer);
        }
 
-       if (found < ncheck)
-               elog(ERROR, "RelCheckFetch: %d record not found for rel %s",
-                        ncheck - found, RelationGetRelationName(relation));
-
-       if (hasindex)
-       {
-               index_endscan(sd);
-               index_close(irel);
-       }
-       else
-               heap_endscan(rcscan);
+       systable_endscan(rcscan);
        heap_close(rcrel, AccessShareLock);
+
+       if (found != ncheck)
+               elog(ERROR, "RelCheckFetch: %d record(s) not found for rel %s",
+                        ncheck - found, RelationGetRelationName(relation));
 }
 
 /*
@@ -2461,11 +2585,9 @@ List *
 RelationGetIndexList(Relation relation)
 {
        Relation        indrel;
-       Relation        irel = (Relation) NULL;
+       SysScanDesc     indscan;
        ScanKeyData skey;
-       IndexScanDesc sd = (IndexScanDesc) NULL;
-       HeapScanDesc hscan = (HeapScanDesc) NULL;
-       bool            hasindex;
+       HeapTuple       htup;
        List       *result;
        MemoryContext oldcxt;
 
@@ -2473,29 +2595,6 @@ RelationGetIndexList(Relation relation)
        if (relation->rd_indexfound)
                return listCopy(relation->rd_indexlist);
 
-       /* Prepare to scan pg_index for entries having indrelid = this rel. */
-       indrel = heap_openr(IndexRelationName, AccessShareLock);
-       hasindex = (indrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
-       if (hasindex)
-       {
-               irel = index_openr(IndexIndrelidIndex);
-               ScanKeyEntryInitialize(&skey,
-                                                          (bits16) 0x0,
-                                                          (AttrNumber) 1,
-                                                          (RegProcedure) F_OIDEQ,
-                                                  ObjectIdGetDatum(RelationGetRelid(relation)));
-               sd = index_beginscan(irel, false, 1, &skey);
-       }
-       else
-       {
-               ScanKeyEntryInitialize(&skey,
-                                                          (bits16) 0x0,
-                                                          (AttrNumber) Anum_pg_index_indrelid,
-                                                          (RegProcedure) F_OIDEQ,
-                                                  ObjectIdGetDatum(RelationGetRelid(relation)));
-               hscan = heap_beginscan(indrel, false, SnapshotNow, 1, &skey);
-       }
-
        /*
         * We build the list we intend to return (in the caller's context)
         * while doing the scan.  After successfully completing the scan, we
@@ -2504,51 +2603,26 @@ RelationGetIndexList(Relation relation)
         */
        result = NIL;
 
-       for (;;)
-       {
-               HeapTupleData tuple;
-               HeapTuple       htup;
-               Buffer          buffer;
-               Form_pg_index index;
+       /* Prepare to scan pg_index for entries having indrelid = this rel. */
+       ScanKeyEntryInitialize(&skey,
+                                                  (bits16) 0x0,
+                                                  (AttrNumber) Anum_pg_index_indrelid,
+                                                  (RegProcedure) F_OIDEQ,
+                                                  ObjectIdGetDatum(RelationGetRelid(relation)));
 
-               if (hasindex)
-               {
-                       RetrieveIndexResult indexRes;
-
-                       indexRes = index_getnext(sd, ForwardScanDirection);
-                       if (!indexRes)
-                               break;
-                       tuple.t_self = indexRes->heap_iptr;
-                       tuple.t_datamcxt = NULL;
-                       tuple.t_data = NULL;
-                       heap_fetch(indrel, SnapshotNow, &tuple, &buffer, sd);
-                       pfree(indexRes);
-                       if (tuple.t_data == NULL)
-                               continue;
-                       htup = &tuple;
-               }
-               else
-               {
-                       htup = heap_getnext(hscan, 0);
-                       if (!HeapTupleIsValid(htup))
-                               break;
-               }
+       indrel = heap_openr(IndexRelationName, AccessShareLock);
+       indscan = systable_beginscan(indrel, IndexIndrelidIndex, true,
+                                                                SnapshotNow,
+                                                                1, &skey);
 
-               index = (Form_pg_index) GETSTRUCT(htup);
+       while (HeapTupleIsValid(htup = systable_getnext(indscan)))
+       {
+               Form_pg_index index = (Form_pg_index) GETSTRUCT(htup);
 
                result = insert_ordered_oid(result, index->indexrelid);
-
-               if (hasindex)
-                       ReleaseBuffer(buffer);
        }
 
-       if (hasindex)
-       {
-               index_endscan(sd);
-               index_close(irel);
-       }
-       else
-               heap_endscan(hscan);
+       systable_endscan(indscan);
        heap_close(indrel, AccessShareLock);
 
        /* Now save a copy of the completed list in the relcache entry. */
@@ -2594,8 +2668,7 @@ insert_ordered_oid(List *list, Oid datum)
 
 
 /*
- *     init_irels(), write_irels() -- handle special-case initialization of
- *                                                                index relation descriptors.
+ *     load_relcache_init_file, write_relcache_init_file
  *
  *             In late 1992, we started regularly having databases with more than
  *             a thousand classes in them.  With this number of classes, it became
@@ -2609,7 +2682,7 @@ insert_ordered_oid(List *list, Oid datum)
  *             In order to get around the problem, we do the following:
  *
  *                +  When the database system is initialized (at initdb time), we
- *                       don't use indices on pg_attribute.  We do sequential scans.
+ *                       don't use indexes.  We do sequential scans.
  *
  *                +  When the backend is started up in normal mode, we load an image
  *                       of the appropriate relation descriptors, in internal format,
@@ -2621,177 +2694,308 @@ insert_ordered_oid(List *list, Oid datum)
  *
  *             We could dispense with the initialization file and just build the
  *             critical reldescs the hard way on every backend startup, but that
- *             slows down backend startup noticeably if pg_class is large.
+ *             slows down backend startup noticeably.
+ *
+ *             We can in fact go further, and save more relcache entries than
+ *             just the ones that are absolutely critical; this allows us to speed
+ *             up backend startup by not having to build such entries the hard way.
+ *             Presently, all the catalog and index entries that are referred to
+ *             by catcaches are stored in the initialization file.
  *
  *             As of v6.5, vacuum.c deletes the initialization file at completion
  *             of a VACUUM, so that it will be rebuilt at the next backend startup.
- *             This ensures that vacuum-collected stats for the system indexes
- *             will eventually get used by the optimizer --- otherwise the relcache
- *             entries for these indexes will show zero sizes forever, since the
- *             relcache entries are pinned in memory and will never be reloaded
- *             from pg_class.
+ *             This ensures that vacuum-collected stats for the system catalogs
+ *             and indexes will be seen by backends started later.
  */
 
-/* pg_attnumind, pg_classnameind, pg_classoidind */
-#define Num_indices_bootstrap  3
-
-static void
-init_irels(void)
+/*
+ * load_relcache_init_file -- attempt to load cache from the init file
+ *
+ * If successful, return TRUE and set criticalRelcachesBuilt to true.
+ * If not successful, return FALSE and set needNewCacheFile to true.
+ *
+ * NOTE: we assume we are already switched into CacheMemoryContext.
+ */
+static bool
+load_relcache_init_file(void)
 {
-       Size            len;
-       int                     nread;
-       File            fd;
-       Relation        irel[Num_indices_bootstrap];
-       Relation        ird;
-       Form_pg_am      am;
-       Form_pg_class relform;
-       MemoryContext indexcxt;
-       IndexStrategy strat;
-       RegProcedure *support;
-       int                     nstrategies,
-                               nsupport;
+       FILE       *fp;
+       char            initfilename[MAXPGPATH];
+       Relation   *rels;
+       int                     relno,
+                               num_rels,
+                               max_rels,
+                               nailed_rels,
+                               nailed_indexes;
        int                     i;
-       int                     relno;
 
-       if ((fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_RDONLY | PG_BINARY, 0600)) < 0)
+       snprintf(initfilename, sizeof(initfilename), "%s/%s",
+                        DatabasePath, RELCACHE_INIT_FILENAME);
+
+       fp = AllocateFile(initfilename, PG_BINARY_R);
+       if (fp == NULL)
        {
-               write_irels();
-               return;
+               needNewCacheFile = true;
+               return false;
        }
 
-       for (relno = 0; relno < Num_indices_bootstrap; relno++)
+       /*
+        * Read the index relcache entries from the file.  Note we will not
+        * enter any of them into the cache if the read fails partway through;
+        * this helps to guard against broken init files.
+        */
+       max_rels = 100;
+       rels = (Relation *) palloc(max_rels * sizeof(Relation));
+       num_rels = 0;
+       nailed_rels = nailed_indexes = 0;
+       initFileRelationIds = NIL;
+
+       for (relno = 0; ; relno++)
        {
+               Size            len;
+               size_t          nread;
+               Relation        rel;
+               Form_pg_class relform;
+
                /* first read the relation descriptor length */
-               if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
+               if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+               {
+                       if (nread == 0)
+                               break;                  /* end of file */
                        goto read_failed;
+               }
 
                /* safety check for incompatible relcache layout */
                if (len != sizeof(RelationData))
                        goto read_failed;
 
-               ird = irel[relno] = (Relation) palloc(len);
-               MemSet(ird, 0, len);
-
-               /* then, read the Relation structure */
-               if ((nread = FileRead(fd, (char *) ird, len)) != len)
-                       goto read_failed;
-
-               /* reset transient fields */
-               ird->rd_targblock = InvalidBlockNumber;
-               ird->rd_fd = -1;
-               ird->rd_refcnt = 0;
+               /* allocate another relcache header */
+               if (num_rels >= max_rels)
+               {
+                       max_rels *= 2;
+                       rels = (Relation *) repalloc(rels, max_rels * sizeof(Relation));
+               }
 
-               ird->rd_node.tblNode = MyDatabaseId;
+               rel = rels[num_rels++] = (Relation) palloc(len);
 
-               /* next, read the access method tuple form */
-               if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
-                       goto read_failed;
-
-               am = (Form_pg_am) palloc(len);
-               if ((nread = FileRead(fd, (char *) am, len)) != len)
+               /* then, read the Relation structure */
+               if ((nread = fread(rel, 1, len, fp)) != len)
                        goto read_failed;
 
-               ird->rd_am = am;
-
                /* next read the relation tuple form */
-               if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
+               if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
                        goto read_failed;
 
                relform = (Form_pg_class) palloc(len);
-               if ((nread = FileRead(fd, (char *) relform, len)) != len)
+               if ((nread = fread(relform, 1, len, fp)) != len)
                        goto read_failed;
 
-               ird->rd_rel = relform;
+               rel->rd_rel = relform;
 
                /* initialize attribute tuple forms */
-               ird->rd_att = CreateTemplateTupleDesc(relform->relnatts);
+               rel->rd_att = CreateTemplateTupleDesc(relform->relnatts);
 
                /* next read all the attribute tuple form data entries */
-               len = ATTRIBUTE_TUPLE_SIZE;
                for (i = 0; i < relform->relnatts; i++)
                {
-                       if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
+                       if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
                                goto read_failed;
 
-                       ird->rd_att->attrs[i] = (Form_pg_attribute) palloc(len);
+                       rel->rd_att->attrs[i] = (Form_pg_attribute) palloc(len);
 
-                       if ((nread = FileRead(fd, (char *) ird->rd_att->attrs[i], len)) != len)
+                       if ((nread = fread(rel->rd_att->attrs[i], 1, len, fp)) != len)
                                goto read_failed;
                }
 
-               /*
-                * prepare index info context --- parameters should match
-                * RelationInitIndexAccessInfo
-                */
-               indexcxt = AllocSetContextCreate(CacheMemoryContext,
-                                                                                RelationGetRelationName(ird),
-                                                                                0,             /* minsize */
-                                                                                512,   /* initsize */
-                                                                                1024); /* maxsize */
-               ird->rd_indexcxt = indexcxt;
-
-               /* next, read the index strategy map */
-               if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
-                       goto read_failed;
+               /* If it's an index, there's more to do */
+               if (rel->rd_rel->relkind == RELKIND_INDEX)
+               {
+                       Form_pg_am      am;
+                       MemoryContext indexcxt;
+                       IndexStrategy strat;
+                       Oid                *operator;
+                       RegProcedure *support;
+                       int                     nstrategies,
+                                               nsupport;
+
+                       /* Count nailed indexes to ensure we have 'em all */
+                       if (rel->rd_isnailed)
+                               nailed_indexes++;
+
+                       /* next, read the pg_index tuple form */
+                       if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+                               goto read_failed;
 
-               strat = (IndexStrategy) MemoryContextAlloc(indexcxt, len);
-               if ((nread = FileRead(fd, (char *) strat, len)) != len)
-                       goto read_failed;
+                       rel->rd_index = (Form_pg_index) palloc(len);
+                       if ((nread = fread(rel->rd_index, 1, len, fp)) != len)
+                               goto read_failed;
 
-               /* have to invalidate any FmgrInfo data in the strategy maps */
-               nstrategies = am->amstrategies * relform->relnatts;
-               for (i = 0; i < nstrategies; i++)
-                       strat->strategyMapData[i].entry[0].sk_func.fn_oid = InvalidOid;
+                       /* next, read the access method tuple form */
+                       if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+                               goto read_failed;
 
-               ird->rd_istrat = strat;
+                       am = (Form_pg_am) palloc(len);
+                       if ((nread = fread(am, 1, len, fp)) != len)
+                               goto read_failed;
+                       rel->rd_am = am;
 
-               /* finally, read the vector of support procedures */
-               if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
-                       goto read_failed;
-               support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
-               if ((nread = FileRead(fd, (char *) support, len)) != len)
-                       goto read_failed;
+                       /*
+                        * prepare index info context --- parameters should match
+                        * RelationInitIndexAccessInfo
+                        */
+                       indexcxt = AllocSetContextCreate(CacheMemoryContext,
+                                                                                        RelationGetRelationName(rel),
+                                                                                        0,             /* minsize */
+                                                                                        512,   /* initsize */
+                                                                                        1024); /* maxsize */
+                       rel->rd_indexcxt = indexcxt;
+
+                       /* next, read the index strategy map */
+                       if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+                               goto read_failed;
 
-               ird->rd_support = support;
+                       strat = (IndexStrategy) MemoryContextAlloc(indexcxt, len);
+                       if ((nread = fread(strat, 1, len, fp)) != len)
+                               goto read_failed;
 
-               nsupport = relform->relnatts * am->amsupport;
-               ird->rd_supportinfo = (FmgrInfo *)
-                       MemoryContextAlloc(indexcxt, nsupport * sizeof(FmgrInfo));
-               MemSet(ird->rd_supportinfo, 0, nsupport * sizeof(FmgrInfo));
+                       /* have to invalidate any FmgrInfo data in the strategy maps */
+                       nstrategies = am->amstrategies * relform->relnatts;
+                       for (i = 0; i < nstrategies; i++)
+                               strat->strategyMapData[i].entry[0].sk_func.fn_oid = InvalidOid;
+
+                       rel->rd_istrat = strat;
+
+                       /* next, read the vector of operator OIDs */
+                       if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+                               goto read_failed;
+
+                       operator = (Oid *) MemoryContextAlloc(indexcxt, len);
+                       if ((nread = fread(operator, 1, len, fp)) != len)
+                               goto read_failed;
+
+                       rel->rd_operator = operator;
 
-               RelationInitLockInfo(ird);
+                       /* finally, read the vector of support procedures */
+                       if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+                               goto read_failed;
+                       support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
+                       if ((nread = fread(support, 1, len, fp)) != len)
+                               goto read_failed;
+
+                       rel->rd_support = support;
+
+                       /* add a zeroed support-fmgr-info vector */
+                       nsupport = relform->relnatts * am->amsupport;
+                       rel->rd_supportinfo = (FmgrInfo *)
+                               MemoryContextAlloc(indexcxt, nsupport * sizeof(FmgrInfo));
+                       MemSet(rel->rd_supportinfo, 0, nsupport * sizeof(FmgrInfo));
+               }
+               else
+               {
+                       /* Count nailed rels to ensure we have 'em all */
+                       if (rel->rd_isnailed)
+                               nailed_rels++;
+
+                       Assert(rel->rd_index == NULL);
+                       Assert(rel->rd_am == NULL);
+                       Assert(rel->rd_indexcxt == NULL);
+                       Assert(rel->rd_istrat == NULL);
+                       Assert(rel->rd_operator == NULL);
+                       Assert(rel->rd_support == NULL);
+                       Assert(rel->rd_supportinfo == NULL);
+               }
+
+               /*
+                * Rules and triggers are not saved (mainly because the internal
+                * format is complex and subject to change).  They must be rebuilt
+                * if needed by RelationCacheInitializePhase2.  This is not expected
+                * to be a big performance hit since few system catalogs have such.
+                */
+               rel->rd_rules = NULL;
+               rel->rd_rulescxt = NULL;
+               rel->trigdesc = NULL;
+
+               /*
+                * Reset transient-state fields in the relcache entry
+                */
+               rel->rd_fd = -1;
+               rel->rd_targblock = InvalidBlockNumber;
+               if (rel->rd_isnailed)
+                       RelationSetReferenceCount(rel, 1);
+               else
+                       RelationSetReferenceCount(rel, 0);
+               rel->rd_indexfound = false;
+               rel->rd_indexlist = NIL;
+               MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
 
-               RelationCacheInsert(ird);
+               /*
+                * Make sure database ID is correct.  This is needed in case the
+                * pg_internal.init file was copied from some other database by
+                * CREATE DATABASE.
+                */
+               if (rel->rd_rel->relisshared)
+                       rel->rd_node.tblNode = InvalidOid;
+               else
+                       rel->rd_node.tblNode = MyDatabaseId;
+
+               RelationInitLockInfo(rel);
+       }
+
+       /*
+        * We reached the end of the init file without apparent problem.
+        * Did we get the right number of nailed items?  (This is a useful
+        * crosscheck in case the set of critical rels or indexes changes.)
+        */
+       if (nailed_rels != NUM_CRITICAL_RELS ||
+               nailed_indexes != NUM_CRITICAL_INDEXES)
+               goto read_failed;
+
+       /*
+        * OK, all appears well.
+        *
+        * Now insert all the new relcache entries into the cache.
+        */
+       for (relno = 0; relno < num_rels; relno++)
+       {
+               RelationCacheInsert(rels[relno]);
+               /* also make a list of their OIDs, for RelationIdIsInInitFile */
+               initFileRelationIds = lconsi((int) RelationGetRelid(rels[relno]),
+                                                                        initFileRelationIds);
        }
 
-       /* successfully read the init file */
-       FileClose(fd);
+       pfree(rels);
+       FreeFile(fp);
+
        criticalRelcachesBuilt = true;
-       return;
+       return true;
 
-       /* init file is broken, so do it the hard way */
+       /*
+        * init file is broken, so do it the hard way.  We don't bother
+        * trying to free the clutter we just allocated; it's not in the
+        * relcache so it won't hurt.
+        */
 read_failed:
-       FileClose(fd);
-       write_irels();
+       pfree(rels);
+       FreeFile(fp);
+
+       needNewCacheFile = true;
+       return false;
 }
 
+/*
+ * Write out a new initialization file with the current contents
+ * of the relcache.
+ */
 static void
-write_irels(void)
+write_relcache_init_file(void)
 {
-       Size            len;
-       int                     nwritten;
-       File            fd;
-       Relation        irel[Num_indices_bootstrap];
-       Relation        ird;
-       Form_pg_am      am;
-       Form_pg_class relform;
-       IndexStrategy strat;
-       RegProcedure *support;
-       int                     i;
-       int                     relno;
-       RelationBuildDescInfo bi;
+       FILE       *fp;
        char            tempfilename[MAXPGPATH];
        char            finalfilename[MAXPGPATH];
+       HASH_SEQ_STATUS status;
+       RelNameCacheEnt *namehentry;
+       MemoryContext oldcxt;
+       int                     i;
 
        /*
         * We must write a temporary file and rename it into place. Otherwise,
@@ -2803,8 +3007,10 @@ write_irels(void)
        snprintf(finalfilename, sizeof(finalfilename), "%s/%s",
                         DatabasePath, RELCACHE_INIT_FILENAME);
 
-       fd = PathNameOpenFile(tempfilename, O_WRONLY | O_CREAT | O_TRUNC | PG_BINARY, 0600);
-       if (fd < 0)
+       unlink(tempfilename);           /* in case it exists w/wrong permissions */
+
+       fp = AllocateFile(tempfilename, PG_BINARY_W);
+       if (fp == NULL)
        {
                /*
                 * We used to consider this a fatal error, but we might as well
@@ -2814,148 +3020,227 @@ write_irels(void)
                return;
        }
 
-       FileSeek(fd, 0L, SEEK_SET);
-
        /*
-        * Build relation descriptors for the critical system indexes without
-        * resort to the descriptor cache.      In order to do this, we set
-        * ProcessingMode to Bootstrap.  The effect of this is to disable
-        * indexed 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.
-        */
-
-       /*---------
-        * Removed the following ProcessingMode change -- inoue
-        * At this point
-        * 1) Catalog Cache isn't initialized
-        * 2) Relation Cache for the following critical indexes aren't built
-        * oldmode = GetProcessingMode();
-        * SetProcessingMode(BootstrapProcessing);
-        *---------
+        * Write all the reldescs (in no particular order).
         */
+       hash_seq_init(&status, RelationNameCache);
 
-       bi.infotype = INFO_RELNAME;
-       bi.i.info_name = AttributeRelidNumIndex;
-       irel[0] = RelationBuildDesc(bi, NULL);
-       irel[0]->rd_isnailed = true;
-
-       bi.i.info_name = ClassNameIndex;
-       irel[1] = RelationBuildDesc(bi, NULL);
-       irel[1]->rd_isnailed = true;
-
-       bi.i.info_name = ClassOidIndex;
-       irel[2] = RelationBuildDesc(bi, NULL);
-       irel[2]->rd_isnailed = true;
-
-       criticalRelcachesBuilt = true;
+       initFileRelationIds = NIL;
 
-       /*
-        * Removed the following ProcessingMode -- inoue
-        * SetProcessingMode(oldmode);
-        */
-
-       /*
-        * Write out the index reldescs to the special cache file.
-        */
-       for (relno = 0; relno < Num_indices_bootstrap; relno++)
+       while ((namehentry = (RelNameCacheEnt *) hash_seq_search(&status)) != NULL)
        {
-               ird = irel[relno];
-
-               /* save the volatile fields in the relation descriptor */
-               am = ird->rd_am;
-               ird->rd_am = (Form_pg_am) NULL;
-               relform = ird->rd_rel;
-               ird->rd_rel = (Form_pg_class) NULL;
-               strat = ird->rd_istrat;
-               support = ird->rd_support;
+               Relation        rel = namehentry->reldesc;
+               Form_pg_class relform = rel->rd_rel;
+               Size            len;
 
                /*
-                * first write the relation descriptor , excluding strategy and
-                * support
+                * first write the relcache entry proper
                 */
                len = sizeof(RelationData);
 
                /* first, write the relation descriptor length */
-               if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
-                       != sizeof(len))
+               if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
                        elog(FATAL, "cannot write init file -- descriptor length");
 
                /* next, write out the Relation structure */
-               if ((nwritten = FileWrite(fd, (char *) ird, len)) != len)
+               if (fwrite(rel, 1, len, fp) != len)
                        elog(FATAL, "cannot write init file -- reldesc");
 
-               /* next, write the access method tuple form */
-               len = sizeof(FormData_pg_am);
-               if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
-                       != sizeof(len))
-                       elog(FATAL, "cannot write init file -- am tuple form length");
-
-               if ((nwritten = FileWrite(fd, (char *) am, len)) != len)
-                       elog(FATAL, "cannot write init file -- am tuple form");
-
                /* next write the relation tuple form */
                len = sizeof(FormData_pg_class);
-               if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
-                       != sizeof(len))
+               if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
                        elog(FATAL, "cannot write init file -- relation tuple form length");
 
-               if ((nwritten = FileWrite(fd, (char *) relform, len)) != len)
+               if (fwrite(relform, 1, len, fp) != len)
                        elog(FATAL, "cannot write init file -- relation tuple form");
 
                /* next, do all the attribute tuple form data entries */
-               len = ATTRIBUTE_TUPLE_SIZE;
                for (i = 0; i < relform->relnatts; i++)
                {
-                       if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
-                               != sizeof(len))
+                       len = ATTRIBUTE_TUPLE_SIZE;
+                       if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
                                elog(FATAL, "cannot write init file -- length of attdesc %d", i);
-                       if ((nwritten = FileWrite(fd, (char *) ird->rd_att->attrs[i], len))
-                               != len)
+                       if (fwrite(rel->rd_att->attrs[i], 1, len, fp) != len)
                                elog(FATAL, "cannot write init file -- attdesc %d", i);
                }
 
-               /* next, write the index strategy map */
-               len = AttributeNumberGetIndexStrategySize(relform->relnatts,
-                                                                                                 am->amstrategies);
-               if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
-                       != sizeof(len))
-                       elog(FATAL, "cannot write init file -- strategy map length");
-
-               if ((nwritten = FileWrite(fd, (char *) strat, len)) != len)
-                       elog(FATAL, "cannot write init file -- strategy map");
-
-               /* finally, write the vector of support procedures */
-               len = relform->relnatts * (am->amsupport * sizeof(RegProcedure));
-               if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
-                       != sizeof(len))
-                       elog(FATAL, "cannot write init file -- support vector length");
+               /* If it's an index, there's more to do */
+               if (rel->rd_rel->relkind == RELKIND_INDEX)
+               {
+                       Form_pg_am      am = rel->rd_am;
+                       HeapTuple       tuple;
 
-               if ((nwritten = FileWrite(fd, (char *) support, len)) != len)
-                       elog(FATAL, "cannot write init file -- support vector");
+                       /*
+                        * We need to write the index tuple form, but this is a bit
+                        * tricky since it's a variable-length struct.  Rather than
+                        * hoping to intuit the length, fetch the pg_index tuple
+                        * afresh using the syscache, and write that.
+                        */
+                       tuple = SearchSysCache(INDEXRELID,
+                                                                  ObjectIdGetDatum(RelationGetRelid(rel)),
+                                                                  0, 0, 0);
+                       if (!HeapTupleIsValid(tuple))
+                               elog(ERROR, "write_relcache_init_file: no pg_index entry for index %u",
+                                        RelationGetRelid(rel));
+                       len = tuple->t_len - tuple->t_data->t_hoff;
+                       if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
+                               elog(FATAL, "cannot write init file -- index tuple form length");
+                       if (fwrite(GETSTRUCT(tuple), 1, len, fp) != len)
+                               elog(FATAL, "cannot write init file -- index tuple form");
+                       ReleaseSysCache(tuple);
+
+                       /* next, write the access method tuple form */
+                       len = sizeof(FormData_pg_am);
+                       if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
+                               elog(FATAL, "cannot write init file -- am tuple form length");
+
+                       if (fwrite(am, 1, len, fp) != len)
+                               elog(FATAL, "cannot write init file -- am tuple form");
+
+                       /* next, write the index strategy map */
+                       len = AttributeNumberGetIndexStrategySize(relform->relnatts,
+                                                                                                         am->amstrategies);
+                       if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
+                               elog(FATAL, "cannot write init file -- strategy map length");
+
+                       if (fwrite(rel->rd_istrat, 1, len, fp) != len)
+                               elog(FATAL, "cannot write init file -- strategy map");
+
+                       /* next, write the vector of operator OIDs */
+                       len = relform->relnatts * (am->amstrategies * sizeof(Oid));
+                       if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
+                               elog(FATAL, "cannot write init file -- operator vector length");
+
+                       if (fwrite(rel->rd_operator, 1, len, fp) != len)
+                               elog(FATAL, "cannot write init file -- operator vector");
+
+                       /* finally, write the vector of support procedures */
+                       len = relform->relnatts * (am->amsupport * sizeof(RegProcedure));
+                       if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
+                               elog(FATAL, "cannot write init file -- support vector length");
+
+                       if (fwrite(rel->rd_support, 1, len, fp) != len)
+                               elog(FATAL, "cannot write init file -- support vector");
+               }
 
-               /* restore volatile fields */
-               ird->rd_am = am;
-               ird->rd_rel = relform;
+               /* also make a list of their OIDs, for RelationIdIsInInitFile */
+               oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+               initFileRelationIds = lconsi((int) RelationGetRelid(rel),
+                                                                        initFileRelationIds);
+               MemoryContextSwitchTo(oldcxt);
        }
 
-       FileClose(fd);
+       FreeFile(fp);
 
        /*
-        * And rename the temp file to its final name, deleting any
-        * previously-existing init file.
+        * Now we have to check whether the data we've so painstakingly
+        * accumulated is already obsolete due to someone else's just-committed
+        * catalog changes.  If so, we just delete the temp file and leave it
+        * to the next backend to try again.  (Our own relcache entries will be
+        * updated by SI message processing, but we can't be sure whether what
+        * we wrote out was up-to-date.)
         *
-        * Note: a failure here is possible under Cygwin, if some other
-        * backend is holding open an unlinked-but-not-yet-gone init file.
-        * So treat this as a noncritical failure.
+        * This mustn't run concurrently with RelationCacheInitFileInvalidate,
+        * so grab a serialization lock for the duration.
         */
-       if (rename(tempfilename, finalfilename) < 0)
+       LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
+
+       /* Make sure we have seen all incoming SI messages */
+       AcceptInvalidationMessages();
+
+       /*
+        * If we have received any SI relcache invals since backend start,
+        * assume we may have written out-of-date data.
+        */
+       if (relcacheInvalsReceived == 0L)
        {
-               elog(NOTICE, "Cannot rename init file %s to %s: %m\n\tContinuing anyway, but there's something wrong.", tempfilename, finalfilename);
                /*
-                * If we fail, try to clean up the useless temp file; don't bother
-                * to complain if this fails too.
+                * OK, rename the temp file to its final name, deleting any
+                * previously-existing init file.
+                *
+                * Note: a failure here is possible under Cygwin, if some other
+                * backend is holding open an unlinked-but-not-yet-gone init file.
+                * So treat this as a noncritical failure.
                 */
+               if (rename(tempfilename, finalfilename) < 0)
+               {
+                       elog(NOTICE, "Cannot rename init file %s to %s: %m\n\tContinuing anyway, but there's something wrong.", tempfilename, finalfilename);
+                       /*
+                        * If we fail, try to clean up the useless temp file; don't bother
+                        * to complain if this fails too.
+                        */
+                       unlink(tempfilename);
+               }
+       }
+       else
+       {
+               /* Delete the already-obsolete temp file */
                unlink(tempfilename);
        }
+
+       LWLockRelease(RelCacheInitLock);
+}
+
+/*
+ * Detect whether a given relation (identified by OID) is one of the ones
+ * we store in the init file.
+ *
+ * Note that we effectively assume that all backends running in a database
+ * would choose to store the same set of relations in the init file;
+ * otherwise there are cases where we'd fail to detect the need for an init
+ * file invalidation.  This does not seem likely to be a problem in practice.
+ */
+bool
+RelationIdIsInInitFile(Oid relationId)
+{
+       return intMember((int) relationId, initFileRelationIds);
+}
+
+/*
+ * Invalidate (remove) the init file during commit of a transaction that
+ * changed one or more of the relation cache entries that are kept in the
+ * init file.
+ *
+ * We actually need to remove the init file twice: once just before sending
+ * the SI messages that include relcache inval for such relations, and once
+ * just after sending them.  The unlink before ensures that a backend that's
+ * currently starting cannot read the now-obsolete init file and then miss
+ * the SI messages that will force it to update its relcache entries.  (This
+ * works because the backend startup sequence gets into the PROC array before
+ * trying to load the init file.)  The unlink after is to synchronize with a
+ * backend that may currently be trying to write an init file based on data
+ * that we've just rendered invalid.  Such a backend will see the SI messages,
+ * but we can't leave the init file sitting around to fool later backends.
+ *
+ * Ignore any failure to unlink the file, since it might not be there if
+ * no backend has been started since the last removal.
+ */
+void
+RelationCacheInitFileInvalidate(bool beforeSend)
+{
+       char            initfilename[MAXPGPATH];
+
+       snprintf(initfilename, sizeof(initfilename), "%s/%s",
+                        DatabasePath, RELCACHE_INIT_FILENAME);
+
+       if (beforeSend)
+       {
+               /* no interlock needed here */
+               unlink(initfilename);
+       }
+       else
+       {
+               /*
+                * We need to interlock this against write_relcache_init_file,
+                * to guard against possibility that someone renames a new-but-
+                * already-obsolete init file into place just after we unlink.
+                * With the interlock, it's certain that write_relcache_init_file
+                * will notice our SI inval message before renaming into place,
+                * or else that we will execute second and successfully unlink
+                * the file.
+                */
+               LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
+               unlink(initfilename);
+               LWLockRelease(RelCacheInitLock);
+       }
 }
index e629bf48e468aa42a20caa53f5aad1e49588276d..dfbcccffbed250efda87862838f135fc11c352cb 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.66 2001/10/25 05:49:46 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.67 2002/02/19 20:11:18 tgl Exp $
  *
  * NOTES
  *       These routines allow the parser/planner/executor to perform
@@ -113,6 +113,16 @@ static struct cachedesc cacheinfo[] = {
                        0,
                        0
        }},
+       {AccessMethodRelationName,      /* AMOID */
+               AmOidIndex,
+               0,
+               1,
+               {
+                       ObjectIdAttributeNumber,
+                       0,
+                       0,
+                       0
+       }},
        {AccessMethodOperatorRelationName,      /* AMOPOPID */
                AccessMethodOperatorIndex,
                0,
@@ -365,8 +375,7 @@ static struct cachedesc cacheinfo[] = {
        }}
 };
 
-static CatCache *SysCache[
-                                                 lengthof(cacheinfo)];
+static CatCache *SysCache[lengthof(cacheinfo)];
 static int     SysCacheSize = lengthof(cacheinfo);
 static bool CacheInitialized = false;
 
@@ -383,7 +392,7 @@ IsCacheInitialized(void)
  *
  * Note that no database access is done here; we only allocate memory
  * and initialize the cache structure. Interrogation of the database
- * to complete initialization of a cache happens only upon first use
+ * to complete initialization of a cache happens upon first use
  * of that cache.
  */
 void
@@ -411,6 +420,32 @@ InitCatalogCache(void)
 }
 
 
+/*
+ * InitCatalogCachePhase2 - finish initializing the caches
+ *
+ * Finish initializing all the caches, including necessary database
+ * access.
+ *
+ * This is *not* essential; normally we allow syscaches to be initialized
+ * on first use.  However, it is useful as a mechanism to preload the
+ * relcache with entries for the most-commonly-used system catalogs.
+ * Therefore, we invoke this routine when we need to write a new relcache
+ * init file.
+ */
+void
+InitCatalogCachePhase2(void)
+{
+       int                     cacheId;
+
+       Assert(CacheInitialized);
+
+       for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
+       {
+               InitCatCachePhase2(SysCache[cacheId]);
+       }
+}
+
+
 /*
  * SearchSysCache
  *
index 3a48b133bfe8aeb3bf50de83fc858b740d51dd67..222ab6d54ab2aed462512795c63717403842055f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.97 2001/11/02 16:30:29 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.98 2002/02/19 20:11:18 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -287,16 +287,15 @@ InitPostgres(const char *dbname, const char *username)
        AmiTransactionOverride(bootstrap);
 
        /*
-        * Initialize the relation descriptor cache. The pre-allocated
-        * reldescs are created here.
+        * Initialize the relation descriptor cache.  This must create
+        * at least the minimum set of "nailed-in" cache entries.  No
+        * catalog access happens here.
         */
        RelationCacheInitialize();
 
        /*
-        * Initialize all the system catalog caches.
-        *
-        * Does not touch files since all routines are builtins (?) - thomas
-        * 1997-11-01
+        * Initialize all the system catalog caches.  Note that no catalog
+        * access happens here; we only set up the cache structure.
         */
        InitCatalogCache();
 
@@ -313,7 +312,11 @@ InitPostgres(const char *dbname, const char *username)
        if (!bootstrap)
                StartTransactionCommand();
 
-       /* replace faked-up relcache entries with the real info */
+       /*
+        * It's now possible to do real access to the system catalogs.
+        *
+        * Replace faked-up relcache entries with correct info.
+        */
        RelationCacheInitializePhase2();
 
        /*
@@ -333,8 +336,10 @@ InitPostgres(const char *dbname, const char *username)
                }
        }
        else
+       {
                /* normal multiuser case */
                InitializeSessionUserId(username);
+       }
 
        /*
         * Unless we are bootstrapping, double-check that InitMyDatabaseInfo()
@@ -349,6 +354,13 @@ InitPostgres(const char *dbname, const char *username)
        set_default_client_encoding();
 #endif
 
+       /*
+        * Final phase of relation cache startup: write a new cache file
+        * if necessary.  This is done after ReverifyMyDatabase to avoid
+        * writing a cache file into a dead database.
+        */
+       RelationCacheInitializePhase3();
+
        /*
         * Set up process-exit callbacks to remove temp relations and then do
         * pre-shutdown cleanup.  This should be last because we want
index db212156c8db9d9cae582ce76d0bf99ad350f528..c8cb4c105863495bfeb423f002a9a475b38c015d 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: genam.h,v 1.31 2001/11/05 17:46:31 momjian Exp $
+ * $Id: genam.h,v 1.32 2002/02/19 20:11:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,9 +31,23 @@ typedef struct IndexBulkDeleteResult
 typedef bool (*IndexBulkDeleteCallback) (ItemPointer itemptr, void *state);
 
 
-/* ----------------
- *             generalized index_ interface routines (in indexam.c)
- * ----------------
+/* Struct for heap-or-index scans of system tables */
+typedef struct SysScanDescData
+{
+       Relation        heap_rel;               /* catalog being scanned */
+       Snapshot        snapshot;               /* time qual (normally SnapshotNow) */
+       Relation        irel;                   /* NULL if doing heap scan */
+       HeapScanDesc scan;                      /* only valid in heap-scan case */
+       IndexScanDesc iscan;            /* only valid in index-scan case */
+       HeapTupleData tuple;            /* workspace for indexscan */
+       Buffer          buffer;                 /* working state for indexscan */
+} SysScanDescData;
+
+typedef SysScanDescData *SysScanDesc;
+
+
+/*
+ * generalized index_ interface routines (in indexam.c)
  */
 extern Relation index_open(Oid relationId);
 extern Relation index_openr(const char *relationName);
@@ -59,9 +73,22 @@ extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum,
 extern struct FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum,
                                  uint16 procnum);
 
-/* in genam.c */
+/*
+ * index access method support routines (in genam.c)
+ */
 extern IndexScanDesc RelationGetIndexScan(Relation relation, bool scanFromEnd,
                                         uint16 numberOfKeys, ScanKey key);
 extern void IndexScanEnd(IndexScanDesc scan);
 
+/*
+ * heap-or-index access to system catalogs (in genam.c)
+ */
+extern SysScanDesc systable_beginscan(Relation rel,
+                                                                         const char *indexRelname,
+                                                                         bool indexOK,
+                                                                         Snapshot snapshot,
+                                                                         unsigned nkeys, ScanKey key);
+extern HeapTuple systable_getnext(SysScanDesc sysscan);
+extern void systable_endscan(SysScanDesc sysscan);
+
 #endif   /* GENAM_H */
index c1000cb70b4a258f6926c62fd01a33bcab49cd68..1335863f8cf8df7715cebbbeb747c05f2276fed7 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: istrat.h,v 1.23 2001/11/05 17:46:31 momjian Exp $
+ * $Id: istrat.h,v 1.24 2002/02/19 20:11:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,6 +47,8 @@
  */
 #define IndexStrategyIsValid(s) PointerIsValid(s)
 
+extern ScanKey StrategyMapGetScanKeyEntry(StrategyMap map,
+                                                                                 StrategyNumber strategyNumber);
 extern StrategyMap IndexStrategyGetStrategyMap(IndexStrategy indexStrategy,
                                          StrategyNumber maxStrategyNum, AttrNumber attrNum);
 
@@ -55,13 +57,5 @@ extern Size AttributeNumberGetIndexStrategySize(AttrNumber maxAttributeNumber,
 extern StrategyNumber RelationGetStrategy(Relation relation,
                           AttrNumber attributeNumber, StrategyEvaluation evaluation,
                                        RegProcedure procedure);
-extern void IndexSupportInitialize(IndexStrategy indexStrategy,
-                                          RegProcedure *indexSupport,
-                                          bool *isUnique,
-                                          Oid indexObjectId,
-                                          Oid accessMethodObjectId,
-                                          StrategyNumber maxStrategyNumber,
-                                          StrategyNumber maxSupportNumber,
-                                          AttrNumber maxAttributeNumber);
 
 #endif   /* ISTRAT_H */
index fb6facec0a844c24e65087987b5793aa39e0a9b3..a2d47b836d25c09649549551fba73615636fb97b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: index.h,v 1.43 2001/11/05 17:46:31 momjian Exp $
+ * $Id: index.h,v 1.44 2002/02/19 20:11:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -15,6 +15,7 @@
 #define INDEX_H
 
 #include "access/itup.h"
+#include "catalog/pg_index.h"
 #include "nodes/execnodes.h"
 
 
@@ -27,9 +28,6 @@ typedef void (*IndexBuildCallback) (Relation index,
                                                                                                void *state);
 
 
-extern Form_pg_am AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
-                                                       MemoryContext resultCxt);
-
 extern Oid index_create(char *heapRelationName,
                         char *indexRelationName,
                         IndexInfo *indexInfo,
@@ -40,7 +38,7 @@ extern Oid index_create(char *heapRelationName,
 
 extern void index_drop(Oid indexId);
 
-extern IndexInfo *BuildIndexInfo(HeapTuple indexTuple);
+extern IndexInfo *BuildIndexInfo(Form_pg_index indexStruct);
 
 extern void FormIndexDatum(IndexInfo *indexInfo,
                           HeapTuple heapTuple,
index 2ca7bf8286e5953965b4618e70e7e11daf9d59b7..8d0ba9c4b9c88e33e8dc4a0af028a68a72a1c6cf 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: indexing.h,v 1.56 2001/11/05 17:46:31 momjian Exp $
+ * $Id: indexing.h,v 1.57 2002/02/19 20:11:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -123,15 +123,6 @@ extern void CatalogCloseIndices(int nIndices, Relation *idescs);
 extern void CatalogIndexInsert(Relation *idescs, int nIndices,
                                   Relation heapRelation, HeapTuple heapTuple);
 
-/*
- * Canned functions for indexscans on certain system indexes.
- * All index-value arguments should be passed as Datum for portability!
- */
-extern HeapTuple AttributeRelidNumIndexScan(Relation heapRelation,
-                                                  Datum relid, Datum attnum);
-extern HeapTuple ClassNameIndexScan(Relation heapRelation, Datum relName);
-extern HeapTuple ClassOidIndexScan(Relation heapRelation, Datum relId);
-
 
 /*
  * These macros are just to keep the C compiler from spitting up on the
index 4e4e07a2c72eece838ef9dfb954b4e8df1dde1f2..c089a47731f0f7c0376666f0f6addb45081330c0 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: executor.h,v 1.61 2001/11/05 17:46:33 momjian Exp $
+ * $Id: executor.h,v 1.62 2002/02/19 20:11:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * prototypes from functions in execAmi.c
  */
-extern void ExecOpenScanR(Oid relOid, int nkeys, ScanKey skeys, bool isindex,
-                         ScanDirection dir, Snapshot snapshot,
-                         Relation *returnRelation, Pointer *returnScanDesc);
-extern void ExecCloseR(Plan *node);
 extern void ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent);
-extern HeapScanDesc ExecReScanR(Relation relDesc, HeapScanDesc scanDesc,
-                       ScanDirection direction, int nkeys, ScanKey skeys);
 extern void ExecMarkPos(Plan *node);
 extern void ExecRestrPos(Plan *node);
 
index 4db2d7e2c0ff8ec6529b54a05018a9c1ad9c6327..91c2084fd9cd76df9d9df0af516fa37be48ebc8f 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lwlock.h,v 1.4 2001/11/05 17:46:35 momjian Exp $
+ * $Id: lwlock.h,v 1.5 2002/02/19 20:11:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -38,6 +38,7 @@ typedef enum LWLockId
        ControlFileLock,
        CheckpointLock,
        CLogControlLock,
+       RelCacheInitLock,
 
        NumFixedLWLocks,                        /* must be last except for
                                                                 * MaxDynamicLWLock */
index de5957441ac5c39522c3cba9f9c1f1cc3aed1c4c..6ad0d74851c9987a8c44177b358e281a94955698 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catcache.h,v 1.37 2001/11/05 17:46:36 momjian Exp $
+ * $Id: catcache.h,v 1.38 2002/02/19 20:11:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,6 +44,12 @@ typedef struct catcache
        int                     cc_key[4];              /* AttrNumber of each key */
        PGFunction      cc_hashfunc[4]; /* hash function to use for each key */
        ScanKeyData cc_skey[4];         /* precomputed key info for heap scans */
+#ifdef CATCACHE_STATS
+       long            cc_searches;    /* total # searches against this cache */
+       long            cc_hits;                /* # of matches against existing entry */
+       long            cc_newloads;    /* # of successful loads of new entry */
+       /* cc_searches - (cc_hits + cc_newloads) is # of failed searches */
+#endif
        Dllist          cc_bucket[1];   /* hash buckets --- VARIABLE LENGTH ARRAY */
 } CatCache;                                            /* VARIABLE LENGTH STRUCT */
 
@@ -89,6 +95,7 @@ extern void AtEOXact_CatCache(bool isCommit);
 extern CatCache *InitCatCache(int id, char *relname, char *indname,
                         int reloidattr,
                         int nkeys, int *key);
+extern void InitCatCachePhase2(CatCache *cache);
 
 extern HeapTuple SearchCatCache(CatCache *cache,
                           Datum v1, Datum v2,
index 1bfcaa83de37c81e05a05abaa62040b2ce8116da..49814386ca6adc23a45a6915e829ae21956eddbf 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: rel.h,v 1.55 2001/11/05 17:46:36 momjian Exp $
+ * $Id: rel.h,v 1.56 2002/02/19 20:11:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include "access/tupdesc.h"
 #include "catalog/pg_am.h"
 #include "catalog/pg_class.h"
+#include "catalog/pg_index.h"
 #include "rewrite/prs2lock.h"
 #include "storage/block.h"
 #include "storage/fd.h"
@@ -113,19 +114,23 @@ typedef struct RelationData
        bool            rd_isnailed;    /* rel is nailed in cache */
        bool            rd_indexfound;  /* true if rd_indexlist is valid */
        bool            rd_uniqueindex; /* true if rel is a UNIQUE index */
-       Form_pg_am      rd_am;                  /* AM tuple (if an index) */
        Form_pg_class rd_rel;           /* RELATION tuple */
+       TupleDesc       rd_att;                 /* tuple descriptor */
        Oid                     rd_id;                  /* relation's object id */
        List       *rd_indexlist;       /* list of OIDs of indexes on relation */
        LockInfoData rd_lockInfo;       /* lock mgr's info for locking relation */
-       TupleDesc       rd_att;                 /* tuple descriptor */
        RuleLock   *rd_rules;           /* rewrite rules */
        MemoryContext rd_rulescxt;      /* private memory cxt for rd_rules, if any */
        TriggerDesc *trigdesc;          /* Trigger info, or NULL if rel has none */
 
+       /* These are non-NULL only for an index relation: */
+       Form_pg_index rd_index;         /* pg_index tuple describing this index */
+       Form_pg_am      rd_am;                  /* pg_am tuple for index's AM */
+
        /* index access support info (used only for an index relation) */
        MemoryContext rd_indexcxt;      /* private memory cxt for this stuff */
        IndexStrategy rd_istrat;        /* operator strategy map */
+       Oid                *rd_operator;        /* OIDs of index operators */
        RegProcedure *rd_support;       /* OIDs of support procedures */
        struct FmgrInfo *rd_supportinfo;        /* lookup info for support
                                                                                 * procedures */
index cd265636155d3caaa5f395e11c84a85490c1624e..e5af1bee61b8e88233e243312aa7e8c2f19ae270 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: relcache.h,v 1.29 2001/11/05 17:46:36 momjian Exp $
+ * $Id: relcache.h,v 1.30 2002/02/19 20:11:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,6 +40,7 @@ extern void RelationInitIndexAccessInfo(Relation relation);
  */
 extern void RelationCacheInitialize(void);
 extern void RelationCacheInitializePhase2(void);
+extern void RelationCacheInitializePhase3(void);
 
 /*
  * Routine to create a relcache entry for an about-to-be-created relation
@@ -62,15 +63,18 @@ extern void RelationPurgeLocalRelation(bool xactComitted);
 
 extern void RelationCacheAbort(void);
 
+/*
+ * Routines to help manage rebuilding of relcache init file
+ */
+extern bool RelationIdIsInInitFile(Oid relationId);
+extern void RelationCacheInitFileInvalidate(bool beforeSend);
 
 /* XLOG support */
 extern void CreateDummyCaches(void);
 extern void DestroyDummyCaches(void);
 
-/*
- * both vacuum.c and relcache.c need to know the name of the relcache init file
- */
 
-#define RELCACHE_INIT_FILENAME "pg_internal.init"
+/* should be used only by relcache.c and catcache.c */
+extern bool criticalRelcachesBuilt;
 
 #endif   /* RELCACHE_H */
index 5e7b2d864ff78b1ad5574777492dc40363682114..6164c02b1525e6320b545250f39518e9a16f82e2 100644 (file)
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: syscache.h,v 1.36 2001/11/05 17:46:36 momjian Exp $
+ * $Id: syscache.h,v 1.37 2002/02/19 20:11:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #define AGGNAME                        0
 #define AMNAME                 1
-#define AMOPOPID               2
-#define AMOPSTRATEGY   3
-#define AMPROCNUM              4
-#define ATTNAME                        5
-#define ATTNUM                 6
-#define CLAAMNAME              7
-#define CLAOID                 8
-#define GRONAME                        9
-#define GROSYSID               10
-#define INDEXRELID             11
-#define INHRELID               12
-#define LANGNAME               13
-#define LANGOID                        14
-#define OPERNAME               15
-#define OPEROID                        16
-#define PROCNAME               17
-#define PROCOID                        18
-#define RELNAME                        19
-#define RELOID                 20
-#define RULENAME               21
-#define SHADOWNAME             22
-#define SHADOWSYSID            23
-#define STATRELATT             24
-#define TYPENAME               25
-#define TYPEOID                        26
+#define AMOID                  2
+#define AMOPOPID               3
+#define AMOPSTRATEGY   4
+#define AMPROCNUM              5
+#define ATTNAME                        6
+#define ATTNUM                 7
+#define CLAAMNAME              8
+#define CLAOID                 9
+#define GRONAME                        10
+#define GROSYSID               11
+#define INDEXRELID             12
+#define INHRELID               13
+#define LANGNAME               14
+#define LANGOID                        15
+#define OPERNAME               16
+#define OPEROID                        17
+#define PROCNAME               18
+#define PROCOID                        19
+#define RELNAME                        20
+#define RELOID                 21
+#define RULENAME               22
+#define SHADOWNAME             23
+#define SHADOWSYSID            24
+#define STATRELATT             25
+#define TYPENAME               26
+#define TYPEOID                        27
 
 extern void InitCatalogCache(void);
+extern void InitCatalogCachePhase2(void);
 
 extern HeapTuple SearchSysCache(int cacheId,
                           Datum key1, Datum key2, Datum key3, Datum key4);