]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/selfuncs.c
Goodbye register keyword. Compiler knows better.
[postgresql] / src / backend / utils / adt / selfuncs.c
1 /*-------------------------------------------------------------------------
2  *
3  * selfuncs.c--
4  *        Selectivity functions for system catalogs and builtin types
5  *
6  *        These routines are registered in the operator catalog in the
7  *        "oprrest" and "oprjoin" attributes.
8  *
9  *        XXX check all the functions--I suspect them to be 1-based.
10  *
11  * Copyright (c) 1994, Regents of the University of California
12  *
13  *
14  * IDENTIFICATION
15  *        $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.17 1998/02/11 19:12:45 momjian Exp $
16  *
17  *-------------------------------------------------------------------------
18  */
19 #include <stdio.h>
20 #include <string.h>
21
22 #include "postgres.h"
23
24 #include "access/heapam.h"
25 #include "fmgr.h"
26 #include "utils/builtins.h"             /* for textout() prototype and where the
27                                                                  * declarations go */
28 #include "utils/palloc.h"
29
30 #include "catalog/catname.h"
31 #include "utils/syscache.h"
32 #include "utils/lsyscache.h"    /* for get_oprrest() */
33 #include "catalog/pg_statistic.h"
34
35 /* N is not a valid var/constant or relation id */
36 #define NONVALUE(N)             ((N) == -1)
37
38 /*
39  * generalize the test for functional index selectivity request
40  */
41 #define FunctionalSelectivity(nIndKeys,attNum) (attNum==InvalidAttrNumber)
42
43 static float32data getattdisbursion(Oid relid, AttrNumber attnum);
44 static void
45 gethilokey(Oid relid, AttrNumber attnum, Oid opid,
46                    char **high, char **low);
47
48
49 /*
50  *              eqsel                   - Selectivity of "=" for any data type.
51  */
52 float64
53 eqsel(Oid opid,
54           Oid relid,
55           AttrNumber attno,
56           char *value,
57           int32 flag)
58 {
59         float64         result;
60
61         result = (float64) palloc(sizeof(float64data));
62         if (NONVALUE(attno) || NONVALUE(relid))
63                 *result = 0.1;
64         else
65                 *result = (float64data) getattdisbursion(relid, (int) attno);
66         return (result);
67 }
68
69 /*
70  *              neqsel                  - Selectivity of "!=" for any data type.
71  */
72 float64
73 neqsel(Oid opid,
74            Oid relid,
75            AttrNumber attno,
76            char *value,
77            int32 flag)
78 {
79         float64         result;
80
81         result = eqsel(opid, relid, attno, value, flag);
82         *result = 1.0 - *result;
83         return (result);
84 }
85
86 /*
87  *              intltsel                - Selectivity of "<" for integers.
88  *                                                Should work for both longs and shorts.
89  */
90 float64
91 intltsel(Oid opid,
92                  Oid relid,
93                  AttrNumber attno,
94                  int32 value,
95                  int32 flag)
96 {
97         float64         result;
98         char       *highchar,
99                            *lowchar;
100         long            val,
101                                 high,
102                                 low,
103                                 top,
104                                 bottom;
105
106         result = (float64) palloc(sizeof(float64data));
107         if (NONVALUE(attno) || NONVALUE(relid))
108                 *result = 1.0 / 3;
109         else
110         {
111                 /* XXX                  val = atol(value); */
112                 val = value;
113                 gethilokey(relid, (int) attno, opid, &highchar, &lowchar);
114                 if (*highchar == 'n' || *lowchar == 'n')
115                 {
116                         *result = 1.0 / 3.0;
117                         return (result);
118                 }
119                 high = atol(highchar);
120                 low = atol(lowchar);
121                 if ((flag & SEL_RIGHT && val < low) ||
122                         (!(flag & SEL_RIGHT) && val > high))
123                 {
124                         float32data nvals;
125
126                         nvals = getattdisbursion(relid, (int) attno);
127                         if (nvals == 0)
128                                 *result = 1.0 / 3.0;
129                         else
130                         {
131                                 *result = 3.0 * (float64data) nvals;
132                                 if (*result > 1.0)
133                                         *result = 1;
134                         }
135                 }
136                 else
137                 {
138                         bottom = high - low;
139                         if (bottom == 0)
140                                 ++bottom;
141                         if (flag & SEL_RIGHT)
142                                 top = val - low;
143                         else
144                                 top = high - val;
145                         if (top > bottom)
146                                 *result = 1.0;
147                         else
148                         {
149                                 if (top == 0)
150                                         ++top;
151                                 *result = ((1.0 * top) / bottom);
152                         }
153                 }
154         }
155         return (result);
156 }
157
158 /*
159  *              intgtsel                - Selectivity of ">" for integers.
160  *                                                Should work for both longs and shorts.
161  */
162 float64
163 intgtsel(Oid opid,
164                  Oid relid,
165                  AttrNumber attno,
166                  int32 value,
167                  int32 flag)
168 {
169         float64         result;
170         int                     notflag;
171
172         if (flag & 0)
173                 notflag = flag & ~SEL_RIGHT;
174         else
175                 notflag = flag | SEL_RIGHT;
176         result = intltsel(opid, relid, attno, value, (int32) notflag);
177         return (result);
178 }
179
180 /*
181  *              eqjoinsel               - Join selectivity of "="
182  */
183 float64
184 eqjoinsel(Oid opid,
185                   Oid relid1,
186                   AttrNumber attno1,
187                   Oid relid2,
188                   AttrNumber attno2)
189 {
190         float64         result;
191         float32data num1,
192                                 num2,
193                                 max;
194
195         result = (float64) palloc(sizeof(float64data));
196         if (NONVALUE(attno1) || NONVALUE(relid1) ||
197                 NONVALUE(attno2) || NONVALUE(relid2))
198                 *result = 0.1;
199         else
200         {
201                 num1 = getattdisbursion(relid1, (int) attno1);
202                 num2 = getattdisbursion(relid2, (int) attno2);
203                 max = (num1 > num2) ? num1 : num2;
204                 if (max == 0)
205                         *result = 1.0;
206                 else
207                         *result = (float64data) max;
208         }
209         return (result);
210 }
211
212 /*
213  *              neqjoinsel              - Join selectivity of "!="
214  */
215 float64
216 neqjoinsel(Oid opid,
217                    Oid relid1,
218                    AttrNumber attno1,
219                    Oid relid2,
220                    AttrNumber attno2)
221 {
222         float64         result;
223
224         result = eqjoinsel(opid, relid1, attno1, relid2, attno2);
225         *result = 1.0 - *result;
226         return (result);
227 }
228
229 /*
230  *              intltjoinsel    - Join selectivity of "<"
231  */
232 float64
233 intltjoinsel(Oid opid,
234                          Oid relid1,
235                          AttrNumber attno1,
236                          Oid relid2,
237                          AttrNumber attno2)
238 {
239         float64         result;
240
241         result = (float64) palloc(sizeof(float64data));
242         *result = 1.0 / 3.0;
243         return (result);
244 }
245
246 /*
247  *              intgtjoinsel    - Join selectivity of ">"
248  */
249 float64
250 intgtjoinsel(Oid opid,
251                          Oid relid1,
252                          AttrNumber attno1,
253                          Oid relid2,
254                          AttrNumber attno2)
255 {
256         float64         result;
257
258         result = (float64) palloc(sizeof(float64data));
259         *result = 1.0 / 3.0;
260         return (result);
261 }
262
263 /*
264  *              getattdisbursion                - Retrieves the number of values within an attribute.
265  *
266  *              Note:
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.
276  */
277 static float32data
278 getattdisbursion(Oid relid, AttrNumber attnum)
279 {
280         HeapTuple       atp;
281         float32data nvals;
282         int32           ntuples;
283
284         atp = SearchSysCacheTuple(ATTNUM,
285                                                           ObjectIdGetDatum(relid),
286                                                           Int16GetDatum(attnum),
287                                                           0, 0);
288         if (!HeapTupleIsValid(atp))
289         {
290                 elog(ERROR, "getattdisbursion: no attribute tuple %d %d",
291                          relid, attnum);
292                 return (0);
293         }
294         nvals = ((AttributeTupleForm) GETSTRUCT(atp))->attdisbursion;
295         if (nvals > 0)
296                 return (nvals);
297
298         atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(relid),
299                                                           0, 0, 0);
300
301         /*
302          * XXX -- use number of tuples as number of distinctive values just
303          * for now, in case number of distinctive values is not cached
304          */
305         if (!HeapTupleIsValid(atp))
306         {
307                 elog(ERROR, "getattdisbursion: no relation tuple %d", relid);
308                 return (0);
309         }
310         ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
311         /* Look above how nvals is used.        - vadim 04/09/97 */
312         if (ntuples > 0)
313                 nvals = 1.0 / ntuples;
314
315         return (nvals);
316 }
317
318 /*
319  *              gethilokey              - Returns a pointer to strings containing
320  *                                                the high and low keys within an attribute.
321  *
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.
326  *
327  *              XXX Question: is this worth sticking in the catalog caches,
328  *                      or will this get invalidated too often?
329  */
330 static void
331 gethilokey(Oid relid,
332                    AttrNumber attnum,
333                    Oid opid,
334                    char **high,
335                    char **low)
336 {
337         Relation rdesc;
338         HeapScanDesc sdesc;
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}}
343         };
344         bool            isnull;
345         HeapTuple       tuple;
346
347         rdesc = heap_openr(StatisticRelationName);
348
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))
355         {
356                 *high = "n";
357                 *low = "n";
358
359                 /*
360                  * XXX                  elog(ERROR, "gethilokey: statistic tuple not
361                  * found");
362                  */
363                 return;
364         }
365         *high = textout((struct varlena *)
366                                         heap_getattr(tuple,
367                                                                  Anum_pg_statistic_stahikey,
368                                                                  RelationGetTupleDescriptor(rdesc),
369                                                                  &isnull));
370         if (isnull)
371                 elog(DEBUG, "gethilokey: high key is null");
372         *low = textout((struct varlena *)
373                                    heap_getattr(tuple,
374                                                                 Anum_pg_statistic_stalokey,
375                                                                 RelationGetTupleDescriptor(rdesc),
376                                                                 &isnull));
377         if (isnull)
378                 elog(DEBUG, "gethilokey: low key is null");
379         heap_endscan(sdesc);
380         heap_close(rdesc);
381 }
382
383 float64
384 btreesel(Oid operatorObjectId,
385                  Oid indrelid,
386                  AttrNumber attributeNumber,
387                  char *constValue,
388                  int32 constFlag,
389                  int32 nIndexKeys,
390                  Oid indexrelid)
391 {
392         float64         result;
393         float64data resultData;
394
395         if (FunctionalSelectivity(nIndexKeys, attributeNumber))
396         {
397
398                 /*
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
402                  */
403                 resultData = 1.0 / 3.0;
404                 result = &resultData;
405         }
406         else
407         {
408                 result = (float64) fmgr(get_oprrest(operatorObjectId),
409                                                                 (char *) operatorObjectId,
410                                                                 (char *) indrelid,
411                                                                 (char *) (int) attributeNumber,
412                                                                 (char *) constValue,
413                                                                 (char *) constFlag,
414                                                                 NULL);
415         }
416
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);
421
422         return (result);
423 }
424
425 float64
426 btreenpage(Oid operatorObjectId,
427                    Oid indrelid,
428                    AttrNumber attributeNumber,
429                    char *constValue,
430                    int32 constFlag,
431                    int32 nIndexKeys,
432                    Oid indexrelid)
433 {
434         float64         temp,
435                                 result;
436         float64data tempData;
437         HeapTuple       atp;
438         int                     npage;
439
440         if (FunctionalSelectivity(nIndexKeys, attributeNumber))
441         {
442
443                 /*
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
447                  */
448                 tempData = 1.0 / 3.0;
449                 temp = &tempData;
450         }
451         else
452         {
453                 temp = (float64) fmgr(get_oprrest(operatorObjectId),
454                                                           (char *) operatorObjectId,
455                                                           (char *) indrelid,
456                                                           (char *) (int) attributeNumber,
457                                                           (char *) constValue,
458                                                           (char *) constFlag,
459                                                           NULL);
460         }
461         atp = SearchSysCacheTuple(RELOID,
462                                                           ObjectIdGetDatum(indexrelid),
463                                                           0, 0, 0);
464         if (!HeapTupleIsValid(atp))
465         {
466                 elog(ERROR, "btreenpage: no index tuple %d", indexrelid);
467                 return (0);
468         }
469
470         npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
471         result = (float64) palloc(sizeof(float64data));
472         *result = *temp * npage;
473         return (result);
474 }
475
476 float64
477 hashsel(Oid operatorObjectId,
478                 Oid indrelid,
479                 AttrNumber attributeNumber,
480                 char *constValue,
481                 int32 constFlag,
482                 int32 nIndexKeys,
483                 Oid indexrelid)
484 {
485
486         float64         result;
487         float64data resultData;
488         HeapTuple       atp;
489         int                     ntuples;
490
491         if (FunctionalSelectivity(nIndexKeys, attributeNumber))
492         {
493
494                 /*
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
498                  */
499
500                 atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(indexrelid),
501                                                                   0, 0, 0);
502                 if (!HeapTupleIsValid(atp))
503                 {
504                         elog(ERROR, "hashsel: no index tuple %d", indexrelid);
505                         return (0);
506                 }
507                 ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
508                 if (ntuples > 0)
509                 {
510                         resultData = 1.0 / (float64data) ntuples;
511                 }
512                 else
513                 {
514                         resultData = (float64data) (1.0 / 100.0);
515                 }
516                 result = &resultData;
517
518         }
519         else
520         {
521                 result = (float64) fmgr(get_oprrest(operatorObjectId),
522                                                                 (char *) operatorObjectId,
523                                                                 (char *) indrelid,
524                                                                 (char *) (int) attributeNumber,
525                                                                 (char *) constValue,
526                                                                 (char *) constFlag,
527                                                                 NULL);
528         }
529
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);
534
535         return (result);
536
537
538 }
539
540 float64
541 hashnpage(Oid operatorObjectId,
542                   Oid indrelid,
543                   AttrNumber attributeNumber,
544                   char *constValue,
545                   int32 constFlag,
546                   int32 nIndexKeys,
547                   Oid indexrelid)
548 {
549         float64         temp,
550                                 result;
551         float64data tempData;
552         HeapTuple       atp;
553         int                     npage;
554         int                     ntuples;
555
556         atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(indexrelid),
557                                                           0, 0, 0);
558         if (!HeapTupleIsValid(atp))
559         {
560                 elog(ERROR, "hashsel: no index tuple %d", indexrelid);
561                 return (0);
562         }
563
564
565         if (FunctionalSelectivity(nIndexKeys, attributeNumber))
566         {
567
568                 /*
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
572                  */
573
574                 ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
575                 if (ntuples > 0)
576                 {
577                         tempData = 1.0 / (float64data) ntuples;
578                 }
579                 else
580                 {
581                         tempData = (float64data) (1.0 / 100.0);
582                 }
583                 temp = &tempData;
584
585         }
586         else
587         {
588                 temp = (float64) fmgr(get_oprrest(operatorObjectId),
589                                                           (char *) operatorObjectId,
590                                                           (char *) indrelid,
591                                                           (char *) (int) attributeNumber,
592                                                           (char *) constValue,
593                                                           (char *) constFlag,
594                                                           NULL);
595         }
596
597         npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
598         result = (float64) palloc(sizeof(float64data));
599         *result = *temp * npage;
600         return (result);
601 }
602
603
604 float64
605 rtsel(Oid operatorObjectId,
606           Oid indrelid,
607           AttrNumber attributeNumber,
608           char *constValue,
609           int32 constFlag,
610           int32 nIndexKeys,
611           Oid indexrelid)
612 {
613         return (btreesel(operatorObjectId, indrelid, attributeNumber,
614                                          constValue, constFlag, nIndexKeys, indexrelid));
615 }
616
617 float64
618 rtnpage(Oid operatorObjectId,
619                 Oid indrelid,
620                 AttrNumber attributeNumber,
621                 char *constValue,
622                 int32 constFlag,
623                 int32 nIndexKeys,
624                 Oid indexrelid)
625 {
626         return (btreenpage(operatorObjectId, indrelid, attributeNumber,
627                                            constValue, constFlag, nIndexKeys, indexrelid));
628 }
629
630 float64
631 gistsel(Oid operatorObjectId,
632                 Oid indrelid,
633                 AttrNumber attributeNumber,
634                 char *constValue,
635                 int32 constFlag,
636                 int32 nIndexKeys,
637                 Oid indexrelid)
638 {
639         return (btreesel(operatorObjectId, indrelid, attributeNumber,
640                                          constValue, constFlag, nIndexKeys, indexrelid));
641 }
642
643 float64
644 gistnpage(Oid operatorObjectId,
645                   Oid indrelid,
646                   AttrNumber attributeNumber,
647                   char *constValue,
648                   int32 constFlag,
649                   int32 nIndexKeys,
650                   Oid indexrelid)
651 {
652         return (btreenpage(operatorObjectId, indrelid, attributeNumber,
653                                            constValue, constFlag, nIndexKeys, indexrelid));
654 }