Fix performance problems with pg_index lookups (see, for example,
authorTom Lane
Sat, 17 Jun 2000 21:49:04 +0000 (21:49 +0000)
committerTom Lane
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
  */