]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/lsyscache.c
A little further progress on schemas: push down RangeVars into
[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-2001, PostgreSQL Global Development Group
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.65 2002/03/22 02:56:35 tgl Exp $
11  *
12  * NOTES
13  *        Eventually, the index information should go through here, too.
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17
18 #include "access/tupmacs.h"
19 #include "catalog/pg_amop.h"
20 #include "catalog/pg_opclass.h"
21 #include "catalog/pg_operator.h"
22 #include "catalog/pg_proc.h"
23 #include "catalog/pg_shadow.h"
24 #include "catalog/pg_statistic.h"
25 #include "catalog/pg_type.h"
26 #include "nodes/makefuncs.h"
27 #include "utils/array.h"
28 #include "utils/builtins.h"
29 #include "utils/lsyscache.h"
30 #include "utils/syscache.h"
31
32
33 /*                              ---------- AMOP CACHES ----------                                                */
34
35 /*
36  * op_in_opclass
37  *
38  *              Return t iff operator 'opno' is in operator class 'opclass'.
39  */
40 bool
41 op_in_opclass(Oid opno, Oid opclass)
42 {
43         return SearchSysCacheExists(AMOPOPID,
44                                                                 ObjectIdGetDatum(opclass),
45                                                                 ObjectIdGetDatum(opno),
46                                                                 0, 0);
47 }
48
49 /*
50  * op_requires_recheck
51  *
52  *              Return t if operator 'opno' requires a recheck when used as a
53  *              member of opclass 'opclass' (ie, this opclass is lossy for this
54  *              operator).
55  *
56  * Caller should already have verified that opno is a member of opclass,
57  * therefore we raise an error if the tuple is not found.
58  */
59 bool
60 op_requires_recheck(Oid opno, Oid opclass)
61 {
62         HeapTuple       tp;
63         Form_pg_amop amop_tup;
64         bool            result;
65
66         tp = SearchSysCache(AMOPOPID,
67                                                 ObjectIdGetDatum(opclass),
68                                                 ObjectIdGetDatum(opno),
69                                                 0, 0);
70         if (!HeapTupleIsValid(tp))
71                 elog(ERROR, "op_requires_recheck: op %u is not a member of opclass %u",
72                          opno, opclass);
73         amop_tup = (Form_pg_amop) GETSTRUCT(tp);
74
75         result = amop_tup->amopreqcheck;
76         ReleaseSysCache(tp);
77         return result;
78 }
79
80 /*                              ---------- ATTRIBUTE CACHES ----------                                   */
81
82 /*
83  * get_attname
84  *
85  *              Given the relation id and the attribute number,
86  *              return the "attname" field from the attribute relation.
87  *
88  * Note: returns a palloc'd copy of the string, or NULL if no such operator.
89  */
90 char *
91 get_attname(Oid relid, AttrNumber attnum)
92 {
93         HeapTuple       tp;
94
95         tp = SearchSysCache(ATTNUM,
96                                                 ObjectIdGetDatum(relid),
97                                                 Int16GetDatum(attnum),
98                                                 0, 0);
99         if (HeapTupleIsValid(tp))
100         {
101                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
102                 char       *result;
103
104                 result = pstrdup(NameStr(att_tup->attname));
105                 ReleaseSysCache(tp);
106                 return result;
107         }
108         else
109                 return NULL;
110 }
111
112 /*
113  * get_attnum
114  *
115  *              Given the relation id and the attribute name,
116  *              return the "attnum" field from the attribute relation.
117  */
118 AttrNumber
119 get_attnum(Oid relid, char *attname)
120 {
121         HeapTuple       tp;
122
123         tp = SearchSysCache(ATTNAME,
124                                                 ObjectIdGetDatum(relid),
125                                                 PointerGetDatum(attname),
126                                                 0, 0);
127         if (HeapTupleIsValid(tp))
128         {
129                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
130                 AttrNumber      result;
131
132                 result = att_tup->attnum;
133                 ReleaseSysCache(tp);
134                 return result;
135         }
136         else
137                 return InvalidAttrNumber;
138 }
139
140 /*
141  * get_atttype
142  *
143  *              Given the relation OID and the attribute number with the relation,
144  *              return the attribute type OID.
145  */
146 Oid
147 get_atttype(Oid relid, AttrNumber attnum)
148 {
149         HeapTuple       tp;
150
151         tp = SearchSysCache(ATTNUM,
152                                                 ObjectIdGetDatum(relid),
153                                                 Int16GetDatum(attnum),
154                                                 0, 0);
155         if (HeapTupleIsValid(tp))
156         {
157                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
158                 Oid                     result;
159
160                 result = att_tup->atttypid;
161                 ReleaseSysCache(tp);
162                 return result;
163         }
164         else
165                 return InvalidOid;
166 }
167
168 /* This routine uses the attname instead of the attnum because it
169  * replaces the routine find_atttype, which is called sometimes when
170  * only the attname, not the attno, is available.
171  */
172 bool
173 get_attisset(Oid relid, char *attname)
174 {
175         HeapTuple       tp;
176
177         tp = SearchSysCache(ATTNAME,
178                                                 ObjectIdGetDatum(relid),
179                                                 PointerGetDatum(attname),
180                                                 0, 0);
181         if (HeapTupleIsValid(tp))
182         {
183                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
184                 bool            result;
185
186                 result = att_tup->attisset;
187                 ReleaseSysCache(tp);
188                 return result;
189         }
190         else
191                 return false;
192 }
193
194 /*
195  * get_atttypmod
196  *
197  *              Given the relation id and the attribute number,
198  *              return the "atttypmod" field from the attribute relation.
199  */
200 int32
201 get_atttypmod(Oid relid, AttrNumber attnum)
202 {
203         HeapTuple       tp;
204
205         tp = SearchSysCache(ATTNUM,
206                                                 ObjectIdGetDatum(relid),
207                                                 Int16GetDatum(attnum),
208                                                 0, 0);
209         if (HeapTupleIsValid(tp))
210         {
211                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
212                 int32           result;
213
214                 result = att_tup->atttypmod;
215                 ReleaseSysCache(tp);
216                 return result;
217         }
218         else
219                 return -1;
220 }
221
222 /*
223  * get_atttypetypmod
224  *
225  *              A two-fer: given the relation id and the attribute number,
226  *              fetch both type OID and atttypmod in a single cache lookup.
227  *
228  * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
229  * raises an error if it can't obtain the information.
230  */
231 void
232 get_atttypetypmod(Oid relid, AttrNumber attnum,
233                                   Oid *typid, int32 *typmod)
234 {
235         HeapTuple       tp;
236         Form_pg_attribute att_tup;
237
238         tp = SearchSysCache(ATTNUM,
239                                                 ObjectIdGetDatum(relid),
240                                                 Int16GetDatum(attnum),
241                                                 0, 0);
242         if (!HeapTupleIsValid(tp))
243                 elog(ERROR, "cache lookup failed for relation %u attribute %d",
244                          relid, attnum);
245         att_tup = (Form_pg_attribute) GETSTRUCT(tp);
246
247         *typid = att_tup->atttypid;
248         *typmod = att_tup->atttypmod;
249         ReleaseSysCache(tp);
250 }
251
252 /*                              ---------- INDEX CACHE ----------                                                */
253
254 /*              watch this space...
255  */
256
257 /*                              ---------- OPCLASS CACHE ----------                                              */
258
259 /*
260  * opclass_is_btree
261  *
262  *              Returns TRUE iff the specified opclass is associated with the
263  *              btree index access method.
264  */
265 bool
266 opclass_is_btree(Oid opclass)
267 {
268         HeapTuple       tp;
269         Form_pg_opclass cla_tup;
270         bool            result;
271
272         tp = SearchSysCache(CLAOID,
273                                                 ObjectIdGetDatum(opclass),
274                                                 0, 0, 0);
275         if (!HeapTupleIsValid(tp))
276                 elog(ERROR, "cache lookup failed for opclass %u", opclass);
277         cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
278
279         result = (cla_tup->opcamid == BTREE_AM_OID);
280         ReleaseSysCache(tp);
281         return result;
282 }
283
284 /*                              ---------- OPERATOR CACHE ----------                                     */
285
286 /*
287  * get_opcode
288  *
289  *              Returns the regproc id of the routine used to implement an
290  *              operator given the operator oid.
291  */
292 RegProcedure
293 get_opcode(Oid opno)
294 {
295         HeapTuple       tp;
296
297         tp = SearchSysCache(OPEROID,
298                                                 ObjectIdGetDatum(opno),
299                                                 0, 0, 0);
300         if (HeapTupleIsValid(tp))
301         {
302                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
303                 RegProcedure result;
304
305                 result = optup->oprcode;
306                 ReleaseSysCache(tp);
307                 return result;
308         }
309         else
310                 return (RegProcedure) InvalidOid;
311 }
312
313 /*
314  * get_opname
315  *        returns the name of the operator with the given opno
316  *
317  * Note: returns a palloc'd copy of the string, or NULL if no such operator.
318  */
319 char *
320 get_opname(Oid opno)
321 {
322         HeapTuple       tp;
323
324         tp = SearchSysCache(OPEROID,
325                                                 ObjectIdGetDatum(opno),
326                                                 0, 0, 0);
327         if (HeapTupleIsValid(tp))
328         {
329                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
330                 char       *result;
331
332                 result = pstrdup(NameStr(optup->oprname));
333                 ReleaseSysCache(tp);
334                 return result;
335         }
336         else
337                 return NULL;
338 }
339
340 /*
341  * op_mergejoinable
342  *
343  *              Returns the left and right sort operators and types corresponding to a
344  *              mergejoinable operator, or nil if the operator is not mergejoinable.
345  */
346 bool
347 op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
348 {
349         HeapTuple       tp;
350         bool            result = false;
351
352         tp = SearchSysCache(OPEROID,
353                                                 ObjectIdGetDatum(opno),
354                                                 0, 0, 0);
355         if (HeapTupleIsValid(tp))
356         {
357                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
358
359                 if (optup->oprlsortop &&
360                         optup->oprrsortop &&
361                         optup->oprleft == ltype &&
362                         optup->oprright == rtype)
363                 {
364                         *leftOp = optup->oprlsortop;
365                         *rightOp = optup->oprrsortop;
366                         result = true;
367                 }
368                 ReleaseSysCache(tp);
369         }
370         return result;
371 }
372
373 /*
374  * op_mergejoin_crossops
375  *
376  *              Returns the cross-type comparison operators (ltype "<" rtype and
377  *              ltype ">" rtype) for an operator previously determined to be
378  *              mergejoinable.  Optionally, fetches the regproc ids of these
379  *              operators, as well as their operator OIDs.
380  *
381  * Raises error if operators cannot be found.  Assuming that the operator
382  * had indeed been marked mergejoinable, this indicates that whoever marked
383  * it so was mistaken.
384  */
385 void
386 op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
387                                           RegProcedure *ltproc, RegProcedure *gtproc)
388 {
389         HeapTuple       tp;
390         Form_pg_operator optup;
391         Oid                     oprleft,
392                                 oprright;
393
394         /*
395          * Get the declared left and right operand types of the operator.
396          */
397         tp = SearchSysCache(OPEROID,
398                                                 ObjectIdGetDatum(opno),
399                                                 0, 0, 0);
400         if (!HeapTupleIsValid(tp))      /* shouldn't happen */
401                 elog(ERROR, "op_mergejoin_crossops: operator %u not found", opno);
402         optup = (Form_pg_operator) GETSTRUCT(tp);
403         oprleft = optup->oprleft;
404         oprright = optup->oprright;
405         ReleaseSysCache(tp);
406
407         /*
408          * Look up the "<" operator with the same input types.  If there isn't
409          * one, whoever marked the "=" operator mergejoinable was a loser.
410          */
411         tp = SearchSysCache(OPERNAME,
412                                                 PointerGetDatum("<"),
413                                                 ObjectIdGetDatum(oprleft),
414                                                 ObjectIdGetDatum(oprright),
415                                                 CharGetDatum('b'));
416         if (!HeapTupleIsValid(tp))
417                 elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching < operator",
418                          opno);
419         optup = (Form_pg_operator) GETSTRUCT(tp);
420         *ltop = tp->t_data->t_oid;
421         if (ltproc)
422                 *ltproc = optup->oprcode;
423         ReleaseSysCache(tp);
424
425         /*
426          * And the same for the ">" operator.
427          */
428         tp = SearchSysCache(OPERNAME,
429                                                 PointerGetDatum(">"),
430                                                 ObjectIdGetDatum(oprleft),
431                                                 ObjectIdGetDatum(oprright),
432                                                 CharGetDatum('b'));
433         if (!HeapTupleIsValid(tp))
434                 elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching > operator",
435                          opno);
436         optup = (Form_pg_operator) GETSTRUCT(tp);
437         *gtop = tp->t_data->t_oid;
438         if (gtproc)
439                 *gtproc = optup->oprcode;
440         ReleaseSysCache(tp);
441 }
442
443 /*
444  * op_hashjoinable
445  *
446  * Returns the hash operator corresponding to a hashjoinable operator,
447  * or InvalidOid if the operator is not hashjoinable.
448  */
449 Oid
450 op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
451 {
452         HeapTuple       tp;
453         Oid                     result = InvalidOid;
454
455         tp = SearchSysCache(OPEROID,
456                                                 ObjectIdGetDatum(opno),
457                                                 0, 0, 0);
458         if (HeapTupleIsValid(tp))
459         {
460                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
461
462                 if (optup->oprcanhash &&
463                         optup->oprleft == ltype &&
464                         optup->oprright == rtype)
465                         result = opno;
466                 ReleaseSysCache(tp);
467         }
468         return result;
469 }
470
471 /*
472  * op_iscachable
473  *
474  * Get the proiscachable flag for the operator's underlying function.
475  */
476 bool
477 op_iscachable(Oid opno)
478 {
479         RegProcedure funcid = get_opcode(opno);
480
481         if (funcid == (RegProcedure) InvalidOid)
482                 elog(ERROR, "Operator OID %u does not exist", opno);
483
484         return func_iscachable((Oid) funcid);
485 }
486
487 /*
488  * get_commutator
489  *
490  *              Returns the corresponding commutator of an operator.
491  */
492 Oid
493 get_commutator(Oid opno)
494 {
495         HeapTuple       tp;
496
497         tp = SearchSysCache(OPEROID,
498                                                 ObjectIdGetDatum(opno),
499                                                 0, 0, 0);
500         if (HeapTupleIsValid(tp))
501         {
502                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
503                 Oid                     result;
504
505                 result = optup->oprcom;
506                 ReleaseSysCache(tp);
507                 return result;
508         }
509         else
510                 return InvalidOid;
511 }
512
513 /*
514  * get_negator
515  *
516  *              Returns the corresponding negator of an operator.
517  */
518 Oid
519 get_negator(Oid opno)
520 {
521         HeapTuple       tp;
522
523         tp = SearchSysCache(OPEROID,
524                                                 ObjectIdGetDatum(opno),
525                                                 0, 0, 0);
526         if (HeapTupleIsValid(tp))
527         {
528                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
529                 Oid                     result;
530
531                 result = optup->oprnegate;
532                 ReleaseSysCache(tp);
533                 return result;
534         }
535         else
536                 return InvalidOid;
537 }
538
539 /*
540  * get_oprrest
541  *
542  *              Returns procedure id for computing selectivity of an operator.
543  */
544 RegProcedure
545 get_oprrest(Oid opno)
546 {
547         HeapTuple       tp;
548
549         tp = SearchSysCache(OPEROID,
550                                                 ObjectIdGetDatum(opno),
551                                                 0, 0, 0);
552         if (HeapTupleIsValid(tp))
553         {
554                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
555                 RegProcedure result;
556
557                 result = optup->oprrest;
558                 ReleaseSysCache(tp);
559                 return result;
560         }
561         else
562                 return (RegProcedure) InvalidOid;
563 }
564
565 /*
566  * get_oprjoin
567  *
568  *              Returns procedure id for computing selectivity of a join.
569  */
570 RegProcedure
571 get_oprjoin(Oid opno)
572 {
573         HeapTuple       tp;
574
575         tp = SearchSysCache(OPEROID,
576                                                 ObjectIdGetDatum(opno),
577                                                 0, 0, 0);
578         if (HeapTupleIsValid(tp))
579         {
580                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
581                 RegProcedure result;
582
583                 result = optup->oprjoin;
584                 ReleaseSysCache(tp);
585                 return result;
586         }
587         else
588                 return (RegProcedure) InvalidOid;
589 }
590
591 /*                              ---------- FUNCTION CACHE ----------                                     */
592
593 /*
594  * get_func_rettype
595  *              Given procedure id, return the function's result type.
596  */
597 Oid
598 get_func_rettype(Oid funcid)
599 {
600         HeapTuple       tp;
601         Oid                     result;
602
603         tp = SearchSysCache(PROCOID,
604                                                 ObjectIdGetDatum(funcid),
605                                                 0, 0, 0);
606         if (!HeapTupleIsValid(tp))
607                 elog(ERROR, "Function OID %u does not exist", funcid);
608
609         result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
610         ReleaseSysCache(tp);
611         return result;
612 }
613
614 /*
615  * func_iscachable
616  *              Given procedure id, return the function's proiscachable flag.
617  */
618 bool
619 func_iscachable(Oid funcid)
620 {
621         HeapTuple       tp;
622         bool            result;
623
624         tp = SearchSysCache(PROCOID,
625                                                 ObjectIdGetDatum(funcid),
626                                                 0, 0, 0);
627         if (!HeapTupleIsValid(tp))
628                 elog(ERROR, "Function OID %u does not exist", funcid);
629
630         result = ((Form_pg_proc) GETSTRUCT(tp))->proiscachable;
631         ReleaseSysCache(tp);
632         return result;
633 }
634
635 /*                              ---------- RELATION CACHE ----------                                     */
636
637 #ifdef NOT_USED
638 /*
639  * get_relnatts
640  *
641  *              Returns the number of attributes for a given relation.
642  */
643 int
644 get_relnatts(Oid relid)
645 {
646         HeapTuple       tp;
647
648         tp = SearchSysCache(RELOID,
649                                                 ObjectIdGetDatum(relid),
650                                                 0, 0, 0);
651         if (HeapTupleIsValid(tp))
652         {
653                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
654                 int                     result;
655
656                 result = reltup->relnatts;
657                 ReleaseSysCache(tp);
658                 return result;
659         }
660         else
661                 return InvalidAttrNumber;
662 }
663 #endif
664
665 /*
666  * get_rel_name
667  *
668  *              Returns the name of a given relation.
669  *
670  * Note: returns a palloc'd copy of the string, or NULL if no such relation.
671  */
672 char *
673 get_rel_name(Oid relid)
674 {
675         HeapTuple       tp;
676
677         tp = SearchSysCache(RELOID,
678                                                 ObjectIdGetDatum(relid),
679                                                 0, 0, 0);
680         if (HeapTupleIsValid(tp))
681         {
682                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
683                 char       *result;
684
685                 result = pstrdup(NameStr(reltup->relname));
686                 ReleaseSysCache(tp);
687                 return result;
688         }
689         else
690                 return NULL;
691 }
692
693 /*
694  * get_rel_type_id
695  *
696  *              Returns the pg_type OID associated with a given relation.
697  *
698  * Note: not all pg_class entries have associated pg_type OIDs; so be
699  * careful to check for InvalidOid result.
700  */
701 Oid
702 get_rel_type_id(Oid relid)
703 {
704         HeapTuple       tp;
705
706         tp = SearchSysCache(RELOID,
707                                                 ObjectIdGetDatum(relid),
708                                                 0, 0, 0);
709         if (HeapTupleIsValid(tp))
710         {
711                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
712                 Oid             result;
713
714                 result = reltup->reltype;
715                 ReleaseSysCache(tp);
716                 return result;
717         }
718         else
719                 return InvalidOid;
720 }
721
722 /*                              ---------- TYPE CACHE ----------                                                 */
723
724 /*
725  * get_typlen
726  *
727  *              Given the type OID, return the length of the type.
728  */
729 int16
730 get_typlen(Oid typid)
731 {
732         HeapTuple       tp;
733
734         tp = SearchSysCache(TYPEOID,
735                                                 ObjectIdGetDatum(typid),
736                                                 0, 0, 0);
737         if (HeapTupleIsValid(tp))
738         {
739                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
740                 int16           result;
741
742                 result = typtup->typlen;
743                 ReleaseSysCache(tp);
744                 return result;
745         }
746         else
747                 return 0;
748 }
749
750 /*
751  * get_typbyval
752  *
753  *              Given the type OID, determine whether the type is returned by value or
754  *              not.  Returns true if by value, false if by reference.
755  */
756 bool
757 get_typbyval(Oid typid)
758 {
759         HeapTuple       tp;
760
761         tp = SearchSysCache(TYPEOID,
762                                                 ObjectIdGetDatum(typid),
763                                                 0, 0, 0);
764         if (HeapTupleIsValid(tp))
765         {
766                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
767                 bool            result;
768
769                 result = typtup->typbyval;
770                 ReleaseSysCache(tp);
771                 return result;
772         }
773         else
774                 return false;
775 }
776
777 /*
778  * get_typlenbyval
779  *
780  *              A two-fer: given the type OID, return both typlen and typbyval.
781  *
782  *              Since both pieces of info are needed to know how to copy a Datum,
783  *              many places need both.  Might as well get them with one cache lookup
784  *              instead of two.  Also, this routine raises an error instead of
785  *              returning a bogus value when given a bad type OID.
786  */
787 void
788 get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
789 {
790         HeapTuple       tp;
791         Form_pg_type typtup;
792
793         tp = SearchSysCache(TYPEOID,
794                                                 ObjectIdGetDatum(typid),
795                                                 0, 0, 0);
796         if (!HeapTupleIsValid(tp))
797                 elog(ERROR, "cache lookup failed for type %u", typid);
798         typtup = (Form_pg_type) GETSTRUCT(tp);
799         *typlen = typtup->typlen;
800         *typbyval = typtup->typbyval;
801         ReleaseSysCache(tp);
802 }
803
804 #ifdef NOT_USED
805 char
806 get_typalign(Oid typid)
807 {
808         HeapTuple       tp;
809
810         tp = SearchSysCache(TYPEOID,
811                                                 ObjectIdGetDatum(typid),
812                                                 0, 0, 0);
813         if (HeapTupleIsValid(tp))
814         {
815                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
816                 char            result;
817
818                 result = typtup->typalign;
819                 ReleaseSysCache(tp);
820                 return result;
821         }
822         else
823                 return 'i';
824 }
825 #endif
826
827 char
828 get_typstorage(Oid typid)
829 {
830         HeapTuple       tp;
831
832         tp = SearchSysCache(TYPEOID,
833                                                 ObjectIdGetDatum(typid),
834                                                 0, 0, 0);
835         if (HeapTupleIsValid(tp))
836         {
837                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
838                 char            result;
839
840                 result = typtup->typstorage;
841                 ReleaseSysCache(tp);
842                 return result;
843         }
844         else
845                 return 'p';
846 }
847
848 /*
849  * get_typdefault
850  *        Given a type OID, return the type's default value, if any.
851  *
852  *        The result is a palloc'd expression node tree, or NULL if there
853  *        is no defined default for the datatype.
854  *
855  * NB: caller should be prepared to coerce result to correct datatype;
856  * the returned expression tree might produce something of the wrong type.
857  */
858 Node *
859 get_typdefault(Oid typid)
860 {
861         HeapTuple       typeTuple;
862         Form_pg_type type;
863         Datum           datum;
864         bool            isNull;
865         Node       *expr;
866
867         typeTuple = SearchSysCache(TYPEOID,
868                                                            ObjectIdGetDatum(typid),
869                                                            0, 0, 0);
870         if (!HeapTupleIsValid(typeTuple))
871                 elog(ERROR, "get_typdefault: failed to lookup type %u", typid);
872         type = (Form_pg_type) GETSTRUCT(typeTuple);
873
874         /*
875          * typdefault and typdefaultbin are potentially null, so don't try to
876          * access 'em as struct fields. Must do it the hard way with
877          * SysCacheGetAttr.
878          */
879         datum = SysCacheGetAttr(TYPEOID,
880                                                         typeTuple,
881                                                         Anum_pg_type_typdefaultbin,
882                                                         &isNull);
883
884         if (!isNull)
885         {
886                 /* We have an expression default */
887                 expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
888                                                                                                                                 datum)));
889         }
890         else
891         {
892                 /* Perhaps we have a plain literal default */
893                 datum = SysCacheGetAttr(TYPEOID,
894                                                                 typeTuple,
895                                                                 Anum_pg_type_typdefault,
896                                                                 &isNull);
897
898                 if (!isNull)
899                 {
900                         char       *strDefaultVal;
901
902                         /* Convert text datum to C string */
903                         strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
904                                                                                                                                 datum));
905                         /* Convert C string to a value of the given type */
906                         datum = OidFunctionCall3(type->typinput,
907                                                                          CStringGetDatum(strDefaultVal),
908                                                                          ObjectIdGetDatum(type->typelem),
909                                                                          Int32GetDatum(-1));
910                         /* Build a Const node containing the value */
911                         expr = (Node *) makeConst(typid,
912                                                                           type->typlen,
913                                                                           datum,
914                                                                           false,
915                                                                           type->typbyval,
916                                                                           false,        /* not a set */
917                                                                           false);
918                         pfree(strDefaultVal);
919                 }
920                 else
921                 {
922                         /* No default */
923                         expr = NULL;
924                 }
925         }
926
927         ReleaseSysCache(typeTuple);
928
929         return expr;
930 }
931
932 /*
933  * getBaseType
934  *              If the given type is a domain, return its base type;
935  *              otherwise return the type's own OID.
936  */
937 Oid
938 getBaseType(Oid typid)
939 {
940         /*
941          * We loop to find the bottom base type in a stack of domains.
942          */
943         for (;;)
944         {
945                 HeapTuple       tup;
946                 Form_pg_type typTup;
947
948                 tup = SearchSysCache(TYPEOID,
949                                                          ObjectIdGetDatum(typid),
950                                                          0, 0, 0);
951                 if (!HeapTupleIsValid(tup))
952                         elog(ERROR, "getBaseType: failed to lookup type %u", typid);
953                 typTup = (Form_pg_type) GETSTRUCT(tup);
954                 if (typTup->typtype != 'd')
955                 {
956                         /* Not a domain, so done */
957                         ReleaseSysCache(tup);
958                         break;
959                 }
960
961                 typid = typTup->typbasetype;
962                 ReleaseSysCache(tup);
963         }
964
965         return typid;
966 }
967
968 /*
969  * get_typavgwidth
970  *
971  *        Given a type OID and a typmod value (pass -1 if typmod is unknown),
972  *        estimate the average width of values of the type.  This is used by
973  *        the planner, which doesn't require absolutely correct results;
974  *        it's OK (and expected) to guess if we don't know for sure.
975  */
976 int32
977 get_typavgwidth(Oid typid, int32 typmod)
978 {
979         int                     typlen = get_typlen(typid);
980         int32           maxwidth;
981
982         /*
983          * Easy if it's a fixed-width type
984          */
985         if (typlen > 0)
986                 return typlen;
987
988         /*
989          * type_maximum_size knows the encoding of typmod for some datatypes;
990          * don't duplicate that knowledge here.
991          */
992         maxwidth = type_maximum_size(typid, typmod);
993         if (maxwidth > 0)
994         {
995                 /*
996                  * For BPCHAR, the max width is also the only width.  Otherwise we
997                  * need to guess about the typical data width given the max. A
998                  * sliding scale for percentage of max width seems reasonable.
999                  */
1000                 if (typid == BPCHAROID)
1001                         return maxwidth;
1002                 if (maxwidth <= 32)
1003                         return maxwidth;        /* assume full width */
1004                 if (maxwidth < 1000)
1005                         return 32 + (maxwidth - 32) / 2;        /* assume 50% */
1006
1007                 /*
1008                  * Beyond 1000, assume we're looking at something like
1009                  * "varchar(10000)" where the limit isn't actually reached often,
1010                  * and use a fixed estimate.
1011                  */
1012                 return 32 + (1000 - 32) / 2;
1013         }
1014
1015         /*
1016          * Ooops, we have no idea ... wild guess time.
1017          */
1018         return 32;
1019 }
1020
1021 /*
1022  * get_typtype
1023  *
1024  *              Given the type OID, find if it is a basic type, a named relation
1025  *              or the generic type 'relation'.
1026  *              It returns the null char if the cache lookup fails...
1027  */
1028 #ifdef NOT_USED
1029 char
1030 get_typtype(Oid typid)
1031 {
1032         HeapTuple       tp;
1033
1034         tp = SearchSysCache(TYPEOID,
1035                                                 ObjectIdGetDatum(typid),
1036                                                 0, 0, 0);
1037         if (HeapTupleIsValid(tp))
1038         {
1039                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1040                 char            result;
1041
1042                 result = typtup->typtype;
1043                 ReleaseSysCache(tp);
1044                 return result;
1045         }
1046         else
1047                 return '\0';
1048 }
1049 #endif
1050
1051 /*                              ---------- STATISTICS CACHE ----------                                   */
1052
1053 /*
1054  * get_attavgwidth
1055  *
1056  *        Given the table and attribute number of a column, get the average
1057  *        width of entries in the column.  Return zero if no data available.
1058  */
1059 int32
1060 get_attavgwidth(Oid relid, AttrNumber attnum)
1061 {
1062         HeapTuple       tp;
1063
1064         tp = SearchSysCache(STATRELATT,
1065                                                 ObjectIdGetDatum(relid),
1066                                                 Int16GetDatum(attnum),
1067                                                 0, 0);
1068         if (HeapTupleIsValid(tp))
1069         {
1070                 int32           stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
1071
1072                 ReleaseSysCache(tp);
1073                 if (stawidth > 0)
1074                         return stawidth;
1075         }
1076         return 0;
1077 }
1078
1079 /*
1080  * get_attstatsslot
1081  *
1082  *              Extract the contents of a "slot" of a pg_statistic tuple.
1083  *              Returns TRUE if requested slot type was found, else FALSE.
1084  *
1085  * Unlike other routines in this file, this takes a pointer to an
1086  * already-looked-up tuple in the pg_statistic cache.  We do this since
1087  * most callers will want to extract more than one value from the cache
1088  * entry, and we don't want to repeat the cache lookup unnecessarily.
1089  *
1090  * statstuple: pg_statistics tuple to be examined.
1091  * atttype: type OID of attribute.
1092  * atttypmod: typmod of attribute.
1093  * reqkind: STAKIND code for desired statistics slot kind.
1094  * reqop: STAOP value wanted, or InvalidOid if don't care.
1095  * values, nvalues: if not NULL, the slot's stavalues are extracted.
1096  * numbers, nnumbers: if not NULL, the slot's stanumbers are extracted.
1097  *
1098  * If assigned, values and numbers are set to point to palloc'd arrays.
1099  * If the attribute type is pass-by-reference, the values referenced by
1100  * the values array are themselves palloc'd.  The palloc'd stuff can be
1101  * freed by calling free_attstatsslot.
1102  */
1103 bool
1104 get_attstatsslot(HeapTuple statstuple,
1105                                  Oid atttype, int32 atttypmod,
1106                                  int reqkind, Oid reqop,
1107                                  Datum **values, int *nvalues,
1108                                  float4 **numbers, int *nnumbers)
1109 {
1110         Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
1111         int                     i,
1112                                 j;
1113         Datum           val;
1114         bool            isnull;
1115         ArrayType  *statarray;
1116         int                     narrayelem;
1117         HeapTuple       typeTuple;
1118         FmgrInfo        inputproc;
1119         Oid                     typelem;
1120
1121         for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
1122         {
1123                 if ((&stats->stakind1)[i] == reqkind &&
1124                         (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
1125                         break;
1126         }
1127         if (i >= STATISTIC_NUM_SLOTS)
1128                 return false;                   /* not there */
1129
1130         if (values)
1131         {
1132                 val = SysCacheGetAttr(STATRELATT, statstuple,
1133                                                           Anum_pg_statistic_stavalues1 + i,
1134                                                           &isnull);
1135                 if (isnull)
1136                         elog(ERROR, "get_attstatsslot: stavalues is null");
1137                 statarray = DatumGetArrayTypeP(val);
1138
1139                 /*
1140                  * Do initial examination of the array.  This produces a list of
1141                  * text Datums --- ie, pointers into the text array value.
1142                  */
1143                 deconstruct_array(statarray, false, -1, 'i', values, nvalues);
1144                 narrayelem = *nvalues;
1145
1146                 /*
1147                  * We now need to replace each text Datum by its internal
1148                  * equivalent.
1149                  *
1150                  * Get the type input proc and typelem for the column datatype.
1151                  */
1152                 typeTuple = SearchSysCache(TYPEOID,
1153                                                                    ObjectIdGetDatum(atttype),
1154                                                                    0, 0, 0);
1155                 if (!HeapTupleIsValid(typeTuple))
1156                         elog(ERROR, "get_attstatsslot: Cache lookup failed for type %u",
1157                                  atttype);
1158                 fmgr_info(((Form_pg_type) GETSTRUCT(typeTuple))->typinput, &inputproc);
1159                 typelem = ((Form_pg_type) GETSTRUCT(typeTuple))->typelem;
1160                 ReleaseSysCache(typeTuple);
1161
1162                 /*
1163                  * Do the conversions.  The palloc'd array of Datums is reused in
1164                  * place.
1165                  */
1166                 for (j = 0; j < narrayelem; j++)
1167                 {
1168                         char       *strval;
1169
1170                         strval = DatumGetCString(DirectFunctionCall1(textout,
1171                                                                                                                  (*values)[j]));
1172                         (*values)[j] = FunctionCall3(&inputproc,
1173                                                                                  CStringGetDatum(strval),
1174                                                                                  ObjectIdGetDatum(typelem),
1175                                                                                  Int32GetDatum(atttypmod));
1176                         pfree(strval);
1177                 }
1178
1179                 /*
1180                  * Free statarray if it's a detoasted copy.
1181                  */
1182                 if ((Pointer) statarray != DatumGetPointer(val))
1183                         pfree(statarray);
1184         }
1185
1186         if (numbers)
1187         {
1188                 val = SysCacheGetAttr(STATRELATT, statstuple,
1189                                                           Anum_pg_statistic_stanumbers1 + i,
1190                                                           &isnull);
1191                 if (isnull)
1192                         elog(ERROR, "get_attstatsslot: stanumbers is null");
1193                 statarray = DatumGetArrayTypeP(val);
1194
1195                 /*
1196                  * We expect the array to be a 1-D float4 array; verify that. We
1197                  * don't need to use deconstruct_array() since the array data is
1198                  * just going to look like a C array of float4 values.
1199                  */
1200                 narrayelem = ARR_DIMS(statarray)[0];
1201                 if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
1202                         ARR_SIZE(statarray) != (ARR_OVERHEAD(1) + narrayelem * sizeof(float4)))
1203                         elog(ERROR, "get_attstatsslot: stanumbers is bogus");
1204                 *numbers = (float4 *) palloc(narrayelem * sizeof(float4));
1205                 memcpy(*numbers, ARR_DATA_PTR(statarray), narrayelem * sizeof(float4));
1206                 *nnumbers = narrayelem;
1207
1208                 /*
1209                  * Free statarray if it's a detoasted copy.
1210                  */
1211                 if ((Pointer) statarray != DatumGetPointer(val))
1212                         pfree(statarray);
1213         }
1214
1215         return true;
1216 }
1217
1218 void
1219 free_attstatsslot(Oid atttype,
1220                                   Datum *values, int nvalues,
1221                                   float4 *numbers, int nnumbers)
1222 {
1223         if (values)
1224         {
1225                 if (!get_typbyval(atttype))
1226                 {
1227                         int                     i;
1228
1229                         for (i = 0; i < nvalues; i++)
1230                                 pfree(DatumGetPointer(values[i]));
1231                 }
1232                 pfree(values);
1233         }
1234         if (numbers)
1235                 pfree(numbers);
1236 }
1237
1238 /*                              ---------- PG_SHADOW CACHE ----------                                    */
1239
1240 /*
1241  * get_usesysid
1242  *
1243  *        Given a user name, look up the user's sysid.
1244  *        Raises an error if no such user (rather than returning zero,
1245  *        which might possibly be a valid usesysid).
1246  *
1247  * Note: the type of usesysid is currently int4, but may change to Oid
1248  * someday.  It'd be reasonable to return zero on failure if we were
1249  * using Oid ...
1250  */
1251 int32
1252 get_usesysid(const char *username)
1253 {
1254         int32           result;
1255         HeapTuple       userTup;
1256
1257         userTup = SearchSysCache(SHADOWNAME,
1258                                                          PointerGetDatum(username),
1259                                                          0, 0, 0);
1260         if (!HeapTupleIsValid(userTup))
1261                 elog(ERROR, "user \"%s\" does not exist", username);
1262
1263         result = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
1264
1265         ReleaseSysCache(userTup);
1266
1267         return result;
1268 }