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...
This commit is contained in:
Tom Lane 1999-11-21 23:25:47 +00:00
parent 40d3e92541
commit 610dfa6d55
3 changed files with 113 additions and 212 deletions

View 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;
}

View 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;
List *indexes = NIL;
Oid indrelid = getrelid(relid, root->rtable);
Relation relation;
HeapScanDesc scan;
ScanKeyData indexKey;
HeapTuple indexTuple;
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);
ScanKeyEntryInitialize(&indexKey, 0,
Anum_pg_index_indrelid,
F_OIDEQ,
ObjectIdGetDatum(indrelid));
/* find the oid of the indexed relation */
indrelid = getrelid(relid, root->rtable);
scan = heap_beginscan(relation, 0, SnapshotNow,
1, &indexKey);
MemSet(info, 0, sizeof(IdxInfoRetval));
/*
* 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));
predString = fmgr(F_TEXTOUT, &index->indpred);
info->indpred = (Node *) stringToNode(predString);
pfree(predString);
}
/* 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;
/* Extract info from the relation descriptor for the index */
indexRelation = index_open(index->indexrelid);
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);
#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)))

View 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 $
*
*-------------------------------------------------------------------------
*/
@ -15,32 +15,11 @@
#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, Index relid,
bool *hasindex, int *pages, int *tuples);
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 List *find_secondary_indexes(Query *root, Index relid);
extern Cost restriction_selectivity(Oid functionObjectId,
Oid operatorObjectId,