]> granicus.if.org Git - postgresql/commitdiff
Fix performance problems with pg_index lookups (see, for example,
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 17 Jun 2000 21:49:04 +0000 (21:49 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 17 Jun 2000 21:49:04 +0000 (21:49 +0000)
discussion of 5/19/00).  pg_index is now searched for indexes of a
relation using an indexscan.  Moreover, this is done once and cached
in the relcache entry for the relation, in the form of a list of OIDs
for the indexes.  This list is used by the parser and executor to drive
lookups in the pg_index syscache when they want to know the properties
of the indexes.  Net result: index information will be fully cached
for repetitive operations such as inserts.

13 files changed:
src/backend/catalog/index.c
src/backend/commands/copy.c
src/backend/commands/indexcmds.c
src/backend/commands/vacuum.c
src/backend/executor/execMain.c
src/backend/executor/execUtils.c
src/backend/executor/nodeAppend.c
src/backend/optimizer/util/plancat.c
src/backend/parser/analyze.c
src/backend/utils/cache/relcache.c
src/include/executor/executor.h
src/include/utils/rel.h
src/include/utils/relcache.h

index b21f408e2cb5a4a9d49591275c8a80a63e62157f..755a7512723e695d9a061408de0f1d3085253c87 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.116 2000/06/17 04:56:36 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.117 2000/06/17 21:48:39 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1105,6 +1105,7 @@ index_create(char *heapRelationName,
 void
 index_drop(Oid indexId)
 {
+       Oid                     heapId;
        Relation        userHeapRelation;
        Relation        userIndexRelation;
        Relation        indexRelation;
@@ -1125,8 +1126,8 @@ index_drop(Oid indexId)
         *      else other backends will still see this index in pg_index.
         * ----------------
         */
-       userHeapRelation = heap_open(IndexGetRelation(indexId),
-                                                                AccessExclusiveLock);
+       heapId = IndexGetRelation(indexId);
+       userHeapRelation = heap_open(heapId, AccessExclusiveLock);
 
        userIndexRelation = index_open(indexId);
        LockRelation(userIndexRelation, AccessExclusiveLock);
@@ -1158,6 +1159,7 @@ index_drop(Oid indexId)
         */
        relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
 
+       /* Remove the pg_class tuple for the index itself */
        tuple = SearchSysCacheTupleCopy(RELOID,
                                                                        ObjectIdGetDatum(indexId),
                                                                        0, 0, 0);
@@ -1166,6 +1168,23 @@ index_drop(Oid indexId)
 
        heap_delete(relationRelation, &tuple->t_self, NULL);
        heap_freetuple(tuple);
+
+       /*
+        * Find the pg_class tuple for the owning relation.  We do not attempt
+        * to clear relhasindex, since we are too lazy to test whether any other
+        * indexes remain (the next VACUUM will fix it if necessary).  But we
+        * must send out a shared-cache-inval notice on the owning relation
+        * to ensure other backends update their relcache lists of indexes.
+        */
+       tuple = SearchSysCacheTupleCopy(RELOID,
+                                                                       ObjectIdGetDatum(heapId),
+                                                                       0, 0, 0);
+
+       Assert(HeapTupleIsValid(tuple));
+
+       ImmediateInvalidateSharedHeapTuple(relationRelation, tuple);
+       heap_freetuple(tuple);
+
        heap_close(relationRelation, RowExclusiveLock);
 
        /* ----------------
@@ -1447,9 +1466,6 @@ setRelhasindexInplace(Oid relid, bool hasindex, bool immediate)
         */
        if (pg_class_scan)
        {
-
-               if (!IsBootstrapProcessingMode())
-                       ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
                rd_rel = (Form_pg_class) GETSTRUCT(tuple);
                rd_rel->relhasindex = hasindex;
                WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
@@ -1461,12 +1477,18 @@ setRelhasindexInplace(Oid relid, bool hasindex, bool immediate)
 
                htup.t_self = tuple->t_self;
                heap_fetch(pg_class, SnapshotNow, &htup, &buffer);
-               ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
                rd_rel = (Form_pg_class) GETSTRUCT(&htup);
                rd_rel->relhasindex = hasindex;
                WriteBuffer(buffer);
        }
 
+       /*
+        * Send out a shared-cache-inval message so other backends notice the
+        * update and fix their syscaches/relcaches.
+        */
+       if (!IsBootstrapProcessingMode())
+               ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
+
        if (!pg_class_scan)
                heap_freetuple(tuple);
        else
index db20ca7372f155ee0d7ae12099cbc311852ffbe1..e29ed167963c0a8f3d008ac0b6910aa912a1c4b9 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.114 2000/06/15 03:32:07 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.115 2000/06/17 21:48:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,6 +32,7 @@
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
+#include "utils/relcache.h"
 #include "utils/syscache.h"
 
 #ifdef MULTIBYTE
@@ -1081,78 +1082,43 @@ IsTypeByVal(Oid type)
  * Space for the array itself is palloc'ed.
  */
 
-typedef struct rel_list
-{
-       Oid                     index_rel_oid;
-       struct rel_list *next;
-} RelationList;
-
 static void
 GetIndexRelations(Oid main_relation_oid,
                                  int *n_indices,
                                  Relation **index_rels)
 {
-       RelationList *head,
-                          *scan;
-       Relation        pg_index_rel;
-       HeapScanDesc scandesc;
-       Oid                     index_relation_oid;
-       HeapTuple       tuple;
-       TupleDesc       tupDesc;
+       Relation        relation;
+       List       *indexoidlist,
+                          *indexoidscan;
        int                     i;
-       bool            isnull;
 
-       pg_index_rel = heap_openr(IndexRelationName, AccessShareLock);
-       scandesc = heap_beginscan(pg_index_rel, 0, SnapshotNow, 0, NULL);
-       tupDesc = RelationGetDescr(pg_index_rel);
+       relation = heap_open(main_relation_oid, AccessShareLock);
+       indexoidlist = RelationGetIndexList(relation);
 
-       *n_indices = 0;
+       *n_indices = length(indexoidlist);
 
-       head = (RelationList *) palloc(sizeof(RelationList));
-       scan = head;
-       head->next = NULL;
+       if (*n_indices > 0)
+               *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
+       else
+               *index_rels = NULL;
 
-       while (HeapTupleIsValid(tuple = heap_getnext(scandesc, 0)))
+       i = 0;
+       foreach(indexoidscan, indexoidlist)
        {
+               Oid                     indexoid = lfirsti(indexoidscan);
+               Relation        index = index_open(indexoid);
 
-               index_relation_oid = (Oid) DatumGetInt32(heap_getattr(tuple, 2,
-                                                                                                         tupDesc, &isnull));
-               if (index_relation_oid == main_relation_oid)
-               {
-                       scan->index_rel_oid = (Oid) DatumGetInt32(heap_getattr(tuple,
-                                                                                               Anum_pg_index_indexrelid,
-                                                                                                         tupDesc, &isnull));
-                       (*n_indices)++;
-                       scan->next = (RelationList *) palloc(sizeof(RelationList));
-                       scan = scan->next;
-               }
-       }
-
-       heap_endscan(scandesc);
-       heap_close(pg_index_rel, AccessShareLock);
-
-       /* We cannot trust to relhasindex of the main_relation now, so... */
-       if (*n_indices == 0)
-               return;
-
-       *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
-
-       for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next)
-       {
-               (*index_rels)[i] = index_open(scan->index_rel_oid);
                /* see comments in ExecOpenIndices() in execUtils.c */
-               if ((*index_rels)[i] != NULL &&
-                       ((*index_rels)[i])->rd_rel->relam != BTREE_AM_OID &&
-                       ((*index_rels)[i])->rd_rel->relam != HASH_AM_OID)
-                       LockRelation((*index_rels)[i], AccessExclusiveLock);
+               if (index != NULL &&
+                       index->rd_rel->relam != BTREE_AM_OID &&
+                       index->rd_rel->relam != HASH_AM_OID)
+                       LockRelation(index, AccessExclusiveLock);
+               (*index_rels)[i] = index;
+               i++;
        }
 
-       for (i = 0, scan = head; i < *n_indices + 1; i++)
-       {
-               scan = head->next;
-               pfree(head);
-               head = scan;
-       }
+       freeList(indexoidlist);
+       heap_close(relation, AccessShareLock);
 }
 
 /*
index 31c96c7d6ab0b6dcec4f1bfde3976c9fa98f8008..f0d61aa112319f408f728c915118658097c24d62 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.29 2000/06/15 03:32:07 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.30 2000/06/17 21:48:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -221,6 +221,13 @@ DefineIndex(char *heapRelationName,
                                         lossy, unique, primary);
        }
 
+       /*
+        * We update the relation's pg_class tuple even if it already has
+        * relhasindex = true.  This is needed to cause a shared-cache-inval
+        * message to be sent for the pg_class tuple, which will cause other
+        * backends to flush their relcache entries and in particular their
+        * cached lists of the indexes for this relation.
+        */
        setRelhasindexInplace(relationId, true, false);
 }
 
index 1ee4e28f21096fdc288115fd819a5c9b0767cffb..5eed27387a72d220b530c6ef34a231a125ecd8ac 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.159 2000/05/29 17:40:43 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.160 2000/06/17 21:48:43 tgl Exp $
  *
 
  *-------------------------------------------------------------------------
@@ -72,7 +72,7 @@ static void update_relstats(Oid relid, int num_pages, int num_tuples, bool hasin
 static VacPage tid_reaped(ItemPointer itemptr, VacPageList vacpagelist);
 static void reap_page(VacPageList vacpagelist, VacPage vacpage);
 static void vpage_insert(VacPageList vacpagelist, VacPage vpnew);
-static void get_indices(Oid relid, int *nindices, Relation **Irel);
+static void get_indices(Relation relation, int *nindices, Relation **Irel);
 static void close_indices(int nindices, Relation *Irel);
 static void get_index_desc(Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc);
 static void *vac_find_eq(void *bot, int nelem, int size, void *elm,
@@ -416,7 +416,7 @@ vacuum_rel(Oid relid, bool analyze)
        /* Now open indices */
        nindices = 0;
        Irel = (Relation *) NULL;
-       get_indices(vacrelstats->relid, &nindices, &Irel);
+       get_indices(onerel, &nindices, &Irel);
        if (!Irel)
                reindex = false;
        else if (!RelationGetForm(onerel)->relhasindex)
@@ -2331,80 +2331,33 @@ CommonSpecialPortalIsOpen(void)
        return CommonSpecialPortalInUse;
 }
 
+
 static void
-get_indices(Oid relid, int *nindices, Relation **Irel)
+get_indices(Relation relation, int *nindices, Relation **Irel)
 {
-       Relation        pgindex;
-       Relation        irel;
-       TupleDesc       tupdesc;
-       HeapTuple       tuple;
-       HeapScanDesc scan;
-       Datum           d;
-       int                     i,
-                               k;
-       bool            n;
-       ScanKeyData key;
-       Oid                *ioid;
-
-       *nindices = i = 0;
-
-       ioid = (Oid *) palloc(10 * sizeof(Oid));
-
-       /* prepare a heap scan on the pg_index relation */
-       pgindex = heap_openr(IndexRelationName, AccessShareLock);
-       tupdesc = RelationGetDescr(pgindex);
-
-       ScanKeyEntryInitialize(&key, 0x0, Anum_pg_index_indrelid,
-                                                  F_OIDEQ,
-                                                  ObjectIdGetDatum(relid));
-
-       scan = heap_beginscan(pgindex, false, SnapshotNow, 1, &key);
-
-       while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
-       {
-               d = heap_getattr(tuple, Anum_pg_index_indexrelid,
-                                                tupdesc, &n);
-               i++;
-               if (i % 10 == 0)
-                       ioid = (Oid *) repalloc(ioid, (i + 10) * sizeof(Oid));
-               ioid[i - 1] = DatumGetObjectId(d);
-       }
+       List       *indexoidlist,
+                          *indexoidscan;
+       int                     i;
 
-       heap_endscan(scan);
-       heap_close(pgindex, AccessShareLock);
+       indexoidlist = RelationGetIndexList(relation);
 
-       if (i == 0)
-       {                                                       /* No one index found */
-               pfree(ioid);
-               return;
-       }
+       *nindices = length(indexoidlist);
 
-       if (Irel != (Relation **) NULL)
-               *Irel = (Relation *) palloc(i * sizeof(Relation));
+       if (*nindices > 0)
+               *Irel = (Relation *) palloc(*nindices * sizeof(Relation));
+       else
+               *Irel = NULL;
 
-       for (k = 0; i > 0;)
+       i = 0;
+       foreach(indexoidscan, indexoidlist)
        {
-               irel = index_open(ioid[--i]);
-               if (irel != (Relation) NULL)
-               {
-                       if (Irel != (Relation **) NULL)
-                               (*Irel)[k] = irel;
-                       else
-                               index_close(irel);
-                       k++;
-               }
-               else
-                       elog(NOTICE, "CAN'T OPEN INDEX %u - SKIP IT", ioid[i]);
-       }
-       *nindices = k;
-       pfree(ioid);
+               Oid                     indexoid = lfirsti(indexoidscan);
 
-       if (Irel != (Relation **) NULL && *nindices == 0)
-       {
-               pfree(*Irel);
-               *Irel = (Relation *) NULL;
+               (*Irel)[i] = index_open(indexoid);
+               i++;
        }
 
+       freeList(indexoidlist);
 }
 
 
index 8fbb4be6cb0dc3991121babad1034af200b5b9ff..f80fe9abab719bdb7227b10f4d125b7ee7622882 100644 (file)
@@ -27,7 +27,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.117 2000/06/15 04:09:50 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.118 2000/06/17 21:48:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -735,7 +735,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
                 */
                if (resultRelationDesc->rd_rel->relhasindex &&
                        operation != CMD_DELETE)
-                       ExecOpenIndices(resultRelationOid, resultRelationInfo);
+                       ExecOpenIndices(resultRelationInfo);
 
                estate->es_result_relation_info = resultRelationInfo;
        }
index 852ff5872ce0fe9cd260f2fc8d41033a7a1a16f8..c1b6e5d79a38a2393e2f2b8598782be65e421ea7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.59 2000/06/15 04:09:52 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.60 2000/06/17 21:48:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,8 @@
 #include "miscadmin.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/relcache.h"
+#include "utils/syscache.h"
 
 static void ExecGetIndexKeyInfo(Form_pg_index indexTuple, int *numAttsOutP,
                                        AttrNumber **attsOutP, FuncIndexInfoPtr fInfoP);
@@ -657,7 +659,7 @@ ExecGetIndexKeyInfo(Form_pg_index indexTuple,
         *      check parameters
         * ----------------
         */
-       if (numAttsOutP == NULL && attsOutP == NULL)
+       if (numAttsOutP == NULL || attsOutP == NULL)
        {
                elog(DEBUG, "ExecGetIndexKeyInfo: %s",
                "invalid parameters: numAttsOutP and attsOutP must be non-NULL");
@@ -724,115 +726,112 @@ ExecGetIndexKeyInfo(Form_pg_index indexTuple,
 /* ----------------------------------------------------------------
  *             ExecOpenIndices
  *
- *             Here we scan the pg_index relation to find indices
- *             associated with a given heap relation oid.      Since we
- *             don't know in advance how many indices we have, we
- *             form lists containing the information we need from
- *             pg_index and then process these lists.
+ *             Find the indices associated with a result relation, open them,
+ *             and save information about them in the result RelationInfo.
  *
- *             Note: much of this code duplicates effort done by
- *             the IndexCatalogInformation function in plancat.c
- *             because IndexCatalogInformation is poorly written.
+ *             At entry, caller has already opened and locked
+ *             resultRelationInfo->ri_RelationDesc.
  *
- *             It would be much better if the functionality provided
- *             by this function and IndexCatalogInformation was
- *             in the form of a small set of orthogonal routines..
- *             If you are trying to understand this, I suggest you
- *             look at the code to IndexCatalogInformation and
- *             FormIndexTuple.. -cim 9/27/89
+ *             This used to be horribly ugly code, and slow too because it
+ *             did a sequential scan of pg_index.  Now we rely on the relcache
+ *             to cache a list of the OIDs of the indices associated with any
+ *             specific relation, and we use the pg_index syscache to get the
+ *             entries we need from pg_index.
  * ----------------------------------------------------------------
  */
 void
-ExecOpenIndices(Oid resultRelationOid,
-                               RelationInfo *resultRelationInfo)
+ExecOpenIndices(RelationInfo *resultRelationInfo)
 {
-       Relation        indexRd;
-       HeapScanDesc indexSd;
-       ScanKeyData key;
-       HeapTuple       tuple;
-       Form_pg_index indexStruct;
-       Oid                     indexOid;
-       List       *oidList;
-       List       *nkeyList;
-       List       *keyList;
-       List       *fiList;
-       char       *predString;
-       List       *predList;
-       List       *indexoid;
-       List       *numkeys;
-       List       *indexkeys;
-       List       *indexfuncs;
-       List       *indexpreds;
-       int                     len;
-
+       Relation        resultRelation = resultRelationInfo->ri_RelationDesc;
+       List       *indexoidlist,
+                          *indexoidscan;
+       int                     len,
+                               i;
        RelationPtr relationDescs;
        IndexInfo **indexInfoArray;
-       FuncIndexInfoPtr fInfoP;
-       int                     numKeyAtts;
-       AttrNumber *indexKeyAtts;
-       PredInfo   *predicate;
-       int                     i;
 
        resultRelationInfo->ri_NumIndices = 0;
-       if (!RelationGetForm(resultRelationInfo->ri_RelationDesc)->relhasindex)
+
+       /* checks for disabled indexes */
+       if (! RelationGetForm(resultRelation)->relhasindex)
                return;
        if (IsIgnoringSystemIndexes() &&
-               IsSystemRelationName(RelationGetRelationName(resultRelationInfo->ri_RelationDesc)))
+               IsSystemRelationName(RelationGetRelationName(resultRelation)))
                return;
+
        /* ----------------
-        *      open pg_index
+        *       Get cached list of index OIDs
         * ----------------
         */
-       indexRd = heap_openr(IndexRelationName, AccessShareLock);
+       indexoidlist = RelationGetIndexList(resultRelation);
+       len = length(indexoidlist);
+       if (len == 0)
+               return;
 
        /* ----------------
-        *      form a scan key
+        *       allocate space for result arrays
         * ----------------
         */
-       ScanKeyEntryInitialize(&key, 0, Anum_pg_index_indrelid,
-                                                  F_OIDEQ,
-                                                  ObjectIdGetDatum(resultRelationOid));
+       relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
+       indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));
+
+       resultRelationInfo->ri_NumIndices = len;
+       resultRelationInfo->ri_IndexRelationDescs = relationDescs;
+       resultRelationInfo->ri_IndexRelationInfo = indexInfoArray;
 
        /* ----------------
-        *      scan the index relation, looking for indices for our
-        *      result relation..
+        *       For each index, open the index relation and save pg_index info.
         * ----------------
         */
-       indexSd = heap_beginscan(indexRd,       /* scan desc */
-                                                        false,         /* scan backward flag */
-                                                        SnapshotNow,           /* NOW snapshot */
-                                                        1, /* number scan keys */
-                                                        &key);         /* scan keys */
-
-       oidList = NIL;
-       nkeyList = NIL;
-       keyList = NIL;
-       fiList = NIL;
-       predList = NIL;
-
-       while (HeapTupleIsValid(tuple = heap_getnext(indexSd, 0)))
+       i = 0;
+       foreach(indexoidscan, indexoidlist)
        {
+               Oid                     indexOid = lfirsti(indexoidscan);
+               Relation        indexDesc;
+               HeapTuple       indexTuple;
+               Form_pg_index indexStruct;
+               int                     numKeyAtts;
+               AttrNumber *indexKeyAtts;
+               FuncIndexInfoPtr fInfoP;
+               PredInfo   *predicate;
+               IndexInfo  *ii;
 
                /* ----------------
-                *      For each index relation we find, extract the information
-                *      we need and store it in a list..
+                * Open (and lock, if necessary) the index relation
                 *
-                *      first get the oid of the index relation from the tuple
+                * Hack for not btree and hash indices: they use relation
+                * level exclusive locking on update (i.e. - they are not
+                * ready for MVCC) and so we have to exclusively lock
+                * indices here to prevent deadlocks if we will scan them
+                * - index_beginscan places AccessShareLock, indices
+                * update methods don't use locks at all. We release this
+                * lock in ExecCloseIndices. Note, that hashes use page
+                * level locking - i.e. are not deadlock-free, - let's
+                * them be on their way -:)) vadim 03-12-1998
                 * ----------------
                 */
-               indexStruct = (Form_pg_index) GETSTRUCT(tuple);
-               indexOid = indexStruct->indexrelid;
+               indexDesc = index_open(indexOid);
+
+               if (indexDesc->rd_rel->relam != BTREE_AM_OID &&
+                       indexDesc->rd_rel->relam != HASH_AM_OID)
+                       LockRelation(indexDesc, AccessExclusiveLock);
 
                /* ----------------
-                * allocate space for functional index information.
+                *      Get the pg_index tuple for the index
                 * ----------------
                 */
-               fInfoP = (FuncIndexInfoPtr) palloc(sizeof(*fInfoP));
+               indexTuple = SearchSysCacheTupleCopy(INDEXRELID,
+                                                                                        ObjectIdGetDatum(indexOid),
+                                                                                        0, 0, 0);
+               if (!HeapTupleIsValid(indexTuple))
+                       elog(ERROR, "ExecOpenIndices: index %u not found", indexOid);
+               indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
 
                /* ----------------
-                *      next get the index key information from the tuple
+                *      extract the index key information from the tuple
                 * ----------------
                 */
+               fInfoP = (FuncIndexInfoPtr) palloc(sizeof(*fInfoP));
                ExecGetIndexKeyInfo(indexStruct,
                                                        &numKeyAtts,
                                                        &indexKeyAtts,
@@ -844,6 +843,8 @@ ExecOpenIndices(Oid resultRelationOid,
                 */
                if (VARSIZE(&indexStruct->indpred) != 0)
                {
+                       char       *predString;
+
                        predString = textout(&indexStruct->indpred);
                        predicate = (PredInfo *) stringToNode(predString);
                        pfree(predString);
@@ -851,152 +852,21 @@ ExecOpenIndices(Oid resultRelationOid,
                else
                        predicate = NULL;
 
-               /* ----------------
-                *      save the index information into lists
-                * ----------------
-                */
-               oidList = lconsi(indexOid, oidList);
-               nkeyList = lconsi(numKeyAtts, nkeyList);
-               keyList = lcons(indexKeyAtts, keyList);
-               fiList = lcons(fInfoP, fiList);
-               predList = lcons(predicate, predList);
-       }
-
-       /* ----------------
-        *      we have the info we need so close the pg_index relation..
-        * ----------------
-        */
-       heap_endscan(indexSd);
-       heap_close(indexRd, AccessShareLock);
-
-       /* ----------------
-        *      Now that we've collected the index information into three
-        *      lists, we open the index relations and store the descriptors
-        *      and the key information into arrays.
-        * ----------------
-        */
-       len = length(oidList);
-       if (len > 0)
-       {
-               /* ----------------
-                *       allocate space for relation descs
-                * ----------------
-                */
-               CXT1_printf("ExecOpenIndices: context is %d\n", CurrentMemoryContext);
-               relationDescs = (RelationPtr)
-                       palloc(len * sizeof(Relation));
-
-               /* ----------------
-                *       initialize index info array
-                * ----------------
-                */
-               CXT1_printf("ExecOpenIndices: context is %d\n", CurrentMemoryContext);
-               indexInfoArray = (IndexInfo **)
-                       palloc(len * sizeof(IndexInfo *));
-
-               for (i = 0; i < len; i++)
-               {
-                       IndexInfo  *ii = makeNode(IndexInfo);
+               /* Save the index info */
+               ii = makeNode(IndexInfo);
+               ii->ii_NumKeyAttributes = numKeyAtts;
+               ii->ii_KeyAttributeNumbers = indexKeyAtts;
+               ii->ii_FuncIndexInfo = fInfoP;
+               ii->ii_Predicate = (Node *) predicate;
 
-                       ii->ii_NumKeyAttributes = 0;
-                       ii->ii_KeyAttributeNumbers = (AttrNumber *) NULL;
-                       ii->ii_FuncIndexInfo = (FuncIndexInfoPtr) NULL;
-                       ii->ii_Predicate = NULL;
-                       indexInfoArray[i] = ii;
-               }
+               heap_freetuple(indexTuple);
 
-               /* ----------------
-                *       attempt to open each of the indices.  If we succeed,
-                *       then store the index relation descriptor into the
-                *       relation descriptor array.
-                * ----------------
-                */
-               i = 0;
-               foreach(indexoid, oidList)
-               {
-                       Relation        indexDesc;
-
-                       indexOid = lfirsti(indexoid);
-                       indexDesc = index_open(indexOid);
-                       if (indexDesc != NULL)
-                       {
-                               relationDescs[i++] = indexDesc;
-
-                               /*
-                                * Hack for not btree and hash indices: they use relation
-                                * level exclusive locking on update (i.e. - they are not
-                                * ready for MVCC) and so we have to exclusively lock
-                                * indices here to prevent deadlocks if we will scan them
-                                * - index_beginscan places AccessShareLock, indices
-                                * update methods don't use locks at all. We release this
-                                * lock in ExecCloseIndices. Note, that hashes use page
-                                * level locking - i.e. are not deadlock-free, - let's
-                                * them be on their way -:)) vadim 03-12-1998
-                                */
-                               if (indexDesc->rd_rel->relam != BTREE_AM_OID &&
-                                       indexDesc->rd_rel->relam != HASH_AM_OID)
-                                       LockRelation(indexDesc, AccessExclusiveLock);
-                       }
-               }
-
-               /* ----------------
-                *       store the relation descriptor array and number of
-                *       descs into the result relation info.
-                * ----------------
-                */
-               resultRelationInfo->ri_NumIndices = i;
-               resultRelationInfo->ri_IndexRelationDescs = relationDescs;
-
-               /* ----------------
-                *       store the index key information collected in our
-                *       lists into the index info array
-                * ----------------
-                */
-               i = 0;
-               foreach(numkeys, nkeyList)
-               {
-                       numKeyAtts = lfirsti(numkeys);
-                       indexInfoArray[i++]->ii_NumKeyAttributes = numKeyAtts;
-               }
-
-               i = 0;
-               foreach(indexkeys, keyList)
-               {
-                       indexKeyAtts = (AttrNumber *) lfirst(indexkeys);
-                       indexInfoArray[i++]->ii_KeyAttributeNumbers = indexKeyAtts;
-               }
-
-               i = 0;
-               foreach(indexfuncs, fiList)
-               {
-                       FuncIndexInfoPtr fiP = (FuncIndexInfoPtr) lfirst(indexfuncs);
-
-                       indexInfoArray[i++]->ii_FuncIndexInfo = fiP;
-               }
-
-               i = 0;
-               foreach(indexpreds, predList)
-                       indexInfoArray[i++]->ii_Predicate = lfirst(indexpreds);
-               /* ----------------
-                *       store the index info array into relation info
-                * ----------------
-                */
-               resultRelationInfo->ri_IndexRelationInfo = indexInfoArray;
+               relationDescs[i] = indexDesc;
+               indexInfoArray[i] = ii;
+               i++;
        }
 
-       /* ----------------
-        *      All done,  resultRelationInfo now contains complete information
-        *      on the indices associated with the result relation.
-        * ----------------
-        */
-
-       /* should free oidList, nkeyList and keyList here */
-       /* OK - let's do it   -jolly */
-       freeList(oidList);
-       freeList(nkeyList);
-       freeList(keyList);
-       freeList(fiList);
-       freeList(predList);
+       freeList(indexoidlist);
 }
 
 /* ----------------------------------------------------------------
@@ -1035,91 +905,6 @@ ExecCloseIndices(RelationInfo *resultRelationInfo)
         */
 }
 
-/* ----------------------------------------------------------------
- *             ExecFormIndexTuple
- *
- *             Most of this code is cannabilized from DefaultBuild().
- *             As said in the comments for ExecOpenIndices, most of
- *             this functionality should be rearranged into a proper
- *             set of routines..
- * ----------------------------------------------------------------
- */
-#ifdef NOT_USED
-IndexTuple
-ExecFormIndexTuple(HeapTuple heapTuple,
-                                  Relation heapRelation,
-                                  Relation indexRelation,
-                                  IndexInfo *indexInfo)
-{
-       IndexTuple      indexTuple;
-       TupleDesc       heapDescriptor;
-       TupleDesc       indexDescriptor;
-       Datum      *datum;
-       char       *nulls;
-
-       int                     numberOfAttributes;
-       AttrNumber *keyAttributeNumbers;
-       FuncIndexInfoPtr fInfoP;
-
-       /* ----------------
-        *      get information from index info structure
-        * ----------------
-        */
-       numberOfAttributes = indexInfo->ii_NumKeyAttributes;
-       keyAttributeNumbers = indexInfo->ii_KeyAttributeNumbers;
-       fInfoP = indexInfo->ii_FuncIndexInfo;
-
-       /* ----------------
-        *      datum and null are arrays in which we collect the index attributes
-        *      when forming a new index tuple.
-        * ----------------
-        */
-       CXT1_printf("ExecFormIndexTuple: context is %d\n", CurrentMemoryContext);
-       datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
-       nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
-
-       /* ----------------
-        *      get the tuple descriptors from the relations so we know
-        *      how to form the index tuples..
-        * ----------------
-        */
-       heapDescriptor = RelationGetDescr(heapRelation);
-       indexDescriptor = RelationGetDescr(indexRelation);
-
-       /* ----------------
-        *      FormIndexDatum fills in its datum and null parameters
-        *      with attribute information taken from the given heap tuple.
-        * ----------------
-        */
-       FormIndexDatum(numberOfAttributes,      /* num attributes */
-                                  keyAttributeNumbers, /* array of att nums to extract */
-                                  heapTuple,   /* tuple from base relation */
-                                  heapDescriptor,              /* heap tuple's descriptor */
-                                  datum,               /* return: array of attributes */
-                                  nulls,               /* return: array of char's */
-                                  fInfoP);             /* functional index information */
-
-       indexTuple = index_formtuple(indexDescriptor,
-                                                                datum,
-                                                                nulls);
-
-       /* ----------------
-        *      free temporary arrays
-        *
-        *      XXX should store these in the IndexInfo instead of allocating
-        *         and freeing on every insertion, but efficency here is not
-        *         that important and FormIndexTuple is wasteful anyways..
-        *         -cim 9/27/89
-        * ----------------
-        */
-       pfree(nulls);
-       pfree(datum);
-
-       return indexTuple;
-}
-
-#endif
-
 /* ----------------------------------------------------------------
  *             ExecInsertIndexTuples
  *
index 51e7d4027e6242c78df59bf8794dc0037a2909a4..5e34e806e32d3d43abc66118c1dca8beba2978e1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.33 2000/06/15 04:09:52 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.34 2000/06/17 21:48:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -285,7 +285,7 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
                                 * indices, but how to tell that here?
                                 */
                                if (rri->ri_RelationDesc->rd_rel->relhasindex)
-                                       ExecOpenIndices(reloid, rri);
+                                       ExecOpenIndices(rri);
                        }
 
                        /*
index 12b2f26bd845448b1da78bb81e8ca9fd7eda5f24..64b47072f71a07d2c4d802cd872672551a6e437f 100644 (file)
@@ -9,11 +9,7 @@
  *
  *
  * IDENTIFICATION
-<<<<<<< plancat.c
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.56 2000/06/15 03:32:16 momjian Exp $
-=======
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.56 2000/06/15 03:32:16 momjian Exp $
->>>>>>> 1.53
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.57 2000/06/17 21:48:51 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,6 +28,7 @@
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/relcache.h"
 #include "utils/syscache.h"
 #include "catalog/catalog.h"
 #include "miscadmin.h"
@@ -54,7 +51,7 @@ relation_info(Query *root, Index relid,
        Form_pg_class relation;
 
        relationTuple = SearchSysCacheTuple(RELOID,
-                                                                         ObjectIdGetDatum(relationObjectId),
+                                                                               ObjectIdGetDatum(relationObjectId),
                                                                                0, 0, 0);
        if (!HeapTupleIsValid(relationTuple))
                elog(ERROR, "relation_info: Relation %u not found",
@@ -81,33 +78,40 @@ relation_info(Query *root, Index relid,
 List *
 find_secondary_indexes(Query *root, Index relid)
 {
-       List       *indexes = NIL;
+       List       *indexinfos = NIL;
+       List       *indexoidlist,
+                          *indexoidscan;
        Oid                     indrelid = getrelid(relid, root->rtable);
        Relation        relation;
-       HeapScanDesc scan;
-       ScanKeyData indexKey;
-       HeapTuple       indexTuple;
-
-       /* Scan pg_index for tuples describing indexes of this rel */
-       relation = heap_openr(IndexRelationName, AccessShareLock);
 
-       ScanKeyEntryInitialize(&indexKey, 0,
-                                                  Anum_pg_index_indrelid,
-                                                  F_OIDEQ,
-                                                  ObjectIdGetDatum(indrelid));
+       /*
+        * We used to scan pg_index directly, but now the relcache offers
+        * a cached list of OID indexes for each relation.  So, get that list
+        * and then use the syscache to obtain pg_index entries.
+        */
+       relation = heap_open(indrelid, AccessShareLock);
+       indexoidlist = RelationGetIndexList(relation);
 
-       scan = heap_beginscan(relation, 0, SnapshotNow,
-                                                 1, &indexKey);
-
-       while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
+       foreach(indexoidscan, indexoidlist)
        {
-               Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
-               IndexOptInfo *info = makeNode(IndexOptInfo);
+               Oid             indexoid = lfirsti(indexoidscan);
+               HeapTuple       indexTuple;
+               Form_pg_index index;
+               IndexOptInfo *info;
                int                     i;
                Relation        indexRelation;
                Oid                     relam;
                uint16          amorderstrategy;
 
+               indexTuple = SearchSysCacheTupleCopy(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);
+               info = makeNode(IndexOptInfo);
+
                /*
                 * Need to make these arrays large enough to be sure there is a
                 * terminating 0 at the end of each one.
@@ -172,13 +176,17 @@ find_secondary_indexes(Query *root, Index relid)
                        }
                }
 
-               indexes = lcons(info, indexes);
+               heap_freetuple(indexTuple);
+
+               indexinfos = lcons(info, indexinfos);
        }
 
-       heap_endscan(scan);
+       freeList(indexoidlist);
+
+       /* XXX keep the lock here? */
        heap_close(relation, AccessShareLock);
 
-       return indexes;
+       return indexinfos;
 }
 
 /*
index dbd8faf319b60b05ac067cce55275578f466cab6..8e23170ac8a9ae3b1412dc6605fa7532e283991b 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Id: analyze.c,v 1.147 2000/06/12 19:40:40 momjian Exp $
+ *     $Id: analyze.c,v 1.148 2000/06/17 21:48:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,6 +27,8 @@
 #include "parser/parse_type.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/relcache.h"
+#include "utils/syscache.h"
 
 void           CheckSelectForUpdate(Query *qry);       /* no points for style... */
 
@@ -2003,13 +2005,9 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
 {
        Relation        pkrel;
        Form_pg_attribute *pkrel_attrs;
-       Relation        indexRd;
-       HeapScanDesc indexSd;
-       ScanKeyData key;
-       HeapTuple       indexTup;
+       List       *indexoidlist,
+                          *indexoidscan;
        Form_pg_index indexStruct = NULL;
-       Ident      *pkattr;
-       int                     pkattno;
        int                     i;
 
        /* ----------
@@ -2023,37 +2021,37 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
        pkrel_attrs = pkrel->rd_att->attrs;
 
        /* ----------
-        * Open pg_index and begin a scan for all indices defined on
-        * the referenced table
+        * Get the list of index OIDs for the table from the relcache,
+        * and look up each one in the pg_index syscache until we find one
+        * marked primary key (hopefully there isn't more than one such).
         * ----------
         */
-       indexRd = heap_openr(IndexRelationName, AccessShareLock);
-       ScanKeyEntryInitialize(&key, 0, Anum_pg_index_indrelid,
-                                                  F_OIDEQ,
-                                                  ObjectIdGetDatum(pkrel->rd_id));
-       indexSd = heap_beginscan(indexRd,       /* scan desc */
-                                                        false,         /* scan backward flag */
-                                                        SnapshotNow,           /* NOW snapshot */
-                                                        1, /* number scan keys */
-                                                        &key);         /* scan keys */
+       indexoidlist = RelationGetIndexList(pkrel);
 
-       /* ----------
-        * Fetch the index with indisprimary == true
-        * ----------
-        */
-       while (HeapTupleIsValid(indexTup = heap_getnext(indexSd, 0)))
+       foreach(indexoidscan, indexoidlist)
        {
-               indexStruct = (Form_pg_index) GETSTRUCT(indexTup);
-
+               Oid             indexoid = lfirsti(indexoidscan);
+               HeapTuple       indexTuple;
+
+               indexTuple = SearchSysCacheTuple(INDEXRELID,
+                                                                                ObjectIdGetDatum(indexoid),
+                                                                                0, 0, 0);
+               if (!HeapTupleIsValid(indexTuple))
+                       elog(ERROR, "transformFkeyGetPrimaryKey: index %u not found",
+                                indexoid);
+               indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
                if (indexStruct->indisprimary)
                        break;
+               indexStruct = NULL;
        }
 
+       freeList(indexoidlist);
+
        /* ----------
         * Check that we found it
         * ----------
         */
-       if (!HeapTupleIsValid(indexTup))
+       if (indexStruct == NULL)
                elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
                         fkconstraint->pktable_name);
 
@@ -2064,8 +2062,9 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
         */
        for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
        {
-               pkattno = indexStruct->indkey[i];
-               pkattr = (Ident *) makeNode(Ident);
+               int                     pkattno = indexStruct->indkey[i];
+               Ident      *pkattr = makeNode(Ident);
+
                pkattr->name = nameout(&(pkrel_attrs[pkattno - 1]->attname));
                pkattr->indirection = NIL;
                pkattr->isRel = false;
@@ -2073,12 +2072,6 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
                fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs, pkattr);
        }
 
-       /* ----------
-        * End index scan and close relations
-        * ----------
-        */
-       heap_endscan(indexSd);
-       heap_close(indexRd, AccessShareLock);
        heap_close(pkrel, AccessShareLock);
 }
 
index f86f4eef778f6b659a127289015ed23b072b6857..4fe3e35b1e86dc5f635284b09b41c1f2a236039d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.100 2000/06/17 04:56:32 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.101 2000/06/17 21:48:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,6 +46,7 @@
 #include "catalog/index.h"
 #include "catalog/indexing.h"
 #include "catalog/pg_attrdef.h"
+#include "catalog/pg_index.h"
 #include "catalog/pg_log.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_relcheck.h"
@@ -1063,16 +1064,14 @@ formrdesc(char *relationName,
                  FormData_pg_attribute *att)
 {
        Relation        relation;
-       Size            len;
        u_int           i;
 
        /* ----------------
         *      allocate new relation desc
         * ----------------
         */
-       len = sizeof(RelationData);
-       relation = (Relation) palloc(len);
-       MemSet((char *) relation, 0, len);
+       relation = (Relation) palloc(sizeof(RelationData));
+       MemSet((char *) relation, 0, sizeof(RelationData));
 
        /* ----------------
         *      don't open the unix file yet..
@@ -1090,9 +1089,8 @@ formrdesc(char *relationName,
         *      initialize relation tuple form
         * ----------------
         */
-       relation->rd_rel = (Form_pg_class)
-               palloc((Size) (sizeof(*relation->rd_rel)));
-       MemSet(relation->rd_rel, 0, sizeof(FormData_pg_class));
+       relation->rd_rel = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
+       MemSet(relation->rd_rel, 0, CLASS_TUPLE_SIZE);
        strcpy(RelationGetPhysicalRelationName(relation), relationName);
 
        /* ----------------
@@ -1414,6 +1412,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
                pfree(relation->rd_istrat);
        if (relation->rd_support)
                pfree(relation->rd_support);
+       freeList(relation->rd_indexlist);
 
        /*
         * If we're really done with the relcache entry, blow it away. But if
@@ -2075,6 +2074,125 @@ RelCheckFetch(Relation relation)
        heap_close(rcrel, AccessShareLock);
 }
 
+/*
+ * RelationGetIndexList -- get a list of OIDs of indexes on this relation
+ *
+ * The index list is created only if someone requests it.  We scan pg_index
+ * to find relevant indexes, and add the list to the relcache entry so that
+ * we won't have to compute it again.  Note that shared cache inval of a
+ * relcache entry will delete the old list and set rd_indexfound to false,
+ * so that we must recompute the index list on next request.  This handles
+ * creation or deletion of an index.
+ *
+ * Since shared cache inval causes the relcache's copy of the list to go away,
+ * we return a copy of the list palloc'd in the caller's context.  The caller
+ * may freeList() the returned list after scanning it.  This is necessary
+ * since the caller will typically be doing syscache lookups on the relevant
+ * indexes, and syscache lookup could cause SI messages to be processed!
+ */
+List *
+RelationGetIndexList(Relation relation)
+{
+       Relation        indrel;
+       Relation        irel = (Relation) NULL;
+       ScanKeyData skey;
+       IndexScanDesc sd = (IndexScanDesc) NULL;
+       HeapScanDesc hscan = (HeapScanDesc) NULL;
+       bool            hasindex;
+       List       *result;
+       MemoryContext oldcxt;
+
+       /* Quick exit if we already computed the list. */
+       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 copy that
+        * list into the relcache entry.  This avoids cache-context memory leakage
+        * if we get some sort of error partway through.
+        */
+       result = NIL;
+       
+       for (;;)
+       {
+               HeapTupleData tuple;
+               HeapTuple       htup;
+               Buffer          buffer;
+               Form_pg_index index;
+
+               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);
+                       pfree(indexRes);
+                       if (tuple.t_data == NULL)
+                               continue;
+                       htup = &tuple;
+               }
+               else
+               {
+                       htup = heap_getnext(hscan, 0);
+                       if (!HeapTupleIsValid(htup))
+                               break;
+               }
+
+               index = (Form_pg_index) GETSTRUCT(htup);
+
+               result = lappendi(result, index->indexrelid);
+
+               if (hasindex)
+                       ReleaseBuffer(buffer);
+       }
+
+       if (hasindex)
+       {
+               index_endscan(sd);
+               index_close(irel);
+       }
+       else
+               heap_endscan(hscan);
+       heap_close(indrel, AccessShareLock);
+
+       /* Now we can save the completed list in the relcache entry. */
+       oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+       relation->rd_indexlist = listCopy(result);
+       relation->rd_indexfound = true;
+       MemoryContextSwitchTo(oldcxt);
+
+       return result;
+}
+
 /*
  *     init_irels(), write_irels() -- handle special-case initialization of
  *                                                                index relation descriptors.
index 3c85762dfafadb12b1e1f2f0e2650165c4565efa..6d196eb5a2c7fef942211ca2a4eefcca440c7cda 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: executor.h,v 1.43 2000/05/29 01:59:11 tgl Exp $
+ * $Id: executor.h,v 1.44 2000/06/17 21:48:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -142,8 +142,7 @@ extern void ExecAssignScanTypeFromOuterPlan(Plan *node,
                                                                CommonScanState *csstate);
 extern Form_pg_attribute ExecGetTypeInfo(Relation relDesc);
 
-extern void ExecOpenIndices(Oid resultRelationOid,
-                               RelationInfo *resultRelationInfo);
+extern void ExecOpenIndices(RelationInfo *resultRelationInfo);
 extern void ExecCloseIndices(RelationInfo *resultRelationInfo);
 extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid,
                                          EState *estate, bool is_update);
index 1bd2f10376ea0a9ba53691876bb3747c755a6a38..2a585c0e7ea2b710e30ce39d65cb29efdc58f230 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: rel.h,v 1.36 2000/04/12 17:16:55 momjian Exp $
+ * $Id: rel.h,v 1.37 2000/06/17 21:49:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -92,14 +92,15 @@ typedef struct RelationData
        bool            rd_isnailed;    /* rel is nailed in cache */
        bool            rd_isnoname;    /* rel has no name */
        bool            rd_unlinked;    /* rel already unlinked or not created yet */
+       bool            rd_indexfound;  /* true if rd_indexlist is valid */
        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 for locking
-                                                                * relation */
+       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 */
-       IndexStrategy rd_istrat;
+       IndexStrategy rd_istrat;        /* info needed if rel is an index */
        RegProcedure *rd_support;
        TriggerDesc *trigdesc;          /* Trigger info, or NULL if rel has none */
 } RelationData;
@@ -138,13 +139,15 @@ typedef Relation *RelationPtr;
  * RelationSetReferenceCount
  *             Sets relation reference count.
  */
-#define RelationSetReferenceCount(relation,count) ((relation)->rd_refcnt = (count))
+#define RelationSetReferenceCount(relation,count) \
+       ((relation)->rd_refcnt = (count))
 
 /*
  * RelationIncrementReferenceCount
  *             Increments relation reference count.
  */
-#define RelationIncrementReferenceCount(relation) ((relation)->rd_refcnt += 1)
+#define RelationIncrementReferenceCount(relation) \
+       ((relation)->rd_refcnt += 1)
 
 /*
  * RelationDecrementReferenceCount
@@ -199,7 +202,8 @@ typedef Relation *RelationPtr;
  *
  *       Returns a Relation Name
  */
-#define RelationGetPhysicalRelationName(relation) (NameStr((relation)->rd_rel->relname))
+#define RelationGetPhysicalRelationName(relation) \
+       (NameStr((relation)->rd_rel->relname))
 
 /*
  * RelationGetNumberOfAttributes
@@ -224,9 +228,11 @@ typedef Relation *RelationPtr;
  */
 #define RelationGetIndexStrategy(relation) ((relation)->rd_istrat)
 
-
+/*
+ * Routines in utils/cache/rel.c
+ */
 extern void RelationSetIndexSupport(Relation relation,
-                                               IndexStrategy strategy,
-                                               RegProcedure *support);
+                                                                       IndexStrategy strategy,
+                                                                       RegProcedure *support);
 
 #endif  /* REL_H */
index 073c846e4b304ce46b61beac96b98bf7c05c1534..aee58942a64d26fbf7cc55b6108af3d4b2042063 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: relcache.h,v 1.19 2000/01/31 04:35:57 tgl Exp $
+ * $Id: relcache.h,v 1.20 2000/06/17 21:49:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * relation lookup routines
  */
-extern Relation RelationIdCacheGetRelation(Oid relationId);
 extern Relation RelationIdGetRelation(Oid relationId);
 extern Relation RelationNameGetRelation(const char *relationName);
 
+/* finds an existing cache entry, but won't make a new one */
+extern Relation RelationIdCacheGetRelation(Oid relationId);
+
 extern void RelationClose(Relation relation);
 extern void RelationForgetRelation(Oid rid);
 
+/*
+ * Routines to compute/retrieve additional cached information
+ */
+extern List *RelationGetIndexList(Relation relation);
+
 /*
  * Routines for flushing/rebuilding relcache entries in various scenarios
  */