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