]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/lsyscache.c
Repair error noticed by Roberto Cornacchia: selectivity code
[postgresql] / src / backend / utils / cache / lsyscache.c
1 /*-------------------------------------------------------------------------
2  *
3  * lsyscache.c
4  *        Convenience routines for common queries in the system catalog cache.
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  * IDENTIFICATION
9  *        $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.34 1999/09/09 02:36:04 tgl Exp $
10  *
11  * NOTES
12  *        Eventually, the index information should go through here, too.
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "catalog/pg_operator.h"
18 #include "catalog/pg_proc.h"
19 #include "catalog/pg_type.h"
20 #include "utils/lsyscache.h"
21 #include "utils/syscache.h"
22
23 /*                              ---------- AMOP CACHES ----------                                                */
24
25 /*
26  * op_class -
27  *
28  *              Return t iff operator 'opno' is in operator class 'opclass'.
29  *
30  */
31 bool
32 op_class(Oid oprno, int32 opclass, Oid amopid)
33 {
34         if (HeapTupleIsValid(SearchSysCacheTuple(AMOPOPID,
35                                                                                          ObjectIdGetDatum(opclass),
36                                                                                          ObjectIdGetDatum(oprno),
37                                                                                          ObjectIdGetDatum(amopid),
38                                                                                          0)))
39                 return true;
40         else
41                 return false;
42 }
43
44 /*                              ---------- ATTRIBUTE CACHES ----------                                   */
45
46 /*
47  * get_attname -
48  *
49  *              Given the relation id and the attribute number,
50  *              return the "attname" field from the attribute relation.
51  *
52  */
53 char *
54 get_attname(Oid relid, AttrNumber attnum)
55 {
56         HeapTuple       tp;
57
58         tp = SearchSysCacheTuple(ATTNUM,
59                                                          ObjectIdGetDatum(relid),
60                                                          UInt16GetDatum(attnum),
61                                                          0, 0);
62         if (HeapTupleIsValid(tp))
63         {
64                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
65                 return pstrdup(att_tup->attname.data);
66         }
67         else
68                 return NULL;
69 }
70
71 /*
72  * get_attnum -
73  *
74  *              Given the relation id and the attribute name,
75  *              return the "attnum" field from the attribute relation.
76  *
77  */
78 AttrNumber
79 get_attnum(Oid relid, char *attname)
80 {
81         HeapTuple       tp;
82
83         tp = SearchSysCacheTuple(ATTNAME,
84                                                          ObjectIdGetDatum(relid),
85                                                          PointerGetDatum(attname),
86                                                          0, 0);
87         if (HeapTupleIsValid(tp))
88         {
89                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
90                 return att_tup->attnum;
91         }
92         else
93                 return InvalidAttrNumber;
94 }
95
96 /*
97  * get_atttype -
98  *
99  *              Given the relation OID and the attribute number with the relation,
100  *              return the attribute type OID.
101  *
102  */
103 Oid
104 get_atttype(Oid relid, AttrNumber attnum)
105 {
106         HeapTuple       tp;
107
108         tp = SearchSysCacheTuple(ATTNUM,
109                                                          ObjectIdGetDatum(relid),
110                                                          UInt16GetDatum(attnum),
111                                                          0, 0);
112         if (HeapTupleIsValid(tp))
113         {
114                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
115                 return att_tup->atttypid;
116         }
117         else
118                 return InvalidOid;
119 }
120
121 /* This routine uses the attname instead of the attnum because it
122  * replaces the routine find_atttype, which is called sometimes when
123  * only the attname, not the attno, is available.
124  */
125 bool
126 get_attisset(Oid relid, char *attname)
127 {
128         HeapTuple       tp;
129
130         tp = SearchSysCacheTuple(ATTNAME,
131                                                          ObjectIdGetDatum(relid),
132                                                          PointerGetDatum(attname),
133                                                          0, 0);
134         if (HeapTupleIsValid(tp))
135         {
136                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
137                 return att_tup->attisset;
138         }
139         else
140                 return false;
141 }
142
143 /*
144  * get_atttypmod -
145  *
146  *              Given the relation id and the attribute number,
147  *              return the "atttypmod" field from the attribute relation.
148  *
149  */
150 int32
151 get_atttypmod(Oid relid, AttrNumber attnum)
152 {
153         HeapTuple       tp;
154
155         tp = SearchSysCacheTuple(ATTNUM,
156                                                          ObjectIdGetDatum(relid),
157                                                          UInt16GetDatum(attnum),
158                                                          0, 0);
159         if (HeapTupleIsValid(tp))
160         {
161                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
162                 return att_tup->atttypmod;
163         }
164         else
165                 return -1;
166 }
167
168 /*
169  * get_attdisbursion
170  *
171  *        Retrieve the disbursion statistic for an attribute,
172  *        or produce an estimate if no info is available.
173  *
174  * min_estimate is the minimum estimate to return if insufficient data
175  * is available to produce a reliable value.  This value may vary
176  * depending on context.  (For example, when deciding whether it is
177  * safe to use a hashjoin, we want to be more conservative than when
178  * estimating the number of tuples produced by an equijoin.)
179  */
180 double
181 get_attdisbursion(Oid relid, AttrNumber attnum, double min_estimate)
182 {
183         HeapTuple       atp;
184         double          disbursion;
185         int32           ntuples;
186
187         atp = SearchSysCacheTuple(ATTNUM,
188                                                           ObjectIdGetDatum(relid),
189                                                           Int16GetDatum(attnum),
190                                                           0, 0);
191         if (!HeapTupleIsValid(atp))
192         {
193                 /* this should not happen */
194                 elog(ERROR, "get_attdisbursion: no attribute tuple %u %d",
195                          relid, attnum);
196                 return min_estimate;
197         }
198
199         disbursion = ((Form_pg_attribute) GETSTRUCT(atp))->attdisbursion;
200         if (disbursion > 0.0)
201                 return disbursion;              /* we have a specific estimate */
202
203         /*
204          * Disbursion is either 0 (no data available) or -1 (disbursion
205          * is 1/numtuples).  Either way, we need the relation size.
206          */
207
208         atp = SearchSysCacheTuple(RELOID,
209                                                           ObjectIdGetDatum(relid),
210                                                           0, 0, 0);
211         if (!HeapTupleIsValid(atp))
212         {
213                 /* this should not happen */
214                 elog(ERROR, "get_attdisbursion: no relation tuple %u", relid);
215                 return min_estimate;
216         }
217
218         ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
219
220         if (ntuples == 0)
221                 return min_estimate;    /* no data available */
222
223         if (disbursion < 0.0)           /* VACUUM thinks there are no duplicates */
224                 return 1.0 / (double) ntuples;
225
226         /*
227          * VACUUM ANALYZE does not compute disbursion for system attributes,
228          * but some of them can reasonably be assumed unique anyway.
229          */
230         if (attnum == ObjectIdAttributeNumber ||
231                 attnum == SelfItemPointerAttributeNumber)
232                 return 1.0 / (double) ntuples;
233
234         /*
235          * VACUUM ANALYZE has not been run for this table.
236          * Produce an estimate = 1/numtuples.  This may produce
237          * unreasonably small estimates for large tables, so limit
238          * the estimate to no less than min_estimate.
239          */
240         disbursion = 1.0 / (double) ntuples;
241         if (disbursion < min_estimate)
242                 disbursion = min_estimate;
243
244         return disbursion;
245 }
246
247 /*                              ---------- INDEX CACHE ----------                                                */
248
249 /*              watch this space...
250  */
251
252 /*                              ---------- OPERATOR CACHE ----------                                     */
253
254 /*
255  * get_opcode -
256  *
257  *              Returns the regproc id of the routine used to implement an
258  *              operator given the operator oid.
259  *
260  */
261 RegProcedure
262 get_opcode(Oid opno)
263 {
264         HeapTuple       tp;
265
266         tp = SearchSysCacheTuple(OPROID,
267                                                          ObjectIdGetDatum(opno),
268                                                          0, 0, 0);
269         if (HeapTupleIsValid(tp))
270         {
271                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
272                 return optup->oprcode;
273         }
274         else
275                 return (RegProcedure) NULL;
276 }
277
278 /*
279  * get_opname -
280  *        returns the name of the operator with the given opno
281  *
282  * Note: returns a palloc'd copy of the string, or NULL if no such operator.
283  */
284 char *
285 get_opname(Oid opno)
286 {
287         HeapTuple       tp;
288
289         tp = SearchSysCacheTuple(OPROID,
290                                                          ObjectIdGetDatum(opno),
291                                                          0, 0, 0);
292         if (HeapTupleIsValid(tp))
293         {
294                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
295                 return pstrdup(optup->oprname.data);
296         }
297         else
298                 return NULL;
299 }
300
301 /*
302  * op_mergejoinable -
303  *
304  *              Returns the left and right sort operators and types corresponding to a
305  *              mergejoinable operator, or nil if the operator is not mergejoinable.
306  *
307  */
308 bool
309 op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
310 {
311         HeapTuple       tp;
312
313         tp = SearchSysCacheTuple(OPROID,
314                                                          ObjectIdGetDatum(opno),
315                                                          0, 0, 0);
316         if (HeapTupleIsValid(tp))
317         {
318                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
319
320                 if (optup->oprlsortop &&
321                         optup->oprrsortop &&
322                         optup->oprleft == ltype &&
323                         optup->oprright == rtype)
324                 {
325                         *leftOp = ObjectIdGetDatum(optup->oprlsortop);
326                         *rightOp = ObjectIdGetDatum(optup->oprrsortop);
327                         return true;
328                 }
329         }
330         return false;
331 }
332
333 /*
334  * op_hashjoinable
335  *
336  * Returns the hash operator corresponding to a hashjoinable operator,
337  * or nil if the operator is not hashjoinable.
338  *
339  */
340 Oid
341 op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
342 {
343         HeapTuple       tp;
344
345         tp = SearchSysCacheTuple(OPROID,
346                                                          ObjectIdGetDatum(opno),
347                                                          0, 0, 0);
348         if (HeapTupleIsValid(tp))
349         {
350                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
351
352                 if (optup->oprcanhash &&
353                         optup->oprleft == ltype &&
354                         optup->oprright == rtype)
355                         return opno;
356         }
357         return InvalidOid;
358 }
359
360 HeapTuple
361 get_operator_tuple(Oid opno)
362 {
363         HeapTuple       optup;
364
365         if ((optup = SearchSysCacheTuple(OPROID,
366                                                                          ObjectIdGetDatum(opno),
367                                                                          0, 0, 0)))
368                 return optup;
369         else
370                 return (HeapTuple) NULL;
371 }
372
373 /*
374  * get_commutator -
375  *
376  *              Returns the corresponding commutator of an operator.
377  *
378  */
379 Oid
380 get_commutator(Oid opno)
381 {
382         HeapTuple       tp;
383
384         tp = SearchSysCacheTuple(OPROID,
385                                                          ObjectIdGetDatum(opno),
386                                                          0, 0, 0);
387         if (HeapTupleIsValid(tp))
388         {
389                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
390                 return optup->oprcom;
391         }
392         else
393                 return InvalidOid;
394 }
395
396 /*
397  * get_negator -
398  *
399  *              Returns the corresponding negator of an operator.
400  *
401  */
402 Oid
403 get_negator(Oid opno)
404 {
405         HeapTuple       tp;
406
407         tp = SearchSysCacheTuple(OPROID,
408                                                          ObjectIdGetDatum(opno),
409                                                          0, 0, 0);
410         if (HeapTupleIsValid(tp))
411         {
412                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
413                 return optup->oprnegate;
414         }
415         else
416                 return InvalidOid;
417 }
418
419 /*
420  * get_oprrest -
421  *
422  *              Returns procedure id for computing selectivity of an operator.
423  *
424  */
425 RegProcedure
426 get_oprrest(Oid opno)
427 {
428         HeapTuple       tp;
429
430         tp = SearchSysCacheTuple(OPROID,
431                                                          ObjectIdGetDatum(opno),
432                                                          0, 0, 0);
433         if (HeapTupleIsValid(tp))
434         {
435                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
436                 return optup->oprrest;
437         }
438         else
439                 return (RegProcedure) NULL;
440 }
441
442 /*
443  * get_oprjoin -
444  *
445  *              Returns procedure id for computing selectivity of a join.
446  *
447  */
448 RegProcedure
449 get_oprjoin(Oid opno)
450 {
451         HeapTuple       tp;
452
453         tp = SearchSysCacheTuple(OPROID,
454                                                          ObjectIdGetDatum(opno),
455                                                          0, 0, 0);
456         if (HeapTupleIsValid(tp))
457         {
458                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
459                 return optup->oprjoin;
460         }
461         else
462                 return (RegProcedure) NULL;
463 }
464
465 /*                              ---------- FUNCTION CACHE ----------                                     */
466
467 /*
468  * get_func_rettype
469  *              Given procedure id, return the function's result type.
470  */
471 Oid
472 get_func_rettype(Oid funcid)
473 {
474         HeapTuple       func_tuple;
475         Oid                     funcrettype;
476
477         func_tuple = SearchSysCacheTuple(PROOID,
478                                                                          ObjectIdGetDatum(funcid),
479                                                                          0, 0, 0);
480
481         if (!HeapTupleIsValid(func_tuple))
482                 elog(ERROR, "Function OID %u does not exist", funcid);
483
484         funcrettype = (Oid)
485                 ((Form_pg_proc) GETSTRUCT(func_tuple))->prorettype;
486
487         return funcrettype;
488 }
489
490 /*                              ---------- RELATION CACHE ----------                                     */
491
492 /*
493  * get_relnatts -
494  *
495  *              Returns the number of attributes for a given relation.
496  *
497  */
498 int
499 get_relnatts(Oid relid)
500 {
501         HeapTuple       tp;
502
503         tp = SearchSysCacheTuple(RELOID,
504                                                          ObjectIdGetDatum(relid),
505                                                          0, 0, 0);
506         if (HeapTupleIsValid(tp))
507         {
508                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
509                 return reltup->relnatts;
510         }
511         else
512                 return InvalidAttrNumber;
513 }
514
515 /*
516  * get_rel_name -
517  *
518  *              Returns the name of a given relation.
519  *
520  */
521 char *
522 get_rel_name(Oid relid)
523 {
524         HeapTuple       tp;
525
526         tp = SearchSysCacheTuple(RELOID,
527                                                          ObjectIdGetDatum(relid),
528                                                          0, 0, 0);
529         if (HeapTupleIsValid(tp))
530         {
531                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
532                 return pstrdup(reltup->relname.data);
533         }
534         else
535                 return NULL;
536 }
537
538 /*                              ---------- TYPE CACHE ----------                                                 */
539
540 /*
541  * get_typlen -
542  *
543  *              Given the type OID, return the length of the type.
544  *
545  */
546 int16
547 get_typlen(Oid typid)
548 {
549         HeapTuple       tp;
550
551         tp = SearchSysCacheTuple(TYPOID,
552                                                          ObjectIdGetDatum(typid),
553                                                          0, 0, 0);
554         if (HeapTupleIsValid(tp))
555         {
556                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
557                 return typtup->typlen;
558         }
559         else
560                 return 0;
561 }
562
563 /*
564  * get_typbyval -
565  *
566  *              Given the type OID, determine whether the type is returned by value or
567  *              not.  Returns 1 if by value, 0 if by reference.
568  *
569  */
570 bool
571 get_typbyval(Oid typid)
572 {
573         HeapTuple       tp;
574
575         tp = SearchSysCacheTuple(TYPOID,
576                                                          ObjectIdGetDatum(typid),
577                                                          0, 0, 0);
578         if (HeapTupleIsValid(tp))
579         {
580                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
581                 return (bool) typtup->typbyval;
582         }
583         else
584                 return false;
585 }
586
587 #ifdef NOT_USED
588 char
589 get_typalign(Oid typid)
590 {
591         HeapTuple       tp;
592
593         tp = SearchSysCacheTuple(TYPOID,
594                                                          ObjectIdGetDatum(typid),
595                                                          0, 0, 0);
596         if (HeapTupleIsValid(tp))
597         {
598                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
599                 return typtup->typalign;
600         }
601         else
602                 return 'i';
603 }
604
605 #endif
606
607 /*
608  * get_typdefault -
609  *
610  *        Given a type OID, return the typdefault field associated with that
611  *        type, or Datum(NULL) if there is no typdefault.  (This implies
612  *        that pass-by-value types can't have a default value that has
613  *        a representation of zero.  Not worth fixing now.)
614  *        The result points to palloc'd storage for non-pass-by-value types.
615  */
616 Datum
617 get_typdefault(Oid typid)
618 {
619         struct varlena *typDefault;
620         int32           dataSize;
621         HeapTuple       typeTuple;
622         Form_pg_type type;
623         int32           typLen;
624         bool            typByVal;
625         Datum           returnValue;
626
627         /*
628          * First, see if there is a non-null typdefault field (usually there isn't)
629          */
630         typDefault = (struct varlena *)
631                 SearchSysCacheGetAttribute(TYPOID,
632                                                                    Anum_pg_type_typdefault,
633                                                                    ObjectIdGetDatum(typid),
634                                                                    0, 0, 0);
635
636         if (typDefault == NULL)
637                 return PointerGetDatum(NULL);
638
639         dataSize = VARSIZE(typDefault) - VARHDRSZ;
640
641         /*
642          * Need the type's length and byVal fields.
643          *
644          * XXX silly to repeat the syscache search that SearchSysCacheGetAttribute
645          * just did --- but at present this path isn't taken often enough to
646          * make it worth fixing.
647          */
648         typeTuple = SearchSysCacheTuple(TYPOID,
649                                                                         ObjectIdGetDatum(typid),
650                                                                         0, 0, 0);
651
652         if (!HeapTupleIsValid(typeTuple))
653                 elog(ERROR, "get_typdefault: failed to lookup type %u", typid);
654
655         type = (Form_pg_type) GETSTRUCT(typeTuple);
656         typLen = type->typlen;
657         typByVal = type->typbyval;
658
659         if (typByVal)
660         {
661                 int8            i8;
662                 int16           i16;
663                 int32           i32 = 0;
664
665                 if (dataSize == typLen)
666                 {
667                         switch (typLen)
668                         {
669                                 case sizeof(int8):
670                                         memcpy((char *) &i8, VARDATA(typDefault), sizeof(int8));
671                                         i32 = i8;
672                                         break;
673                                 case sizeof(int16):
674                                         memcpy((char *) &i16, VARDATA(typDefault), sizeof(int16));
675                                         i32 = i16;
676                                         break;
677                                 case sizeof(int32):
678                                         memcpy((char *) &i32, VARDATA(typDefault), sizeof(int32));
679                                         break;
680                         }
681                         returnValue = Int32GetDatum(i32);
682                 }
683                 else
684                         returnValue = PointerGetDatum(NULL);
685         }
686         else if (typLen < 0)
687         {
688                 /* variable-size type */
689                 if (dataSize < 0)
690                         returnValue = PointerGetDatum(NULL);
691                 else
692                 {
693                         returnValue = PointerGetDatum(palloc(VARSIZE(typDefault)));
694                         memcpy((char *) DatumGetPointer(returnValue),
695                                    (char *) typDefault,
696                                    (int) VARSIZE(typDefault));
697                 }
698         }
699         else
700         {
701                 /* fixed-size pass-by-ref type */
702                 if (dataSize != typLen)
703                         returnValue = PointerGetDatum(NULL);
704                 else
705                 {
706                         returnValue = PointerGetDatum(palloc(dataSize));
707                         memcpy((char *) DatumGetPointer(returnValue),
708                                    VARDATA(typDefault),
709                                    (int) dataSize);
710                 }
711         }
712
713         return returnValue;
714 }
715
716 /*
717  * get_typtype -
718  *
719  *              Given the type OID, find if it is a basic type, a named relation
720  *              or the generic type 'relation'.
721  *              It returns the null char if the cache lookup fails...
722  *
723  */
724 #ifdef NOT_USED
725 char
726 get_typtype(Oid typid)
727 {
728         HeapTuple       tp;
729
730         tp = SearchSysCacheTuple(TYPOID,
731                                                          ObjectIdGetDatum(typid),
732                                                          0, 0, 0);
733         if (HeapTupleIsValid(tp))
734         {
735                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
736                 return typtup->typtype;
737         }
738         else
739                 return '\0';
740 }
741
742 #endif