OSDN Git Service

f7026ba158fef6e561444a1d0cc7a10e1f611deb
[pg-rex/syncrep.git] / 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.26 1999/03/18 19:59:55 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 gethilokey(Oid relid, AttrNumber attnum, Oid opid,
45                    char **high, char **low);
46
47
48 /*
49  *              eqsel                   - Selectivity of "=" for any data type.
50  */
51 float64
52 eqsel(Oid opid,
53           Oid relid,
54           AttrNumber attno,
55           char *value,
56           int32 flag)
57 {
58         float64         result;
59
60         result = (float64) palloc(sizeof(float64data));
61         if (NONVALUE(attno) || NONVALUE(relid))
62                 *result = 0.1;
63         else
64                 *result = (float64data) getattdisbursion(relid, (int) attno);
65         return result;
66 }
67
68 /*
69  *              neqsel                  - Selectivity of "!=" for any data type.
70  */
71 float64
72 neqsel(Oid opid,
73            Oid relid,
74            AttrNumber attno,
75            char *value,
76            int32 flag)
77 {
78         float64         result;
79
80         result = eqsel(opid, relid, attno, value, flag);
81         *result = 1.0 - *result;
82         return result;
83 }
84
85 /*
86  *              intltsel                - Selectivity of "<" for integers.
87  *                                                Should work for both longs and shorts.
88  */
89 float64
90 intltsel(Oid opid,
91                  Oid relid,
92                  AttrNumber attno,
93                  int32 value,
94                  int32 flag)
95 {
96         float64         result;
97         char       *highchar,
98                            *lowchar;
99         long            val,
100                                 high,
101                                 low,
102                                 top,
103                                 bottom;
104
105         result = (float64) palloc(sizeof(float64data));
106         if (NONVALUE(attno) || NONVALUE(relid))
107                 *result = 1.0 / 3;
108         else
109         {
110                 /* XXX                  val = atol(value); */
111                 val = value;
112                 gethilokey(relid, (int) attno, opid, &highchar, &lowchar);
113                 if (*highchar == 'n' || *lowchar == 'n')
114                 {
115                         *result = 1.0 / 3.0;
116                         return result;
117                 }
118                 high = atol(highchar);
119                 low = atol(lowchar);
120                 if ((flag & SEL_RIGHT && val < low) ||
121                         (!(flag & SEL_RIGHT) && val > high))
122                 {
123                         float32data nvals;
124
125                         nvals = getattdisbursion(relid, (int) attno);
126                         if (nvals == 0)
127                                 *result = 1.0 / 3.0;
128                         else
129                         {
130                                 *result = 3.0 * (float64data) nvals;
131                                 if (*result > 1.0)
132                                         *result = 1;
133                         }
134                 }
135                 else
136                 {
137                         bottom = high - low;
138                         if (bottom == 0)
139                                 ++bottom;
140                         if (flag & SEL_RIGHT)
141                                 top = val - low;
142                         else
143                                 top = high - val;
144                         if (top > bottom)
145                                 *result = 1.0;
146                         else
147                         {
148                                 if (top == 0)
149                                         ++top;
150                                 *result = ((1.0 * top) / bottom);
151                         }
152                 }
153         }
154         return result;
155 }
156
157 /*
158  *              intgtsel                - Selectivity of ">" for integers.
159  *                                                Should work for both longs and shorts.
160  */
161 float64
162 intgtsel(Oid opid,
163                  Oid relid,
164                  AttrNumber attno,
165                  int32 value,
166                  int32 flag)
167 {
168         float64         result;
169         int                     notflag;
170
171         if (flag & 0)
172                 notflag = flag & ~SEL_RIGHT;
173         else
174                 notflag = flag | SEL_RIGHT;
175         result = intltsel(opid, relid, attno, value, (int32) notflag);
176         return result;
177 }
178
179 /*
180  *              eqjoinsel               - Join selectivity of "="
181  */
182 float64
183 eqjoinsel(Oid opid,
184                   Oid relid1,
185                   AttrNumber attno1,
186                   Oid relid2,
187                   AttrNumber attno2)
188 {
189         float64         result;
190         float32data num1,
191                                 num2,
192                                 max;
193
194         result = (float64) palloc(sizeof(float64data));
195         if (NONVALUE(attno1) || NONVALUE(relid1) ||
196                 NONVALUE(attno2) || NONVALUE(relid2))
197                 *result = 0.1;
198         else
199         {
200                 num1 = getattdisbursion(relid1, (int) attno1);
201                 num2 = getattdisbursion(relid2, (int) attno2);
202                 max = (num1 > num2) ? num1 : num2;
203                 if (max == 0)
204                         *result = 1.0;
205                 else
206                         *result = (float64data) max;
207         }
208         return result;
209 }
210
211 /*
212  *              neqjoinsel              - Join selectivity of "!="
213  */
214 float64
215 neqjoinsel(Oid opid,
216                    Oid relid1,
217                    AttrNumber attno1,
218                    Oid relid2,
219                    AttrNumber attno2)
220 {
221         float64         result;
222
223         result = eqjoinsel(opid, relid1, attno1, relid2, attno2);
224         *result = 1.0 - *result;
225         return result;
226 }
227
228 /*
229  *              intltjoinsel    - Join selectivity of "<"
230  */
231 float64
232 intltjoinsel(Oid opid,
233                          Oid relid1,
234                          AttrNumber attno1,
235                          Oid relid2,
236                          AttrNumber attno2)
237 {
238         float64         result;
239
240         result = (float64) palloc(sizeof(float64data));
241         *result = 1.0 / 3.0;
242         return result;
243 }
244
245 /*
246  *              intgtjoinsel    - Join selectivity of ">"
247  */
248 float64
249 intgtjoinsel(Oid opid,
250                          Oid relid1,
251                          AttrNumber attno1,
252                          Oid relid2,
253                          AttrNumber attno2)
254 {
255         float64         result;
256
257         result = (float64) palloc(sizeof(float64data));
258         *result = 1.0 / 3.0;
259         return result;
260 }
261
262 /*
263  *              getattdisbursion                - Retrieves the number of values within an attribute.
264  *
265  *              Note:
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.
275  */
276 static float32data
277 getattdisbursion(Oid relid, AttrNumber attnum)
278 {
279         HeapTuple       atp;
280         float32data nvals;
281         int32           ntuples;
282
283         atp = SearchSysCacheTuple(ATTNUM,
284                                                           ObjectIdGetDatum(relid),
285                                                           Int16GetDatum(attnum),
286                                                           0, 0);
287         if (!HeapTupleIsValid(atp))
288         {
289                 elog(ERROR, "getattdisbursion: no attribute tuple %d %d",
290                          relid, attnum);
291                 return 0;
292         }
293         nvals = ((Form_pg_attribute) GETSTRUCT(atp))->attdisbursion;
294         if (nvals > 0)
295                 return nvals;
296
297         atp = SearchSysCacheTuple(RELOID,
298                                                           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        rel;
338         HeapScanDesc scan;
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         rel = 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         scan = heap_beginscan(rel, 0, SnapshotNow, 3, key);
353         tuple = heap_getnext(scan, 0);
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                                                                  RelationGetDescr(rel),
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                                                                 RelationGetDescr(rel),
376                                                                 &isnull));
377         if (isnull)
378                 elog(DEBUG, "gethilokey: low key is null");
379         heap_endscan(scan);
380         heap_close(rel);
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
394         if (FunctionalSelectivity(nIndexKeys, attributeNumber))
395         {
396                 /*
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
400                  */
401                 result = (float64) palloc(sizeof(float64data));
402                 *result = 1.0 / 3.0;
403         }
404         else
405         {
406                 result = (float64) fmgr(get_oprrest(operatorObjectId),
407                                                                 (char *) operatorObjectId,
408                                                                 (char *) indrelid,
409                                                                 (char *) (int) attributeNumber,
410                                                                 (char *) constValue,
411                                                                 (char *) constFlag,
412                                                                 NULL);
413         }
414
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);
419
420         return result;
421 }
422
423 float64
424 btreenpage(Oid operatorObjectId,
425                    Oid indrelid,
426                    AttrNumber attributeNumber,
427                    char *constValue,
428                    int32 constFlag,
429                    int32 nIndexKeys,
430                    Oid indexrelid)
431 {
432         float64         temp,
433                                 result;
434         float64data tempData;
435         HeapTuple       atp;
436         int                     npage;
437
438         if (FunctionalSelectivity(nIndexKeys, attributeNumber))
439         {
440                 /*
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
444                  */
445                 tempData = 1.0 / 3.0;
446                 temp = &tempData;
447         }
448         else
449         {
450                 temp = (float64) fmgr(get_oprrest(operatorObjectId),
451                                                           (char *) operatorObjectId,
452                                                           (char *) indrelid,
453                                                           (char *) (int) attributeNumber,
454                                                           (char *) constValue,
455                                                           (char *) constFlag,
456                                                           NULL);
457         }
458         atp = SearchSysCacheTuple(RELOID,
459                                                           ObjectIdGetDatum(indexrelid),
460                                                           0, 0, 0);
461         if (!HeapTupleIsValid(atp))
462         {
463                 elog(ERROR, "btreenpage: no index tuple %d", indexrelid);
464                 return 0;
465         }
466
467         npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
468         result = (float64) palloc(sizeof(float64data));
469         *result = *temp * npage;
470         return result;
471 }
472
473 float64
474 hashsel(Oid operatorObjectId,
475                 Oid indrelid,
476                 AttrNumber attributeNumber,
477                 char *constValue,
478                 int32 constFlag,
479                 int32 nIndexKeys,
480                 Oid indexrelid)
481 {
482
483         float64         result;
484         float64data resultData;
485         HeapTuple       atp;
486         int                     ntuples;
487
488         if (FunctionalSelectivity(nIndexKeys, attributeNumber))
489         {
490
491                 /*
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
495                  */
496
497                 atp = SearchSysCacheTuple(RELOID,
498                                                                   ObjectIdGetDatum(indexrelid),
499                                                                   0, 0, 0);
500                 if (!HeapTupleIsValid(atp))
501                 {
502                         elog(ERROR, "hashsel: no index tuple %d", indexrelid);
503                         return 0;
504                 }
505                 ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
506                 if (ntuples > 0)
507                         resultData = 1.0 / (float64data) ntuples;
508                 else
509                         resultData = (float64data) (1.0 / 100.0);
510                 result = &resultData;
511
512         }
513         else
514         {
515                 result = (float64) fmgr(get_oprrest(operatorObjectId),
516                                                                 (char *) operatorObjectId,
517                                                                 (char *) indrelid,
518                                                                 (char *) (int) attributeNumber,
519                                                                 (char *) constValue,
520                                                                 (char *) constFlag,
521                                                                 NULL);
522         }
523
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);
528
529         return result;
530
531
532 }
533
534 float64
535 hashnpage(Oid operatorObjectId,
536                   Oid indrelid,
537                   AttrNumber attributeNumber,
538                   char *constValue,
539                   int32 constFlag,
540                   int32 nIndexKeys,
541                   Oid indexrelid)
542 {
543         float64         temp,
544                                 result;
545         float64data tempData;
546         HeapTuple       atp;
547         int                     npage;
548         int                     ntuples;
549
550         atp = SearchSysCacheTuple(RELOID,
551                                                           ObjectIdGetDatum(indexrelid),
552                                                           0, 0, 0);
553         if (!HeapTupleIsValid(atp))
554         {
555                 elog(ERROR, "hashsel: no index tuple %d", indexrelid);
556                 return 0;
557         }
558
559
560         if (FunctionalSelectivity(nIndexKeys, attributeNumber))
561         {
562
563                 /*
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
567                  */
568
569                 ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
570                 if (ntuples > 0)
571                         tempData = 1.0 / (float64data) ntuples;
572                 else
573                         tempData = (float64data) (1.0 / 100.0);
574                 temp = &tempData;
575
576         }
577         else
578         {
579                 temp = (float64) fmgr(get_oprrest(operatorObjectId),
580                                                           (char *) operatorObjectId,
581                                                           (char *) indrelid,
582                                                           (char *) (int) attributeNumber,
583                                                           (char *) constValue,
584                                                           (char *) constFlag,
585                                                           NULL);
586         }
587
588         npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
589         result = (float64) palloc(sizeof(float64data));
590         *result = *temp * npage;
591         return result;
592 }
593
594
595 float64
596 rtsel(Oid operatorObjectId,
597           Oid indrelid,
598           AttrNumber attributeNumber,
599           char *constValue,
600           int32 constFlag,
601           int32 nIndexKeys,
602           Oid indexrelid)
603 {
604         return (btreesel(operatorObjectId, indrelid, attributeNumber,
605                                          constValue, constFlag, nIndexKeys, indexrelid));
606 }
607
608 float64
609 rtnpage(Oid operatorObjectId,
610                 Oid indrelid,
611                 AttrNumber attributeNumber,
612                 char *constValue,
613                 int32 constFlag,
614                 int32 nIndexKeys,
615                 Oid indexrelid)
616 {
617         return (btreenpage(operatorObjectId, indrelid, attributeNumber,
618                                            constValue, constFlag, nIndexKeys, indexrelid));
619 }
620
621 float64
622 gistsel(Oid operatorObjectId,
623                 Oid indrelid,
624                 AttrNumber attributeNumber,
625                 char *constValue,
626                 int32 constFlag,
627                 int32 nIndexKeys,
628                 Oid indexrelid)
629 {
630         return (btreesel(operatorObjectId, indrelid, attributeNumber,
631                                          constValue, constFlag, nIndexKeys, indexrelid));
632 }
633
634 float64
635 gistnpage(Oid operatorObjectId,
636                   Oid indrelid,
637                   AttrNumber attributeNumber,
638                   char *constValue,
639                   int32 constFlag,
640                   int32 nIndexKeys,
641                   Oid indexrelid)
642 {
643         return (btreenpage(operatorObjectId, indrelid, attributeNumber,
644                                            constValue, constFlag, nIndexKeys, indexrelid));
645 }