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.26 1999/03/18 19:59:55 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);
44 static void gethilokey(Oid relid, AttrNumber attnum, Oid opid,
45 char **high, char **low);
49 * eqsel - Selectivity of "=" for any data type.
60 result = (float64) palloc(sizeof(float64data));
61 if (NONVALUE(attno) || NONVALUE(relid))
64 *result = (float64data) getattdisbursion(relid, (int) attno);
69 * neqsel - Selectivity of "!=" for any data type.
80 result = eqsel(opid, relid, attno, value, flag);
81 *result = 1.0 - *result;
86 * intltsel - Selectivity of "<" for integers.
87 * Should work for both longs and shorts.
105 result = (float64) palloc(sizeof(float64data));
106 if (NONVALUE(attno) || NONVALUE(relid))
110 /* XXX val = atol(value); */
112 gethilokey(relid, (int) attno, opid, &highchar, &lowchar);
113 if (*highchar == 'n' || *lowchar == 'n')
118 high = atol(highchar);
120 if ((flag & SEL_RIGHT && val < low) ||
121 (!(flag & SEL_RIGHT) && val > high))
125 nvals = getattdisbursion(relid, (int) attno);
130 *result = 3.0 * (float64data) nvals;
140 if (flag & SEL_RIGHT)
150 *result = ((1.0 * top) / bottom);
158 * intgtsel - Selectivity of ">" for integers.
159 * Should work for both longs and shorts.
172 notflag = flag & ~SEL_RIGHT;
174 notflag = flag | SEL_RIGHT;
175 result = intltsel(opid, relid, attno, value, (int32) notflag);
180 * eqjoinsel - Join selectivity of "="
194 result = (float64) palloc(sizeof(float64data));
195 if (NONVALUE(attno1) || NONVALUE(relid1) ||
196 NONVALUE(attno2) || NONVALUE(relid2))
200 num1 = getattdisbursion(relid1, (int) attno1);
201 num2 = getattdisbursion(relid2, (int) attno2);
202 max = (num1 > num2) ? num1 : num2;
206 *result = (float64data) max;
212 * neqjoinsel - Join selectivity of "!="
223 result = eqjoinsel(opid, relid1, attno1, relid2, attno2);
224 *result = 1.0 - *result;
229 * intltjoinsel - Join selectivity of "<"
232 intltjoinsel(Oid opid,
240 result = (float64) palloc(sizeof(float64data));
246 * intgtjoinsel - Join selectivity of ">"
249 intgtjoinsel(Oid opid,
257 result = (float64) palloc(sizeof(float64data));
263 * getattdisbursion - Retrieves the number of values within an attribute.
266 * getattdisbursion and gethilokey both currently use keyed
267 * relation scans and amgetattr. Alternatively,
268 * the relation scan could be non-keyed and the tuple
269 * returned could be cast (struct X *) tuple + tuple->t_hoff.
270 * The first method is good for testing the implementation,
271 * but the second may ultimately be faster?!? In any case,
272 * using the cast instead of amgetattr would be
273 * more efficient. However, the cast will not work
274 * for gethilokey which accesses stahikey in struct statistic.
277 getattdisbursion(Oid relid, AttrNumber attnum)
283 atp = SearchSysCacheTuple(ATTNUM,
284 ObjectIdGetDatum(relid),
285 Int16GetDatum(attnum),
287 if (!HeapTupleIsValid(atp))
289 elog(ERROR, "getattdisbursion: no attribute tuple %d %d",
293 nvals = ((Form_pg_attribute) GETSTRUCT(atp))->attdisbursion;
297 atp = SearchSysCacheTuple(RELOID,
298 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 rel = 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 scan = heap_beginscan(rel, 0, SnapshotNow, 3, key);
353 tuple = heap_getnext(scan, 0);
354 if (!HeapTupleIsValid(tuple))
360 * XXX elog(ERROR, "gethilokey: statistic tuple not
365 *high = textout((struct varlena *)
367 Anum_pg_statistic_stahikey,
368 RelationGetDescr(rel),
371 elog(DEBUG, "gethilokey: high key is null");
372 *low = textout((struct varlena *)
374 Anum_pg_statistic_stalokey,
375 RelationGetDescr(rel),
378 elog(DEBUG, "gethilokey: low key is null");
384 btreesel(Oid operatorObjectId,
386 AttrNumber attributeNumber,
394 if (FunctionalSelectivity(nIndexKeys, attributeNumber))
397 * Need to call the functions selectivity function here. For now
398 * simply assume it's 1/3 since functions don't currently have
399 * selectivity functions
401 result = (float64) palloc(sizeof(float64data));
406 result = (float64) fmgr(get_oprrest(operatorObjectId),
407 (char *) operatorObjectId,
409 (char *) (int) attributeNumber,
415 if (!PointerIsValid(result))
416 elog(ERROR, "Btree Selectivity: bad pointer");
417 if (*result < 0.0 || *result > 1.0)
418 elog(ERROR, "Btree Selectivity: bad value %lf", *result);
424 btreenpage(Oid operatorObjectId,
426 AttrNumber attributeNumber,
434 float64data tempData;
438 if (FunctionalSelectivity(nIndexKeys, attributeNumber))
441 * Need to call the functions selectivity function here. For now
442 * simply assume it's 1/3 since functions don't currently have
443 * selectivity functions
445 tempData = 1.0 / 3.0;
450 temp = (float64) fmgr(get_oprrest(operatorObjectId),
451 (char *) operatorObjectId,
453 (char *) (int) attributeNumber,
458 atp = SearchSysCacheTuple(RELOID,
459 ObjectIdGetDatum(indexrelid),
461 if (!HeapTupleIsValid(atp))
463 elog(ERROR, "btreenpage: no index tuple %d", indexrelid);
467 npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
468 result = (float64) palloc(sizeof(float64data));
469 *result = *temp * npage;
474 hashsel(Oid operatorObjectId,
476 AttrNumber attributeNumber,
484 float64data resultData;
488 if (FunctionalSelectivity(nIndexKeys, attributeNumber))
492 * Need to call the functions selectivity function here. For now
493 * simply use 1/Number of Tuples since functions don't currently
494 * have selectivity functions
497 atp = SearchSysCacheTuple(RELOID,
498 ObjectIdGetDatum(indexrelid),
500 if (!HeapTupleIsValid(atp))
502 elog(ERROR, "hashsel: no index tuple %d", indexrelid);
505 ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
507 resultData = 1.0 / (float64data) ntuples;
509 resultData = (float64data) (1.0 / 100.0);
510 result = &resultData;
515 result = (float64) fmgr(get_oprrest(operatorObjectId),
516 (char *) operatorObjectId,
518 (char *) (int) attributeNumber,
524 if (!PointerIsValid(result))
525 elog(ERROR, "Hash Table Selectivity: bad pointer");
526 if (*result < 0.0 || *result > 1.0)
527 elog(ERROR, "Hash Table Selectivity: bad value %lf", *result);
535 hashnpage(Oid operatorObjectId,
537 AttrNumber attributeNumber,
545 float64data tempData;
550 atp = SearchSysCacheTuple(RELOID,
551 ObjectIdGetDatum(indexrelid),
553 if (!HeapTupleIsValid(atp))
555 elog(ERROR, "hashsel: no index tuple %d", indexrelid);
560 if (FunctionalSelectivity(nIndexKeys, attributeNumber))
564 * Need to call the functions selectivity function here. For now,
565 * use 1/Number of Tuples since functions don't currently have
566 * selectivity functions
569 ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
571 tempData = 1.0 / (float64data) ntuples;
573 tempData = (float64data) (1.0 / 100.0);
579 temp = (float64) fmgr(get_oprrest(operatorObjectId),
580 (char *) operatorObjectId,
582 (char *) (int) attributeNumber,
588 npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
589 result = (float64) palloc(sizeof(float64data));
590 *result = *temp * npage;
596 rtsel(Oid operatorObjectId,
598 AttrNumber attributeNumber,
604 return (btreesel(operatorObjectId, indrelid, attributeNumber,
605 constValue, constFlag, nIndexKeys, indexrelid));
609 rtnpage(Oid operatorObjectId,
611 AttrNumber attributeNumber,
617 return (btreenpage(operatorObjectId, indrelid, attributeNumber,
618 constValue, constFlag, nIndexKeys, indexrelid));
622 gistsel(Oid operatorObjectId,
624 AttrNumber attributeNumber,
630 return (btreesel(operatorObjectId, indrelid, attributeNumber,
631 constValue, constFlag, nIndexKeys, indexrelid));
635 gistnpage(Oid operatorObjectId,
637 AttrNumber attributeNumber,
643 return (btreenpage(operatorObjectId, indrelid, attributeNumber,
644 constValue, constFlag, nIndexKeys, indexrelid));