1 /*-------------------------------------------------------------------------
4 * Selectivity functions for system catalogs and builtin types
6 * These routines are registered in the operator catalog in the
7 * "oprrest" and "oprjoin" attributes.
9 * XXX check all the functions--I suspect them to be 1-based.
11 * Copyright (c) 1994, Regents of the University of California
15 * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.17 1998/02/11 19:12:45 momjian Exp $
17 *-------------------------------------------------------------------------
24 #include "access/heapam.h"
26 #include "utils/builtins.h" /* for textout() prototype and where the
28 #include "utils/palloc.h"
30 #include "catalog/catname.h"
31 #include "utils/syscache.h"
32 #include "utils/lsyscache.h" /* for get_oprrest() */
33 #include "catalog/pg_statistic.h"
35 /* N is not a valid var/constant or relation id */
36 #define NONVALUE(N) ((N) == -1)
39 * generalize the test for functional index selectivity request
41 #define FunctionalSelectivity(nIndKeys,attNum) (attNum==InvalidAttrNumber)
43 static float32data getattdisbursion(Oid relid, AttrNumber attnum);
45 gethilokey(Oid relid, AttrNumber attnum, Oid opid,
46 char **high, char **low);
50 * eqsel - Selectivity of "=" for any data type.
61 result = (float64) palloc(sizeof(float64data));
62 if (NONVALUE(attno) || NONVALUE(relid))
65 *result = (float64data) getattdisbursion(relid, (int) attno);
70 * neqsel - Selectivity of "!=" for any data type.
81 result = eqsel(opid, relid, attno, value, flag);
82 *result = 1.0 - *result;
87 * intltsel - Selectivity of "<" for integers.
88 * Should work for both longs and shorts.
106 result = (float64) palloc(sizeof(float64data));
107 if (NONVALUE(attno) || NONVALUE(relid))
111 /* XXX val = atol(value); */
113 gethilokey(relid, (int) attno, opid, &highchar, &lowchar);
114 if (*highchar == 'n' || *lowchar == 'n')
119 high = atol(highchar);
121 if ((flag & SEL_RIGHT && val < low) ||
122 (!(flag & SEL_RIGHT) && val > high))
126 nvals = getattdisbursion(relid, (int) attno);
131 *result = 3.0 * (float64data) nvals;
141 if (flag & SEL_RIGHT)
151 *result = ((1.0 * top) / bottom);
159 * intgtsel - Selectivity of ">" for integers.
160 * Should work for both longs and shorts.
173 notflag = flag & ~SEL_RIGHT;
175 notflag = flag | SEL_RIGHT;
176 result = intltsel(opid, relid, attno, value, (int32) notflag);
181 * eqjoinsel - Join selectivity of "="
195 result = (float64) palloc(sizeof(float64data));
196 if (NONVALUE(attno1) || NONVALUE(relid1) ||
197 NONVALUE(attno2) || NONVALUE(relid2))
201 num1 = getattdisbursion(relid1, (int) attno1);
202 num2 = getattdisbursion(relid2, (int) attno2);
203 max = (num1 > num2) ? num1 : num2;
207 *result = (float64data) max;
213 * neqjoinsel - Join selectivity of "!="
224 result = eqjoinsel(opid, relid1, attno1, relid2, attno2);
225 *result = 1.0 - *result;
230 * intltjoinsel - Join selectivity of "<"
233 intltjoinsel(Oid opid,
241 result = (float64) palloc(sizeof(float64data));
247 * intgtjoinsel - Join selectivity of ">"
250 intgtjoinsel(Oid opid,
258 result = (float64) palloc(sizeof(float64data));
264 * getattdisbursion - Retrieves the number of values within an attribute.
267 * getattdisbursion and gethilokey both currently use keyed
268 * relation scans and amgetattr. Alternatively,
269 * the relation scan could be non-keyed and the tuple
270 * returned could be cast (struct X *) tuple + tuple->t_hoff.
271 * The first method is good for testing the implementation,
272 * but the second may ultimately be faster?!? In any case,
273 * using the cast instead of amgetattr would be
274 * more efficient. However, the cast will not work
275 * for gethilokey which accesses stahikey in struct statistic.
278 getattdisbursion(Oid relid, AttrNumber attnum)
284 atp = SearchSysCacheTuple(ATTNUM,
285 ObjectIdGetDatum(relid),
286 Int16GetDatum(attnum),
288 if (!HeapTupleIsValid(atp))
290 elog(ERROR, "getattdisbursion: no attribute tuple %d %d",
294 nvals = ((AttributeTupleForm) GETSTRUCT(atp))->attdisbursion;
298 atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(relid),
302 * XXX -- use number of tuples as number of distinctive values just
303 * for now, in case number of distinctive values is not cached
305 if (!HeapTupleIsValid(atp))
307 elog(ERROR, "getattdisbursion: no relation tuple %d", relid);
310 ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
311 /* Look above how nvals is used. - vadim 04/09/97 */
313 nvals = 1.0 / ntuples;
319 * gethilokey - Returns a pointer to strings containing
320 * the high and low keys within an attribute.
322 * Currently returns "0", and "0" in high and low if the statistic
323 * catalog does not contain the proper tuple. Eventually, the
324 * statistic demon should have the tuple maintained, and it should
325 * elog() if the tuple is missing.
327 * XXX Question: is this worth sticking in the catalog caches,
328 * or will this get invalidated too often?
331 gethilokey(Oid relid,
339 static ScanKeyData key[3] = {
340 {0, Anum_pg_statistic_starelid, F_OIDEQ, {0, 0, F_OIDEQ}},
341 {0, Anum_pg_statistic_staattnum, F_INT2EQ, {0, 0, F_INT2EQ}},
342 {0, Anum_pg_statistic_staop, F_OIDEQ, {0, 0, F_OIDEQ}}
347 rdesc = heap_openr(StatisticRelationName);
349 key[0].sk_argument = ObjectIdGetDatum(relid);
350 key[1].sk_argument = Int16GetDatum((int16) attnum);
351 key[2].sk_argument = ObjectIdGetDatum(opid);
352 sdesc = heap_beginscan(rdesc, 0, false, 3, key);
353 tuple = heap_getnext(sdesc, 0, (Buffer *) NULL);
354 if (!HeapTupleIsValid(tuple))
360 * XXX elog(ERROR, "gethilokey: statistic tuple not
365 *high = textout((struct varlena *)
367 Anum_pg_statistic_stahikey,
368 RelationGetTupleDescriptor(rdesc),
371 elog(DEBUG, "gethilokey: high key is null");
372 *low = textout((struct varlena *)
374 Anum_pg_statistic_stalokey,
375 RelationGetTupleDescriptor(rdesc),
378 elog(DEBUG, "gethilokey: low key is null");
384 btreesel(Oid operatorObjectId,
386 AttrNumber attributeNumber,
393 float64data resultData;
395 if (FunctionalSelectivity(nIndexKeys, attributeNumber))
399 * Need to call the functions selectivity function here. For now
400 * simply assume it's 1/3 since functions don't currently have
401 * selectivity functions
403 resultData = 1.0 / 3.0;
404 result = &resultData;
408 result = (float64) fmgr(get_oprrest(operatorObjectId),
409 (char *) operatorObjectId,
411 (char *) (int) attributeNumber,
417 if (!PointerIsValid(result))
418 elog(ERROR, "Btree Selectivity: bad pointer");
419 if (*result < 0.0 || *result > 1.0)
420 elog(ERROR, "Btree Selectivity: bad value %lf", *result);
426 btreenpage(Oid operatorObjectId,
428 AttrNumber attributeNumber,
436 float64data tempData;
440 if (FunctionalSelectivity(nIndexKeys, attributeNumber))
444 * Need to call the functions selectivity function here. For now
445 * simply assume it's 1/3 since functions don't currently have
446 * selectivity functions
448 tempData = 1.0 / 3.0;
453 temp = (float64) fmgr(get_oprrest(operatorObjectId),
454 (char *) operatorObjectId,
456 (char *) (int) attributeNumber,
461 atp = SearchSysCacheTuple(RELOID,
462 ObjectIdGetDatum(indexrelid),
464 if (!HeapTupleIsValid(atp))
466 elog(ERROR, "btreenpage: no index tuple %d", indexrelid);
470 npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
471 result = (float64) palloc(sizeof(float64data));
472 *result = *temp * npage;
477 hashsel(Oid operatorObjectId,
479 AttrNumber attributeNumber,
487 float64data resultData;
491 if (FunctionalSelectivity(nIndexKeys, attributeNumber))
495 * Need to call the functions selectivity function here. For now
496 * simply use 1/Number of Tuples since functions don't currently
497 * have selectivity functions
500 atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(indexrelid),
502 if (!HeapTupleIsValid(atp))
504 elog(ERROR, "hashsel: no index tuple %d", indexrelid);
507 ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
510 resultData = 1.0 / (float64data) ntuples;
514 resultData = (float64data) (1.0 / 100.0);
516 result = &resultData;
521 result = (float64) fmgr(get_oprrest(operatorObjectId),
522 (char *) operatorObjectId,
524 (char *) (int) attributeNumber,
530 if (!PointerIsValid(result))
531 elog(ERROR, "Hash Table Selectivity: bad pointer");
532 if (*result < 0.0 || *result > 1.0)
533 elog(ERROR, "Hash Table Selectivity: bad value %lf", *result);
541 hashnpage(Oid operatorObjectId,
543 AttrNumber attributeNumber,
551 float64data tempData;
556 atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(indexrelid),
558 if (!HeapTupleIsValid(atp))
560 elog(ERROR, "hashsel: no index tuple %d", indexrelid);
565 if (FunctionalSelectivity(nIndexKeys, attributeNumber))
569 * Need to call the functions selectivity function here. For now,
570 * use 1/Number of Tuples since functions don't currently have
571 * selectivity functions
574 ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
577 tempData = 1.0 / (float64data) ntuples;
581 tempData = (float64data) (1.0 / 100.0);
588 temp = (float64) fmgr(get_oprrest(operatorObjectId),
589 (char *) operatorObjectId,
591 (char *) (int) attributeNumber,
597 npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
598 result = (float64) palloc(sizeof(float64data));
599 *result = *temp * npage;
605 rtsel(Oid operatorObjectId,
607 AttrNumber attributeNumber,
613 return (btreesel(operatorObjectId, indrelid, attributeNumber,
614 constValue, constFlag, nIndexKeys, indexrelid));
618 rtnpage(Oid operatorObjectId,
620 AttrNumber attributeNumber,
626 return (btreenpage(operatorObjectId, indrelid, attributeNumber,
627 constValue, constFlag, nIndexKeys, indexrelid));
631 gistsel(Oid operatorObjectId,
633 AttrNumber attributeNumber,
639 return (btreesel(operatorObjectId, indrelid, attributeNumber,
640 constValue, constFlag, nIndexKeys, indexrelid));
644 gistnpage(Oid operatorObjectId,
646 AttrNumber attributeNumber,
652 return (btreenpage(operatorObjectId, indrelid, attributeNumber,
653 constValue, constFlag, nIndexKeys, indexrelid));