Commit 610dfa6d authored by Tom Lane's avatar Tom Lane

Combine index_info and find_secondary_indexes into a single routine that

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...
parent 40d3e925
...@@ -7,21 +7,16 @@ ...@@ -7,21 +7,16 @@
* *
* *
* IDENTIFICATION * 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 "postgres.h"
#include "optimizer/pathnode.h" #include "optimizer/pathnode.h"
#include "optimizer/plancat.h" #include "optimizer/plancat.h"
static List *find_secondary_index(Query *root, Oid relid);
/* /*
* find_relation_indices * find_relation_indices
* Returns a list of index nodes containing appropriate information for * Returns a list of index nodes containing appropriate information for
...@@ -32,56 +27,7 @@ List * ...@@ -32,56 +27,7 @@ List *
find_relation_indices(Query *root, RelOptInfo *rel) find_relation_indices(Query *root, RelOptInfo *rel)
{ {
if (rel->indexed) if (rel->indexed)
return find_secondary_index(root, lfirsti(rel->relids)); return find_secondary_indexes(root, lfirsti(rel->relids));
else else
return NIL; 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;
}
...@@ -8,13 +8,14 @@ ...@@ -8,13 +8,14 @@
* *
* *
* IDENTIFICATION * 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 <math.h>
#include "postgres.h" #include "postgres.h"
#include "access/genam.h" #include "access/genam.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "catalog/catname.h" #include "catalog/catname.h"
...@@ -38,8 +39,8 @@ static void IndexSelectivity(Oid indexrelid, Oid baserelid, int nIndexKeys, ...@@ -38,8 +39,8 @@ static void IndexSelectivity(Oid indexrelid, Oid baserelid, int nIndexKeys,
/* /*
* relation_info - * relation_info -
* Retrieves catalog information for a given relation. Given the oid of * Retrieves catalog information for a given relation.
* the relation, return the following information: * Given the rangetable index of the relation, return the following info:
* whether the relation has secondary indices * whether the relation has secondary indices
* number of pages * number of pages
* number of tuples * number of tuples
...@@ -54,166 +55,141 @@ relation_info(Query *root, Index relid, ...@@ -54,166 +55,141 @@ relation_info(Query *root, Index relid,
relationObjectId = getrelid(relid, root->rtable); relationObjectId = getrelid(relid, root->rtable);
relationTuple = SearchSysCacheTuple(RELOID, relationTuple = SearchSysCacheTuple(RELOID,
ObjectIdGetDatum(relationObjectId), ObjectIdGetDatum(relationObjectId),
0, 0, 0); 0, 0, 0);
if (HeapTupleIsValid(relationTuple)) if (HeapTupleIsValid(relationTuple))
{ {
relation = (Form_pg_class) GETSTRUCT(relationTuple); relation = (Form_pg_class) GETSTRUCT(relationTuple);
*hasindex = (relation->relhasindex) ? TRUE : FALSE; *hasindex = (relation->relhasindex) ? true : false;
*pages = relation->relpages; *pages = relation->relpages;
*tuples = relation->reltuples; *tuples = relation->reltuples;
} }
else else
{ {
elog(ERROR, "RelationCatalogInformation: Relation %u not found", elog(ERROR, "relation_info: Relation %u not found",
relationObjectId); relationObjectId);
} }
return;
} }
/* /*
* index_info * find_secondary_indexes
* Retrieves catalog information on an index on a given relation. * 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 * 'relid' is the RT index of the relation for which indices are being located
* 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'.
* *
* Returns a list of new index RelOptInfo nodes.
*/ */
bool List *
index_info(Query *root, bool first, int relid, IdxInfoRetval *info) find_secondary_indexes(Query *root, Index relid)
{ {
int i; List *indexes = NIL;
HeapTuple indexTuple, Oid indrelid = getrelid(relid, root->rtable);
amopTuple; Relation relation;
Form_pg_index index; HeapScanDesc scan;
Relation indexRelation; ScanKeyData indexKey;
uint16 amstrategy; HeapTuple indexTuple;
Oid relam;
Oid indrelid;
static Relation relation = (Relation) NULL;
static HeapScanDesc scan = (HeapScanDesc) NULL;
static ScanKeyData indexKey;
/* Scan pg_index for tuples describing indexes of this rel */
relation = heap_openr(IndexRelationName, AccessShareLock);
/* find the oid of the indexed relation */ ScanKeyEntryInitialize(&indexKey, 0,
indrelid = getrelid(relid, root->rtable); Anum_pg_index_indrelid,
F_OIDEQ,
ObjectIdGetDatum(indrelid));
MemSet(info, 0, sizeof(IdxInfoRetval)); scan = heap_beginscan(relation, 0, SnapshotNow,
1, &indexKey);
/* while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
* 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)
{ {
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) * Need to make these arrays large enough to be sure there is a
* only needs to stay around until it's used in find_index_paths, * terminating 0 at the end of each one.
* which is all within a command, so the automatic pfree at end of
* transaction should be ok.
*/ */
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); for (i = 0; i < INDEX_MAX_KEYS; i++)
info->indpred = (Node *) stringToNode(predString); info->indexkeys[i] = index->indkey[i];
pfree(predString); 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 */ /* Extract info from the relation descriptor for the index */
indexRelation = index_open(index->indexrelid); indexRelation = index_open(index->indexrelid);
#ifdef notdef #ifdef notdef
/* XXX should iterate through strategies -- but how? use #1 for now */ /* XXX should iterate through strategies -- but how? use #1 for now */
amstrategy = indexRelation->rd_am->amstrategies; amstrategy = indexRelation->rd_am->amstrategies;
#endif /* notdef */ #endif /* notdef */
amstrategy = 1; amstrategy = 1;
relam = indexRelation->rd_rel->relam; relam = indexRelation->rd_rel->relam;
info->relam = relam; info->relam = relam;
info->pages = indexRelation->rd_rel->relpages; info->pages = indexRelation->rd_rel->relpages;
info->tuples = indexRelation->rd_rel->reltuples; info->tuples = indexRelation->rd_rel->reltuples;
index_close(indexRelation); index_close(indexRelation);
/* /*
* Find the index ordering keys * Fetch the ordering operators associated with the index.
* *
* Must use indclass to know when to stop looking since with functional * XXX what if it's a hash or other unordered index?
* indices there could be several keys (args) for one opclass. -mer 27 */
* Sept 1991 MemSet(info->ordering, 0, sizeof(Oid) * (INDEX_MAX_KEYS+1));
*/ for (i = 0; i < INDEX_MAX_KEYS && index->indclass[i]; i++)
for (i = 0; i < 8 && index->indclass[i]; ++i) {
{ HeapTuple amopTuple;
amopTuple = SearchSysCacheTuple(AMOPSTRATEGY,
amopTuple = SearchSysCacheTuple(AMOPSTRATEGY,
ObjectIdGetDatum(relam), ObjectIdGetDatum(relam),
ObjectIdGetDatum(index->indclass[i]), ObjectIdGetDatum(index->indclass[i]),
UInt16GetDatum(amstrategy), UInt16GetDatum(amstrategy),
0); 0);
if (!HeapTupleIsValid(amopTuple)) if (!HeapTupleIsValid(amopTuple))
elog(ERROR, "index_info: no amop %u %u %d", elog(ERROR, "find_secondary_indexes: no amop %u %u %d",
relam, index->indclass[i], amstrategy); relam, index->indclass[i], amstrategy);
info->orderOprs[i] = ((Form_pg_amop) GETSTRUCT(amopTuple))->amopopr; 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, ...@@ -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 * Returns an integer list containing the OIDs of all relations which
* inherits from the relation with OID 'inhparent'. * inherit *directly* from the relation with OID 'inhparent'.
*/ */
List * List *
find_inheritance_children(Oid inhparent) find_inheritance_children(Oid inhparent)
...@@ -390,8 +366,8 @@ find_inheritance_children(Oid inhparent) ...@@ -390,8 +366,8 @@ find_inheritance_children(Oid inhparent)
fmgr_info(F_OIDEQ, &key[0].sk_func); fmgr_info(F_OIDEQ, &key[0].sk_func);
key[0].sk_nargs = key[0].sk_func.fn_nargs; 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); relation = heap_openr(InheritsRelationName, AccessShareLock);
scan = heap_beginscan(relation, 0, SnapshotNow, 1, key); scan = heap_beginscan(relation, 0, SnapshotNow, 1, key);
while (HeapTupleIsValid(inheritsTuple = heap_getnext(scan, 0))) while (HeapTupleIsValid(inheritsTuple = heap_getnext(scan, 0)))
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -15,32 +15,11 @@ ...@@ -15,32 +15,11 @@
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
/*
* transient data structure to hold return value of index_info. Note that extern void relation_info(Query *root, Index relid,
* indexkeys, orderOprs and classlist is "null-terminated". bool *hasindex, int *pages, int *tuples);
*/
typedef struct IdxInfoRetval extern List *find_secondary_indexes(Query *root, Index relid);
{
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 Cost restriction_selectivity(Oid functionObjectId, extern Cost restriction_selectivity(Oid functionObjectId,
Oid operatorObjectId, Oid operatorObjectId,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment