diff options
author | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
commit | d31084e9d1118b25fd16580d9d8c2924b5740dff (patch) | |
tree | 3179e66307d54df9c7b966543550e601eb55e668 /src/backend/optimizer/util/plancat.c | |
download | postgresql-PG95-1_01.tar.gz postgresql-PG95-1_01.zip |
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/optimizer/util/plancat.c')
-rw-r--r-- | src/backend/optimizer/util/plancat.c | 582 |
1 files changed, 582 insertions, 0 deletions
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c new file mode 100644 index 00000000000..4dca017f95a --- /dev/null +++ b/src/backend/optimizer/util/plancat.c @@ -0,0 +1,582 @@ +/*------------------------------------------------------------------------- + * + * plancat.c-- + * routines for accessing the system catalogs + * + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.1.1.1 1996/07/09 06:21:39 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include <stdio.h> +#include "postgres.h" + +#include "access/heapam.h" +#include "access/genam.h" +#include "access/htup.h" +#include "access/itup.h" + +#include "catalog/catname.h" +#include "catalog/pg_amop.h" +#include "catalog/pg_index.h" +#include "catalog/pg_inherits.h" +#include "catalog/pg_version.h" + +#include "nodes/pg_list.h" +#include "parser/parsetree.h" /* for getrelid() */ +#include "fmgr.h" + +#include "optimizer/internal.h" +#include "optimizer/plancat.h" + +#include "utils/tqual.h" +#include "utils/elog.h" +#include "utils/palloc.h" +#include "utils/syscache.h" + + +static void IndexSelectivity(Oid indexrelid, Oid indrelid, int32 nIndexKeys, + Oid AccessMethodOperatorClasses[], Oid operatorObjectIds[], + int32 varAttributeNumbers[], char *constValues[], int32 constFlags[], + float *idxPages, float *idxSelec); + + +/* + * relation-info - + * Retrieves catalog information for a given relation. Given the oid of + * the relation, return the following information: + * whether the relation has secondary indices + * number of pages + * number of tuples + */ +void +relation_info(Query *root, Index relid, + bool *hasindex, int *pages, int *tuples) +{ + HeapTuple relationTuple; + Form_pg_class relation; + Oid relationObjectId; + + relationObjectId = getrelid(relid, root->rtable); + relationTuple = SearchSysCacheTuple(RELOID, + ObjectIdGetDatum(relationObjectId), + 0,0,0); + if (HeapTupleIsValid(relationTuple)) { + relation = (Form_pg_class)GETSTRUCT(relationTuple); + + *hasindex = (relation->relhasindex) ? TRUE : FALSE; + *pages = relation->relpages; + *tuples = relation->reltuples; + } else { + elog(WARN, "RelationCatalogInformation: Relation %d not found", + relationObjectId); + } + + return; +} + + +/* + * index-info-- + * Retrieves catalog information on an index on a 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'. + * + */ +bool +index_info(Query *root, bool first, int relid, IdxInfoRetval *info) +{ + register i; + HeapTuple indexTuple, amopTuple; + IndexTupleForm index; + Relation indexRelation; + uint16 amstrategy; + Oid relam; + Oid indrelid; + + static Relation relation = (Relation) NULL; + static HeapScanDesc scan = (HeapScanDesc) NULL; + 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 (RelationIsValid(relation)) + heap_close(relation); + if (HeapScanIsValid(scan)) + heap_endscan(scan); + + ScanKeyEntryInitialize(&indexKey, 0, + Anum_pg_index_indrelid, + F_OIDEQ, + ObjectIdGetDatum(indrelid)); + + relation = heap_openr(IndexRelationName); + scan = heap_beginscan(relation, 0, NowTimeQual, + 1, &indexKey); + } + if (!HeapScanIsValid(scan)) + elog(WARN, "index_info: scan not started"); + indexTuple = heap_getnext(scan, 0, (Buffer *) NULL); + if (!HeapTupleIsValid(indexTuple)) { + heap_endscan(scan); + heap_close(relation); + scan = (HeapScanDesc) NULL; + relation = (Relation) NULL; + return(0); + } + + /* Extract info from the index tuple */ + index = (IndexTupleForm)GETSTRUCT(indexTuple); + info->relid = index->indexrelid; /* index relation */ + for (i = 0; i < 8; i++) + info->indexkeys[i] = index->indkey[i]; + for (i = 0; i < 8; i++) + info->classlist[i] = index->indclass[i]; + + info->indproc = index->indproc; /* functional index ?? */ + + /* partial index ?? */ + if (VARSIZE(&index->indpred) != 0) { + /* + * 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. + */ + char *predString; + + predString = fmgr(F_TEXTOUT, &index->indpred); + info->indpred = (Node*)stringToNode(predString); + pfree(predString); + } + + /* 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; +#endif /* notdef */ + amstrategy = 1; + relam = indexRelation->rd_rel->relam; + info->relam = relam; + info->pages = indexRelation->rd_rel->relpages; + info->tuples = indexRelation->rd_rel->reltuples; + heap_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, + ObjectIdGetDatum(relam), + ObjectIdGetDatum(index->indclass[i]), + UInt16GetDatum(amstrategy), + 0); + if (!HeapTupleIsValid(amopTuple)) + elog(WARN, "index_info: no amop %d %d %d", + relam, index->indclass[i], amstrategy); + info->orderOprs[i] = + ((Form_pg_amop)GETSTRUCT(amopTuple))->amopopr; + } + return(TRUE); +} + +/* + * index-selectivity-- + * + * Call util/plancat.c:IndexSelectivity with the indicated arguments. + * + * 'indid' is the index OID + * 'classes' is a list of index key classes + * 'opnos' is a list of index key operator OIDs + * 'relid' is the OID of the relation indexed + * 'attnos' is a list of the relation attnos which the index keys over + * 'values' is a list of the values of the clause's constants + * 'flags' is a list of fixnums which describe the constants + * 'nkeys' is the number of index keys + * + * Returns two floats: index pages and index selectivity in 'idxPages' and + * 'idxSelec'. + * + */ +void +index_selectivity(Oid indid, + Oid *classes, + List *opnos, + Oid relid, + List *attnos, + List *values, + List *flags, + int32 nkeys, + float *idxPages, + float *idxSelec) +{ + Oid *opno_array; + int *attno_array, *flag_array; + char **value_array; + int i = 0; + List *xopno, *xattno, *value, *flag; + + if (length(opnos)!=nkeys || length(attnos)!=nkeys || + length(values)!=nkeys || length(flags)!=nkeys) { + + *idxPages = 0.0; + *idxSelec = 1.0; + return; + } + + opno_array = (Oid *)palloc(nkeys*sizeof(Oid)); + attno_array = (int *)palloc(nkeys*sizeof(int32)); + value_array = (char **)palloc(nkeys*sizeof(char *)); + flag_array = (int *)palloc(nkeys*sizeof(int32)); + + i = 0; + foreach(xopno, opnos) { + opno_array[i++] = (int)lfirst(xopno); + } + + i = 0; + foreach(xattno,attnos) { + attno_array[i++] = (int)lfirst(xattno); + } + + i = 0; + foreach(value, values) { + value_array[i++] = (char *)lfirst(value); + } + + i = 0; + foreach(flag,flags) { + flag_array[i++] = (int)lfirst(flag); + } + + IndexSelectivity(indid, + relid, + nkeys, + classes, /* not used */ + opno_array, + attno_array, + value_array, + flag_array, + idxPages, + idxSelec); + return; +} + +/* + * restriction_selectivity in lisp system.-- + * + * NOTE: The routine is now merged with RestrictionClauseSelectivity + * as defined in plancat.c + * + * Returns the selectivity of a specified operator. + * This code executes registered procedures stored in the + * operator relation, by calling the function manager. + * + * XXX The assumption in the selectivity procedures is that if the + * relation OIDs or attribute numbers are -1, then the clause + * isn't of the form (op var const). + */ +Cost +restriction_selectivity(Oid functionObjectId, + Oid operatorObjectId, + Oid relationObjectId, + AttrNumber attributeNumber, + char *constValue, + int32 constFlag) +{ + float64 result; + + result = (float64) fmgr(functionObjectId, + (char *) operatorObjectId, + (char *) relationObjectId, + (char *) attributeNumber, + (char *) constValue, + (char *) constFlag, + NULL); + if (!PointerIsValid(result)) + elog(WARN, "RestrictionClauseSelectivity: bad pointer"); + + if (*result < 0.0 || *result > 1.0) + elog(WARN, "RestrictionClauseSelectivity: bad value %lf", + *result); + + return ((Cost)*result); +} + +/* + * join_selectivity-- + * Similarly, this routine is merged with JoinClauseSelectivity in + * plancat.c + * + * Returns the selectivity of an operator, given the join clause + * information. + * + * XXX The assumption in the selectivity procedures is that if the + * relation OIDs or attribute numbers are -1, then the clause + * isn't of the form (op var var). + */ +Cost +join_selectivity (Oid functionObjectId, + Oid operatorObjectId, + Oid relationObjectId1, + AttrNumber attributeNumber1, + Oid relationObjectId2, + AttrNumber attributeNumber2) +{ + float64 result; + + result = (float64) fmgr(functionObjectId, + (char *) operatorObjectId, + (char *) relationObjectId1, + (char *) attributeNumber1, + (char *) relationObjectId2, + (char *) attributeNumber2, + NULL); + if (!PointerIsValid(result)) + elog(WARN, "JoinClauseSelectivity: bad pointer"); + + if (*result < 0.0 || *result > 1.0) + elog(WARN, "JoinClauseSelectivity: bad value %lf", + *result); + + return((Cost)*result); +} + +/* + * find_all_inheritors-- + * + * Returns a LISP list containing the OIDs of all relations which + * inherits from the relation with OID 'inhparent'. + */ +List * +find_inheritance_children(Oid inhparent) +{ + static ScanKeyData key[1] = { + { 0, Anum_pg_inherits_inhparent, F_OIDEQ } + }; + + HeapTuple inheritsTuple; + Relation relation; + HeapScanDesc scan; + List *list = NIL; + Oid inhrelid; + + fmgr_info(F_OIDEQ, &key[0].sk_func, &key[0].sk_nargs); + + key[0].sk_argument = ObjectIdGetDatum((Oid)inhparent); + relation = heap_openr(InheritsRelationName); + scan = heap_beginscan(relation, 0, NowTimeQual, 1, key); + while (HeapTupleIsValid(inheritsTuple = + heap_getnext(scan, 0, + (Buffer *) NULL))) { + inhrelid = ((InheritsTupleForm)GETSTRUCT(inheritsTuple))->inhrel; + list = lappendi(list, inhrelid); + } + heap_endscan(scan); + heap_close(relation); + return(list); +} + +/* + * VersionGetParents-- + * + * Returns a LISP list containing the OIDs of all relations which are + * base relations of the relation with OID 'verrelid'. + */ +List * +VersionGetParents(Oid verrelid) +{ + static ScanKeyData key[1] = { + { 0, Anum_pg_version_verrelid, F_OIDEQ } + }; + + HeapTuple versionTuple; + Relation relation; + HeapScanDesc scan; + Oid verbaseid; + List *list= NIL; + + fmgr_info(F_OIDEQ, &key[0].sk_func, &key[0].sk_nargs); + relation = heap_openr(VersionRelationName); + key[0].sk_argument = ObjectIdGetDatum(verrelid); + scan = heap_beginscan(relation, 0, NowTimeQual, 1, key); + for (;;) { + versionTuple = heap_getnext(scan, 0, + (Buffer *) NULL); + if (!HeapTupleIsValid(versionTuple)) + break; + verbaseid = ((VersionTupleForm) + GETSTRUCT(versionTuple))->verbaseid; + + list = lconsi(verbaseid, list); + + key[0].sk_argument = ObjectIdGetDatum(verbaseid); + heap_rescan(scan, 0, key); + } + heap_endscan(scan); + heap_close(relation); + return(list); +} + +/***************************************************************************** + * + *****************************************************************************/ + +/* + * IdexSelectivity-- + * + * Retrieves the 'amopnpages' and 'amopselect' parameters for each + * AM operator when a given index (specified by 'indexrelid') is used. + * These two parameters are returned by copying them to into an array of + * floats. + * + * Assumption: the attribute numbers and operator ObjectIds are in order + * WRT to each other (otherwise, you have no way of knowing which + * AM operator class or attribute number corresponds to which operator. + * + * 'varAttributeNumbers' contains attribute numbers for variables + * 'constValues' contains the constant values + * 'constFlags' describes how to treat the constants in each clause + * 'nIndexKeys' describes how many keys the index actually has + * + * Returns 'selectivityInfo' filled with the sum of all pages touched + * and the product of each clause's selectivity. + * + */ +static void +IndexSelectivity(Oid indexrelid, + Oid indrelid, + int32 nIndexKeys, + Oid AccessMethodOperatorClasses[], /* XXX not used? */ + Oid operatorObjectIds[], + int32 varAttributeNumbers[], + char *constValues[], + int32 constFlags[], + float *idxPages, + float *idxSelec) +{ + register i, n; + HeapTuple indexTuple, amopTuple, indRel; + IndexTupleForm index; + Form_pg_amop amop; + Oid indclass; + float64data npages, select; + float64 amopnpages, amopselect; + Oid relam; + + indRel = SearchSysCacheTuple(RELOID, + ObjectIdGetDatum(indexrelid), + 0,0,0); + if (!HeapTupleIsValid(indRel)) + elog(WARN, "IndexSelectivity: index %d not found", + indexrelid); + relam = ((Form_pg_class)GETSTRUCT(indRel))->relam; + + indexTuple = SearchSysCacheTuple(INDEXRELID, + ObjectIdGetDatum(indexrelid), + 0,0,0); + if (!HeapTupleIsValid(indexTuple)) + elog(WARN, "IndexSelectivity: index %d not found", + indexrelid); + index = (IndexTupleForm)GETSTRUCT(indexTuple); + + npages = 0.0; + select = 1.0; + for (n = 0; n < nIndexKeys; ++n) { + /* + * Find the AM class for this key. + * + * If the first attribute number is invalid then we have a + * functional index, and AM class is the first one defined + * since functional indices have exactly one key. + */ + indclass = (varAttributeNumbers[0] == InvalidAttrNumber) ? + index->indclass[0] : InvalidOid; + i = 0; + while ((i < nIndexKeys) && (indclass == InvalidOid)) { + if (varAttributeNumbers[n] == index->indkey[i]) { + indclass = index->indclass[i]; + break; + } + i++; + } + if (!OidIsValid(indclass)) { + /* + * Presumably this means that we are using a functional + * index clause and so had no variable to match to + * the index key ... if not we are in trouble. + */ + elog(NOTICE, "IndexSelectivity: no key %d in index %d", + varAttributeNumbers[n], indexrelid); + continue; + } + + amopTuple = SearchSysCacheTuple(AMOPOPID, + ObjectIdGetDatum(indclass), + ObjectIdGetDatum(operatorObjectIds[n]), + ObjectIdGetDatum(relam), + 0); + if (!HeapTupleIsValid(amopTuple)) + elog(WARN, "IndexSelectivity: no amop %d %d", + indclass, operatorObjectIds[n]); + amop = (Form_pg_amop)GETSTRUCT(amopTuple); + amopnpages = (float64) fmgr(amop->amopnpages, + (char *) operatorObjectIds[n], + (char *) indrelid, + (char *) varAttributeNumbers[n], + (char *) constValues[n], + (char *) constFlags[n], + (char *) nIndexKeys, + (char *) indexrelid); + npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0; + if ((i = npages) < npages) /* ceil(npages)? */ + npages += 1.0; + amopselect = (float64) fmgr(amop->amopselect, + (char *) operatorObjectIds[n], + (char *) indrelid, + (char *) varAttributeNumbers[n], + (char *) constValues[n], + (char *) constFlags[n], + (char *) nIndexKeys, + (char *) indexrelid); + select *= PointerIsValid(amopselect) ? *amopselect : 1.0; + } + *idxPages = npages; + *idxSelec = select; +} + |