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:
parent
40d3e92541
commit
610dfa6d55
@ -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 *
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
@ -60,126 +61,82 @@ relation_info(Query *root, Index relid,
|
|||||||
{
|
{
|
||||||
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;
|
/* Scan pg_index for tuples describing indexes of this rel */
|
||||||
static HeapScanDesc scan = (HeapScanDesc) NULL;
|
relation = heap_openr(IndexRelationName, AccessShareLock);
|
||||||
static ScanKeyData indexKey;
|
|
||||||
|
|
||||||
|
|
||||||
/* find the oid of the indexed relation */
|
|
||||||
indrelid = getrelid(relid, root->rtable);
|
|
||||||
|
|
||||||
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,
|
ScanKeyEntryInitialize(&indexKey, 0,
|
||||||
Anum_pg_index_indrelid,
|
Anum_pg_index_indrelid,
|
||||||
F_OIDEQ,
|
F_OIDEQ,
|
||||||
ObjectIdGetDatum(indrelid));
|
ObjectIdGetDatum(indrelid));
|
||||||
|
|
||||||
relation = heap_openr(IndexRelationName, AccessShareLock);
|
|
||||||
scan = heap_beginscan(relation, 0, SnapshotNow,
|
scan = heap_beginscan(relation, 0, SnapshotNow,
|
||||||
1, &indexKey);
|
1, &indexKey);
|
||||||
}
|
|
||||||
if (!HeapScanIsValid(scan))
|
while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
|
||||||
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));
|
||||||
|
|
||||||
predString = fmgr(F_TEXTOUT, &index->indpred);
|
/* Extract info from the pg_index tuple */
|
||||||
info->indpred = (Node *) stringToNode(predString);
|
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);
|
pfree(predString);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
info->indpred = NIL;
|
||||||
|
|
||||||
|
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 */
|
/* Extract info from the relation descriptor for the index */
|
||||||
indexRelation = index_open(index->indexrelid);
|
indexRelation = index_open(index->indexrelid);
|
||||||
@ -195,25 +152,44 @@ index_info(Query *root, bool first, int relid, IdxInfoRetval *info)
|
|||||||
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
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < 8 && index->indclass[i]; ++i)
|
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,
|
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;
|
||||||
}
|
}
|
||||||
return TRUE;
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
* 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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
*
|
*
|
||||||
* 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 @@
|
|||||||
|
|
||||||
#include "nodes/parsenodes.h"
|
#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,
|
extern List *find_secondary_indexes(Query *root, Index relid);
|
||||||
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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user