Combine index_info and find_secondary_indexes into a single routine that
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 21 Nov 1999 23:25:47 +0000 (23:25 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 21 Nov 1999 23:25:47 +0000 (23:25 +0000)
returns a list of RelOptInfos, eliminating the need for static state
in index_info.  That static state was a direct cause of coredumps; if
anything decided to elog(ERROR) partway through an index_info search of
pg_index, the next query would try to close a scan pointer that was
pointing at no-longer-valid memory.  Another example of the reasons to
avoid static state variables...

src/backend/optimizer/util/indexnode.c
src/backend/optimizer/util/plancat.c
src/include/optimizer/plancat.h

index 4817232f2fb2a96de065aac80cd0b2b026f2c1e5..350209690b706dd4ae7fde4b7d4cb75b138293bb 100644 (file)
@@ -7,21 +7,16 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/indexnode.c,v 1.20 1999/08/16 02:17:57 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/indexnode.c,v 1.21 1999/11/21 23:25:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-#include <sys/types.h>
-
 #include "postgres.h"
 
-
 #include "optimizer/pathnode.h"
 #include "optimizer/plancat.h"
 
 
-static List *find_secondary_index(Query *root, Oid relid);
-
 /*
  * find_relation_indices
  *   Returns a list of index nodes containing appropriate information for
@@ -32,56 +27,7 @@ List *
 find_relation_indices(Query *root, RelOptInfo *rel)
 {
    if (rel->indexed)
-       return find_secondary_index(root, lfirsti(rel->relids));
+       return find_secondary_indexes(root, lfirsti(rel->relids));
    else
        return NIL;
 }
-
-/*
- * find_secondary_index
- *   Creates a list of RelOptInfo nodes containing information for each
- *   secondary index defined on a relation by searching through the index
- *   catalog.
- *
- * 'relid' is the OID of the relation for which indices are being located
- *
- * Returns a list of new index RelOptInfo nodes.
- */
-static List *
-find_secondary_index(Query *root, Oid relid)
-{
-   IdxInfoRetval indexinfo;
-   List       *indexes = NIL;
-   bool        first = true;
-
-   while (index_info(root, first, relid, &indexinfo))
-   {
-       RelOptInfo *indexnode = makeNode(RelOptInfo);
-
-       indexnode->relids = lconsi(indexinfo.relid, NIL);
-       indexnode->relam = indexinfo.relam;
-       indexnode->pages = indexinfo.pages;
-       indexnode->tuples = indexinfo.tuples;
-       indexnode->classlist = indexinfo.classlist;
-       indexnode->indexkeys = indexinfo.indexkeys;
-       indexnode->ordering = indexinfo.orderOprs;
-       indexnode->indproc = indexinfo.indproc;
-       indexnode->indpred = (List *) indexinfo.indpred;
-
-       indexnode->indexed = false;     /* not indexed itself */
-       indexnode->size = 0;
-       indexnode->width = 0;
-       indexnode->targetlist = NIL;
-       indexnode->pathlist = NIL;
-       indexnode->cheapestpath = NULL;
-       indexnode->pruneable = true;
-       indexnode->restrictinfo = NIL;
-       indexnode->joininfo = NIL;
-       indexnode->innerjoin = NIL;
-
-       indexes = lcons(indexnode, indexes);
-       first = false;
-   }
-
-   return indexes;
-}
index ef120f8d2fe513df543ac5203102e955391ac782..b023c5451d0525d35dfb527a4aee81fab5133dd9 100644 (file)
@@ -8,13 +8,14 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.38 1999/09/18 19:07:06 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.39 1999/11/21 23:25:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include <math.h>
 
 #include "postgres.h"
+
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "catalog/catname.h"
@@ -38,8 +39,8 @@ static void IndexSelectivity(Oid indexrelid, Oid baserelid, int nIndexKeys,
 
 /*
  * relation_info -
- *   Retrieves catalog information for a given relation. Given the oid of
- *   the relation, return the following information:
+ *   Retrieves catalog information for a given relation.
+ *   Given the rangetable index of the relation, return the following info:
  *             whether the relation has secondary indices
  *             number of pages
  *             number of tuples
@@ -54,166 +55,141 @@ relation_info(Query *root, Index relid,
 
    relationObjectId = getrelid(relid, root->rtable);
    relationTuple = SearchSysCacheTuple(RELOID,
-                                     ObjectIdGetDatum(relationObjectId),
+                                       ObjectIdGetDatum(relationObjectId),
                                        0, 0, 0);
    if (HeapTupleIsValid(relationTuple))
    {
        relation = (Form_pg_class) GETSTRUCT(relationTuple);
 
-       *hasindex = (relation->relhasindex) ? TRUE : FALSE;
+       *hasindex = (relation->relhasindex) ? true : false;
        *pages = relation->relpages;
        *tuples = relation->reltuples;
    }
    else
    {
-       elog(ERROR, "RelationCatalogInformation: Relation %u not found",
+       elog(ERROR, "relation_info: Relation %u not found",
             relationObjectId);
    }
-
-   return;
 }
 
-
 /*
- * index_info
- *   Retrieves catalog information on an index on a given relation.
+ * find_secondary_indexes
+ *   Creates a list of RelOptInfo nodes containing information for each
+ *   secondary index defined on the given relation.
  *
- *   The index relation is opened on the first invocation. The current
- *   retrieves the next index relation within the catalog that has not
- *   already been retrieved by a previous call.  The index catalog
- *   is closed when no more indices for 'relid' can be found.
- *
- * 'first' is 1 if this is the first call
- *
- * Returns true if successful and false otherwise. Index info is returned
- * via the transient data structure 'info'.
+ * 'relid' is the RT index of the relation for which indices are being located
  *
+ * Returns a list of new index RelOptInfo nodes.
  */
-bool
-index_info(Query *root, bool first, int relid, IdxInfoRetval *info)
+List *
+find_secondary_indexes(Query *root, Index relid)
 {
-   int         i;
-   HeapTuple   indexTuple,
-               amopTuple;
-   Form_pg_index index;
-   Relation    indexRelation;
-   uint16      amstrategy;
-   Oid         relam;
-   Oid         indrelid;
-
-   static Relation relation = (Relation) NULL;
-   static HeapScanDesc scan = (HeapScanDesc) NULL;
-   static ScanKeyData indexKey;
+   List       *indexes = NIL;
+   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);
 
-   /* find the oid of the indexed relation */
-   indrelid = getrelid(relid, root->rtable);
+   ScanKeyEntryInitialize(&indexKey, 0,
+                          Anum_pg_index_indrelid,
+                          F_OIDEQ,
+                          ObjectIdGetDatum(indrelid));
 
-   MemSet(info, 0, sizeof(IdxInfoRetval));
+   scan = heap_beginscan(relation, 0, SnapshotNow,
+                         1, &indexKey);
 
-   /*
-    * the maximum number of elements in each of the following arrays is
-    * 8. We allocate one more for a terminating 0 to indicate the end of
-    * the array.
-    */
-   info->indexkeys = (int *) palloc(sizeof(int) * 9);
-   MemSet(info->indexkeys, 0, sizeof(int) * 9);
-   info->orderOprs = (Oid *) palloc(sizeof(Oid) * 9);
-   MemSet(info->orderOprs, 0, sizeof(Oid) * 9);
-   info->classlist = (Oid *) palloc(sizeof(Oid) * 9);
-   MemSet(info->classlist, 0, sizeof(Oid) * 9);
-
-   /* Find an index on the given relation */
-   if (first)
-   {
-       if (HeapScanIsValid(scan))
-           heap_endscan(scan);
-       scan = (HeapScanDesc) NULL;
-       if (RelationIsValid(relation))
-           heap_close(relation, AccessShareLock);
-       relation = (Relation) NULL;
-
-       ScanKeyEntryInitialize(&indexKey, 0,
-                              Anum_pg_index_indrelid,
-                              F_OIDEQ,
-                              ObjectIdGetDatum(indrelid));
-
-       relation = heap_openr(IndexRelationName, AccessShareLock);
-       scan = heap_beginscan(relation, 0, SnapshotNow,
-                             1, &indexKey);
-   }
-   if (!HeapScanIsValid(scan))
-       elog(ERROR, "index_info: scan not started");
-   indexTuple = heap_getnext(scan, 0);
-   if (!HeapTupleIsValid(indexTuple))
-   {
-       heap_endscan(scan);
-       heap_close(relation, AccessShareLock);
-       scan = (HeapScanDesc) NULL;
-       relation = (Relation) NULL;
-       return 0;
-   }
-
-   /* Extract info from the index tuple */
-   index = (Form_pg_index) GETSTRUCT(indexTuple);
-   info->relid = index->indexrelid;    /* index relation */
-   for (i = 0; i < INDEX_MAX_KEYS; i++)
-       info->indexkeys[i] = index->indkey[i];
-   for (i = 0; i < INDEX_MAX_KEYS; i++)
-       info->classlist[i] = index->indclass[i];
-
-   info->indproc = index->indproc;     /* functional index ?? */
-
-   /* partial index ?? */
-   if (VARSIZE(&index->indpred) != 0)
+   while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
    {
+       Form_pg_index   index = (Form_pg_index) GETSTRUCT(indexTuple);
+       RelOptInfo     *info = makeNode(RelOptInfo);
+       int             i;
+       Relation        indexRelation;
+       uint16          amstrategy;
+       Oid             relam;
 
        /*
-        * The memory allocated here for the predicate (in lispReadString)
-        * only needs to stay around until it's used in find_index_paths,
-        * which is all within a command, so the automatic pfree at end of
-        * transaction should be ok.
+        * Need to make these arrays large enough to be sure there is a
+        * terminating 0 at the end of each one.
         */
-       char       *predString;
+       info->classlist = (Oid *) palloc(sizeof(Oid) * (INDEX_MAX_KEYS+1));
+       info->indexkeys = (int *) palloc(sizeof(int) * (INDEX_MAX_KEYS+1));
+       info->ordering = (Oid *) palloc(sizeof(Oid) * (INDEX_MAX_KEYS+1));
+
+       /* Extract info from the pg_index tuple */
+       info->relids = lconsi(index->indexrelid, NIL);
+       info->indproc = index->indproc;     /* functional index ?? */
+       if (VARSIZE(&index->indpred) != 0)  /* partial index ?? */
+       {
+           char       *predString = fmgr(F_TEXTOUT, &index->indpred);
+           info->indpred = (List *) stringToNode(predString);
+           pfree(predString);
+       }
+       else
+           info->indpred = NIL;
 
-       predString = fmgr(F_TEXTOUT, &index->indpred);
-       info->indpred = (Node *) stringToNode(predString);
-       pfree(predString);
-   }
+       for (i = 0; i < INDEX_MAX_KEYS; i++)
+           info->indexkeys[i] = index->indkey[i];
+       info->indexkeys[INDEX_MAX_KEYS] = 0;
+       for (i = 0; i < INDEX_MAX_KEYS; i++)
+           info->classlist[i] = index->indclass[i];
+       info->classlist[INDEX_MAX_KEYS] = (Oid) 0;
 
-   /* Extract info from the relation descriptor for the index */
-   indexRelation = index_open(index->indexrelid);
+       /* Extract info from the relation descriptor for the index */
+       indexRelation = index_open(index->indexrelid);
 #ifdef notdef
-   /* XXX should iterate through strategies -- but how?  use #1 for now */
-   amstrategy = indexRelation->rd_am->amstrategies;
+       /* XXX should iterate through strategies -- but how?  use #1 for now */
+       amstrategy = indexRelation->rd_am->amstrategies;
 #endif  /* notdef */
-   amstrategy = 1;
-   relam = indexRelation->rd_rel->relam;
-   info->relam = relam;
-   info->pages = indexRelation->rd_rel->relpages;
-   info->tuples = indexRelation->rd_rel->reltuples;
-   index_close(indexRelation);
+       amstrategy = 1;
+       relam = indexRelation->rd_rel->relam;
+       info->relam = relam;
+       info->pages = indexRelation->rd_rel->relpages;
+       info->tuples = indexRelation->rd_rel->reltuples;
+       index_close(indexRelation);
 
-   /*
-    * Find the index ordering keys
-    *
-    * Must use indclass to know when to stop looking since with functional
-    * indices there could be several keys (args) for one opclass. -mer 27
-    * Sept 1991
-    */
-   for (i = 0; i < 8 && index->indclass[i]; ++i)
-   {
-       amopTuple = SearchSysCacheTuple(AMOPSTRATEGY,
+       /*
+        * Fetch the ordering operators associated with the index.
+        *
+        * XXX what if it's a hash or other unordered index?
+        */
+       MemSet(info->ordering, 0, sizeof(Oid) * (INDEX_MAX_KEYS+1));
+       for (i = 0; i < INDEX_MAX_KEYS && index->indclass[i]; i++)
+       {
+           HeapTuple       amopTuple;
+
+           amopTuple = SearchSysCacheTuple(AMOPSTRATEGY,
                                        ObjectIdGetDatum(relam),
-                                   ObjectIdGetDatum(index->indclass[i]),
+                                       ObjectIdGetDatum(index->indclass[i]),
                                        UInt16GetDatum(amstrategy),
                                        0);
-       if (!HeapTupleIsValid(amopTuple))
-           elog(ERROR, "index_info: no amop %u %u %d",
-                relam, index->indclass[i], amstrategy);
-       info->orderOprs[i] = ((Form_pg_amop) GETSTRUCT(amopTuple))->amopopr;
+           if (!HeapTupleIsValid(amopTuple))
+               elog(ERROR, "find_secondary_indexes: no amop %u %u %d",
+                    relam, index->indclass[i], amstrategy);
+           info->ordering[i] = ((Form_pg_amop) GETSTRUCT(amopTuple))->amopopr;
+       }
+
+       info->indexed = false;      /* not indexed itself */
+       info->size = 0;
+       info->width = 0;
+       info->targetlist = NIL;
+       info->pathlist = NIL;
+       info->cheapestpath = NULL;
+       info->pruneable = true;
+       info->restrictinfo = NIL;
+       info->joininfo = NIL;
+       info->innerjoin = NIL;
+
+       indexes = lcons(info, indexes);
    }
-   return TRUE;
+
+   heap_endscan(scan);
+   heap_close(relation, AccessShareLock);
+
+   return indexes;
 }
 
 /*
@@ -370,10 +346,10 @@ join_selectivity(Oid functionObjectId,
 }
 
 /*
- * find_all_inheritors
+ * find_inheritance_children
  *
- * Returns a LISP list containing the OIDs of all relations which
- * inherits from the relation with OID 'inhparent'.
+ * Returns an integer list containing the OIDs of all relations which
+ * inherit *directly* from the relation with OID 'inhparent'.
  */
 List *
 find_inheritance_children(Oid inhparent)
@@ -390,8 +366,8 @@ find_inheritance_children(Oid inhparent)
 
    fmgr_info(F_OIDEQ, &key[0].sk_func);
    key[0].sk_nargs = key[0].sk_func.fn_nargs;
+   key[0].sk_argument = ObjectIdGetDatum(inhparent);
 
-   key[0].sk_argument = ObjectIdGetDatum((Oid) inhparent);
    relation = heap_openr(InheritsRelationName, AccessShareLock);
    scan = heap_beginscan(relation, 0, SnapshotNow, 1, key);
    while (HeapTupleIsValid(inheritsTuple = heap_getnext(scan, 0)))
index 9a12ecb1d8cb1d88a4ed27d09eccff5821d886a1..34c853d68f8b767dd4c35d73fd00b124251e977f 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: plancat.h,v 1.13 1999/07/25 23:07:23 tgl Exp $
+ * $Id: plancat.h,v 1.14 1999/11/21 23:25:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "nodes/parsenodes.h"
 
-/*
- * transient data structure to hold return value of index_info. Note that
- * indexkeys, orderOprs and classlist is "null-terminated".
- */
-typedef struct IdxInfoRetval
-{
-   Oid         relid;          /* OID of the index relation (not the OID
-                                * of the relation being indexed) */
-   Oid         relam;          /* OID of the pg_am of this index */
-   int         pages;          /* number of pages in the index relation */
-   int         tuples;         /* number of tuples in the index relation */
-   int        *indexkeys;      /* keys over which we're indexing */
-   Oid        *orderOprs;      /* operators used for ordering purposes */
-   Oid        *classlist;      /* classes of AM operators */
-   Oid         indproc;
-   Node       *indpred;
-} IdxInfoRetval;
-
-
-extern void relation_info(Query *root,
-             Oid relid,
-             bool *hashindex, int *pages,
-             int *tuples);
-
-extern bool index_info(Query *root,
-          bool first, int relid, IdxInfoRetval *info);
+
+extern void relation_info(Query *root, Index relid,
+                         bool *hasindex, int *pages, int *tuples);
+
+extern List *find_secondary_indexes(Query *root, Index relid);
 
 extern Cost restriction_selectivity(Oid functionObjectId,
                        Oid operatorObjectId,