1 /*-------------------------------------------------------------------------
4 * routines for accessing the system catalogs
7 * Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.29 1999/05/10 00:45:25 momjian Exp $
13 *-------------------------------------------------------------------------
18 #include "access/heapam.h"
19 #include "access/genam.h"
20 #include "access/htup.h"
21 #include "access/itup.h"
23 #include "catalog/catname.h"
24 #include "catalog/pg_amop.h"
25 #include "catalog/pg_index.h"
26 #include "catalog/pg_inherits.h"
27 #include "catalog/pg_version.h"
29 #include "parser/parsetree.h" /* for getrelid() */
32 #include "optimizer/internal.h"
33 #include "optimizer/plancat.h"
35 #include "utils/syscache.h"
37 #include <regex/utils.h>
43 static void IndexSelectivity(Oid indexrelid, Oid indrelid, int32 nIndexKeys,
44 Oid *AccessMethodOperatorClasses, Oid *operatorObjectIds,
45 int32 *varAttributeNumbers, char **constValues, int32 *constFlags,
46 float *idxPages, float *idxSelec);
51 * Retrieves catalog information for a given relation. Given the oid of
52 * the relation, return the following information:
53 * whether the relation has secondary indices
58 relation_info(Query *root, Index relid,
59 bool *hasindex, int *pages, int *tuples)
61 HeapTuple relationTuple;
62 Form_pg_class relation;
65 relationObjectId = getrelid(relid, root->rtable);
66 relationTuple = SearchSysCacheTuple(RELOID,
67 ObjectIdGetDatum(relationObjectId),
69 if (HeapTupleIsValid(relationTuple))
71 relation = (Form_pg_class) GETSTRUCT(relationTuple);
73 *hasindex = (relation->relhasindex) ? TRUE : FALSE;
74 *pages = relation->relpages;
75 *tuples = relation->reltuples;
79 elog(ERROR, "RelationCatalogInformation: Relation %u not found",
89 * Retrieves catalog information on an index on a given relation.
91 * The index relation is opened on the first invocation. The current
92 * retrieves the next index relation within the catalog that has not
93 * already been retrieved by a previous call. The index catalog
94 * is closed when no more indices for 'relid' can be found.
96 * 'first' is 1 if this is the first call
98 * Returns true if successful and false otherwise. Index info is returned
99 * via the transient data structure 'info'.
103 index_info(Query *root, bool first, int relid, IdxInfoRetval *info)
106 HeapTuple indexTuple,
109 Relation indexRelation;
114 static Relation relation = (Relation) NULL;
115 static HeapScanDesc scan = (HeapScanDesc) NULL;
116 static ScanKeyData indexKey;
119 /* find the oid of the indexed relation */
120 indrelid = getrelid(relid, root->rtable);
122 MemSet(info, 0, sizeof(IdxInfoRetval));
125 * the maximum number of elements in each of the following arrays is
126 * 8. We allocate one more for a terminating 0 to indicate the end of
129 info->indexkeys = (int *) palloc(sizeof(int) * 9);
130 MemSet(info->indexkeys, 0, sizeof(int) * 9);
131 info->orderOprs = (Oid *) palloc(sizeof(Oid) * 9);
132 MemSet(info->orderOprs, 0, sizeof(Oid) * 9);
133 info->classlist = (Oid *) palloc(sizeof(Oid) * 9);
134 MemSet(info->classlist, 0, sizeof(Oid) * 9);
136 /* Find an index on the given relation */
139 if (RelationIsValid(relation))
140 heap_close(relation);
141 if (HeapScanIsValid(scan))
144 ScanKeyEntryInitialize(&indexKey, 0,
145 Anum_pg_index_indrelid,
147 ObjectIdGetDatum(indrelid));
149 relation = heap_openr(IndexRelationName);
150 scan = heap_beginscan(relation, 0, SnapshotNow,
153 if (!HeapScanIsValid(scan))
154 elog(ERROR, "index_info: scan not started");
155 indexTuple = heap_getnext(scan, 0);
156 if (!HeapTupleIsValid(indexTuple))
159 heap_close(relation);
160 scan = (HeapScanDesc) NULL;
161 relation = (Relation) NULL;
165 /* Extract info from the index tuple */
166 index = (Form_pg_index) GETSTRUCT(indexTuple);
167 info->relid = index->indexrelid; /* index relation */
168 for (i = 0; i < INDEX_MAX_KEYS; i++)
169 info->indexkeys[i] = index->indkey[i];
170 for (i = 0; i < INDEX_MAX_KEYS; i++)
171 info->classlist[i] = index->indclass[i];
173 info->indproc = index->indproc; /* functional index ?? */
175 /* partial index ?? */
176 if (VARSIZE(&index->indpred) != 0)
180 * The memory allocated here for the predicate (in lispReadString)
181 * only needs to stay around until it's used in find_index_paths,
182 * which is all within a command, so the automatic pfree at end of
183 * transaction should be ok.
187 predString = fmgr(F_TEXTOUT, &index->indpred);
188 info->indpred = (Node *) stringToNode(predString);
192 /* Extract info from the relation descriptor for the index */
193 indexRelation = index_open(index->indexrelid);
195 /* XXX should iterate through strategies -- but how? use #1 for now */
196 amstrategy = indexRelation->rd_am->amstrategies;
199 relam = indexRelation->rd_rel->relam;
201 info->pages = indexRelation->rd_rel->relpages;
202 info->tuples = indexRelation->rd_rel->reltuples;
203 heap_close(indexRelation);
206 * Find the index ordering keys
208 * Must use indclass to know when to stop looking since with functional
209 * indices there could be several keys (args) for one opclass. -mer 27
212 for (i = 0; i < 8 && index->indclass[i]; ++i)
214 amopTuple = SearchSysCacheTuple(AMOPSTRATEGY,
215 ObjectIdGetDatum(relam),
216 ObjectIdGetDatum(index->indclass[i]),
217 UInt16GetDatum(amstrategy),
219 if (!HeapTupleIsValid(amopTuple))
220 elog(ERROR, "index_info: no amop %u %u %d",
221 relam, index->indclass[i], amstrategy);
222 info->orderOprs[i] = ((Form_pg_amop) GETSTRUCT(amopTuple))->amopopr;
230 * Call util/plancat.c:IndexSelectivity with the indicated arguments.
232 * 'indid' is the index OID
233 * 'classes' is a list of index key classes
234 * 'opnos' is a list of index key operator OIDs
235 * 'relid' is the OID of the relation indexed
236 * 'attnos' is a list of the relation attnos which the index keys over
237 * 'values' is a list of the values of the clause's constants
238 * 'flags' is a list of fixnums which describe the constants
239 * 'nkeys' is the number of index keys
241 * Returns two floats: index pages and index selectivity in 'idxPages' and
246 index_selectivity(Oid indid,
267 if (length(opnos) != nkeys || length(attnos) != nkeys ||
268 length(values) != nkeys || length(flags) != nkeys)
276 opno_array = (Oid *) palloc(nkeys * sizeof(Oid));
277 attno_array = (int *) palloc(nkeys * sizeof(int32));
278 value_array = (char **) palloc(nkeys * sizeof(char *));
279 flag_array = (int *) palloc(nkeys * sizeof(int32));
282 foreach(xopno, opnos)
283 opno_array[i++] = lfirsti(xopno);
286 foreach(xattno, attnos)
287 attno_array[i++] = lfirsti(xattno);
290 foreach(value, values)
291 value_array[i++] = (char *) lfirst(value);
295 flag_array[i++] = lfirsti(flag);
297 IndexSelectivity(indid,
300 classes, /* not used */
311 * restriction_selectivity in lisp system.
313 * NOTE: The routine is now merged with RestrictionClauseSelectivity
314 * as defined in plancat.c
316 * Returns the selectivity of a specified operator.
317 * This code executes registered procedures stored in the
318 * operator relation, by calling the function manager.
320 * XXX The assumption in the selectivity procedures is that if the
321 * relation OIDs or attribute numbers are -1, then the clause
322 * isn't of the form (op var const).
325 restriction_selectivity(Oid functionObjectId,
326 Oid operatorObjectId,
327 Oid relationObjectId,
328 AttrNumber attributeNumber,
334 result = (float64) fmgr(functionObjectId,
335 (char *) operatorObjectId,
336 (char *) relationObjectId,
337 (char *) (int) attributeNumber,
341 if (!PointerIsValid(result))
342 elog(ERROR, "RestrictionClauseSelectivity: bad pointer");
344 if (*result < 0.0 || *result > 1.0)
345 elog(ERROR, "RestrictionClauseSelectivity: bad value %lf",
348 return (Cost) *result;
353 * Similarly, this routine is merged with JoinClauseSelectivity in
356 * Returns the selectivity of an operator, given the join clause
359 * XXX The assumption in the selectivity procedures is that if the
360 * relation OIDs or attribute numbers are -1, then the clause
361 * isn't of the form (op var var).
364 join_selectivity(Oid functionObjectId,
365 Oid operatorObjectId,
366 Oid relationObjectId1,
367 AttrNumber attributeNumber1,
368 Oid relationObjectId2,
369 AttrNumber attributeNumber2)
373 result = (float64) fmgr(functionObjectId,
374 (char *) operatorObjectId,
375 (char *) relationObjectId1,
376 (char *) (int) attributeNumber1,
377 (char *) relationObjectId2,
378 (char *) (int) attributeNumber2,
380 if (!PointerIsValid(result))
381 elog(ERROR, "JoinClauseSelectivity: bad pointer");
383 if (*result < 0.0 || *result > 1.0)
384 elog(ERROR, "JoinClauseSelectivity: bad value %lf",
387 return (Cost) *result;
391 * find_all_inheritors
393 * Returns a LISP list containing the OIDs of all relations which
394 * inherits from the relation with OID 'inhparent'.
397 find_inheritance_children(Oid inhparent)
399 static ScanKeyData key[1] = {
400 {0, Anum_pg_inherits_inhparent, F_OIDEQ}
403 HeapTuple inheritsTuple;
409 fmgr_info(F_OIDEQ, &key[0].sk_func);
410 key[0].sk_nargs = key[0].sk_func.fn_nargs;
412 key[0].sk_argument = ObjectIdGetDatum((Oid) inhparent);
413 relation = heap_openr(InheritsRelationName);
414 scan = heap_beginscan(relation, 0, SnapshotNow, 1, key);
415 while (HeapTupleIsValid(inheritsTuple = heap_getnext(scan, 0)))
417 inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrel;
418 list = lappendi(list, inhrelid);
421 heap_close(relation);
429 * Returns a LISP list containing the OIDs of all relations which are
430 * base relations of the relation with OID 'verrelid'.
433 VersionGetParents(Oid verrelid)
435 static ScanKeyData key[1] = {
436 {0, Anum_pg_version_verrelid, F_OIDEQ}
439 HeapTuple versionTuple;
445 fmgr_info(F_OIDEQ, &key[0].sk_func);
446 key[0].sk_nargs = key[0].sk_func.fn_nargs;
447 relation = heap_openr(VersionRelationName);
448 key[0].sk_argument = ObjectIdGetDatum(verrelid);
449 scan = heap_beginscan(relation, 0, SnapshotNow, 1, key);
450 while (HeapTupleIsValid(versionTuple = heap_getnext(scan, 0)))
452 verbaseid = ((Form_pg_version)
453 GETSTRUCT(versionTuple))->verbaseid;
455 list = lconsi(verbaseid, list);
457 key[0].sk_argument = ObjectIdGetDatum(verbaseid);
458 heap_rescan(scan, 0, key);
461 heap_close(relation);
467 /*****************************************************************************
469 *****************************************************************************/
474 * Retrieves the 'amopnpages' and 'amopselect' parameters for each
475 * AM operator when a given index (specified by 'indexrelid') is used.
476 * These two parameters are returned by copying them to into an array of
479 * Assumption: the attribute numbers and operator ObjectIds are in order
480 * WRT to each other (otherwise, you have no way of knowing which
481 * AM operator class or attribute number corresponds to which operator.
483 * 'varAttributeNumbers' contains attribute numbers for variables
484 * 'constValues' contains the constant values
485 * 'constFlags' describes how to treat the constants in each clause
486 * 'nIndexKeys' describes how many keys the index actually has
488 * Returns 'selectivityInfo' filled with the sum of all pages touched
489 * and the product of each clause's selectivity.
493 IndexSelectivity(Oid indexrelid,
496 Oid *AccessMethodOperatorClasses, /* XXX not used? */
497 Oid *operatorObjectIds,
498 int32 *varAttributeNumbers,
506 HeapTuple indexTuple,
518 float64data fattr_select = 1.0;
520 indRel = SearchSysCacheTuple(RELOID,
521 ObjectIdGetDatum(indexrelid),
523 if (!HeapTupleIsValid(indRel))
524 elog(ERROR, "IndexSelectivity: index %u not found",
526 relam = ((Form_pg_class) GETSTRUCT(indRel))->relam;
528 indexTuple = SearchSysCacheTuple(INDEXRELID,
529 ObjectIdGetDatum(indexrelid),
531 if (!HeapTupleIsValid(indexTuple))
532 elog(ERROR, "IndexSelectivity: index %u not found",
534 index = (Form_pg_index) GETSTRUCT(indexTuple);
537 * Hack for non-functional btree npages estimation: npages =
538 * index_pages * selectivity_of_1st_attr_clause(s) - vadim 04/24/97
540 if (relam == BTREE_AM_OID &&
541 varAttributeNumbers[0] != InvalidAttrNumber)
546 for (n = 0; n < nIndexKeys; ++n)
549 * Find the AM class for this key.
551 * If the first attribute number is invalid then we have a functional
552 * index, and AM class is the first one defined since functional
553 * indices have exactly one key.
555 indclass = (varAttributeNumbers[0] == InvalidAttrNumber) ?
556 index->indclass[0] : InvalidOid;
558 while ((i < nIndexKeys) && (indclass == InvalidOid))
560 if (varAttributeNumbers[n] == index->indkey[i])
562 indclass = index->indclass[i];
567 if (!OidIsValid(indclass))
571 * Presumably this means that we are using a functional index
572 * clause and so had no variable to match to the index key ...
573 * if not we are in trouble.
575 elog(NOTICE, "IndexSelectivity: no key %d in index %u",
576 varAttributeNumbers[n], indexrelid);
580 amopTuple = SearchSysCacheTuple(AMOPOPID,
581 ObjectIdGetDatum(indclass),
582 ObjectIdGetDatum(operatorObjectIds[n]),
583 ObjectIdGetDatum(relam),
585 if (!HeapTupleIsValid(amopTuple))
586 elog(ERROR, "IndexSelectivity: no amop %u %u",
587 indclass, operatorObjectIds[n]);
588 amop = (Form_pg_amop) GETSTRUCT(amopTuple);
592 amopnpages = (float64) fmgr(amop->amopnpages,
593 (char *) operatorObjectIds[n],
595 (char *) varAttributeNumbers[n],
596 (char *) constValues[n],
597 (char *) constFlags[n],
599 (char *) indexrelid);
602 * So cool guys! Npages for x > 10 and x < 20 is twice as
603 * npages for x > 10! - vadim 04/09/97
605 npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0;
606 if ((i = npages) < npages) /* ceil(npages)? */
609 npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0;
612 amopselect = (float64) fmgr(amop->amopselect,
613 (char *) operatorObjectIds[n],
615 (char *) varAttributeNumbers[n],
616 (char *) constValues[n],
617 (char *) constFlags[n],
619 (char *) indexrelid);
621 if (nphack && varAttributeNumbers[n] == index->indkey[0])
622 fattr_select *= PointerIsValid(amopselect) ? *amopselect : 1.0;
624 select *= PointerIsValid(amopselect) ? *amopselect : 1.0;
628 * Estimation of npages below is hack of course, but it's better than
629 * it was before. - vadim 04/09/97
633 npages = fattr_select * ((Form_pg_class) GETSTRUCT(indRel))->relpages;
634 *idxPages = ceil((double) npages);
639 npages = npages / (1.0 + nIndexKeys);
640 *idxPages = ceil((double) (npages / nIndexKeys));