]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/lsyscache.c
Planner failed to be smart about binary-compatible expressions in pathkeys
[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-2003, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  *        $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.112 2003/12/03 17:45:09 tgl Exp $
11  *
12  * NOTES
13  *        Eventually, the index information should go through here, too.
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17 #include "miscadmin.h"
18
19 #include "access/hash.h"
20 #include "access/tupmacs.h"
21 #include "catalog/pg_amop.h"
22 #include "catalog/pg_amproc.h"
23 #include "catalog/pg_namespace.h"
24 #include "catalog/pg_opclass.h"
25 #include "catalog/pg_operator.h"
26 #include "catalog/pg_proc.h"
27 #include "catalog/pg_shadow.h"
28 #include "catalog/pg_statistic.h"
29 #include "catalog/pg_type.h"
30 #include "nodes/makefuncs.h"
31 #include "utils/array.h"
32 #include "utils/builtins.h"
33 #include "utils/catcache.h"
34 #include "utils/datum.h"
35 #include "utils/lsyscache.h"
36 #include "utils/syscache.h"
37
38
39 /*                              ---------- AMOP CACHES ----------                                                */
40
41 /*
42  * op_in_opclass
43  *
44  *              Return t iff operator 'opno' is in operator class 'opclass'.
45  */
46 bool
47 op_in_opclass(Oid opno, Oid opclass)
48 {
49         return SearchSysCacheExists(AMOPOPID,
50                                                                 ObjectIdGetDatum(opno),
51                                                                 ObjectIdGetDatum(opclass),
52                                                                 0, 0);
53 }
54
55 /*
56  * get_op_opclass_properties
57  *
58  *              Get the operator's strategy number, subtype, and recheck (lossy) flag
59  *              within the specified opclass.
60  *
61  * Caller should already have verified that opno is a member of opclass,
62  * therefore we raise an error if the tuple is not found.
63  */
64 void
65 get_op_opclass_properties(Oid opno, Oid opclass,
66                                                   int *strategy, Oid *subtype, bool *recheck)
67 {
68         HeapTuple       tp;
69         Form_pg_amop amop_tup;
70
71         tp = SearchSysCache(AMOPOPID,
72                                                 ObjectIdGetDatum(opno),
73                                                 ObjectIdGetDatum(opclass),
74                                                 0, 0);
75         if (!HeapTupleIsValid(tp))
76                 elog(ERROR, "operator %u is not a member of opclass %u",
77                          opno, opclass);
78         amop_tup = (Form_pg_amop) GETSTRUCT(tp);
79         *strategy = amop_tup->amopstrategy;
80         *subtype = amop_tup->amopsubtype;
81         *recheck = amop_tup->amopreqcheck;
82         ReleaseSysCache(tp);
83 }
84
85 /*
86  * get_opclass_member
87  *              Get the OID of the operator that implements the specified strategy
88  *              with the specified subtype for the specified opclass.
89  *
90  * Returns InvalidOid if there is no pg_amop entry for the given keys.
91  */
92 Oid
93 get_opclass_member(Oid opclass, Oid subtype, int16 strategy)
94 {
95         HeapTuple       tp;
96         Form_pg_amop amop_tup;
97         Oid                     result;
98
99         tp = SearchSysCache(AMOPSTRATEGY,
100                                                 ObjectIdGetDatum(opclass),
101                                                 ObjectIdGetDatum(subtype),
102                                                 Int16GetDatum(strategy),
103                                                 0);
104         if (!HeapTupleIsValid(tp))
105                 return InvalidOid;
106         amop_tup = (Form_pg_amop) GETSTRUCT(tp);
107         result = amop_tup->amopopr;
108         ReleaseSysCache(tp);
109         return result;
110 }
111
112 /*
113  * get_op_hash_function
114  *              Get the OID of the datatype-specific hash function associated with
115  *              a hashable equality operator.
116  *
117  * Returns InvalidOid if no hash function can be found.  (This indicates
118  * that the operator should not have been marked oprcanhash.)
119  */
120 Oid
121 get_op_hash_function(Oid opno)
122 {
123         CatCList   *catlist;
124         int                     i;
125         Oid                     opclass = InvalidOid;
126
127         /*
128          * Search pg_amop to see if the target operator is registered as the
129          * "=" operator of any hash opclass.  If the operator is registered in
130          * multiple opclasses, assume we can use the associated hash function
131          * from any one.
132          */
133         catlist = SearchSysCacheList(AMOPOPID, 1,
134                                                                  ObjectIdGetDatum(opno),
135                                                                  0, 0, 0);
136
137         for (i = 0; i < catlist->n_members; i++)
138         {
139                 HeapTuple       tuple = &catlist->members[i]->tuple;
140                 Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
141
142                 if (aform->amopstrategy == HTEqualStrategyNumber &&
143                         opclass_is_hash(aform->amopclaid))
144                 {
145                         opclass = aform->amopclaid;
146                         break;
147                 }
148         }
149
150         ReleaseSysCacheList(catlist);
151
152         if (OidIsValid(opclass))
153         {
154                 /* Found a suitable opclass, get its default hash support function */
155                 return get_opclass_proc(opclass, InvalidOid, HASHPROC);
156         }
157
158         /* Didn't find a match... */
159         return InvalidOid;
160 }
161
162
163 /*                              ---------- AMPROC CACHES ----------                                              */
164
165 /*
166  * get_opclass_proc
167  *              Get the OID of the specified support function
168  *              for the specified opclass and subtype.
169  *
170  * Returns InvalidOid if there is no pg_amproc entry for the given keys.
171  */
172 Oid
173 get_opclass_proc(Oid opclass, Oid subtype, int16 procnum)
174 {
175         HeapTuple       tp;
176         Form_pg_amproc amproc_tup;
177         RegProcedure result;
178
179         tp = SearchSysCache(AMPROCNUM,
180                                                 ObjectIdGetDatum(opclass),
181                                                 ObjectIdGetDatum(subtype),
182                                                 Int16GetDatum(procnum),
183                                                 0);
184         if (!HeapTupleIsValid(tp))
185                 return InvalidOid;
186         amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
187         result = amproc_tup->amproc;
188         ReleaseSysCache(tp);
189         return result;
190 }
191
192
193 /*                              ---------- ATTRIBUTE CACHES ----------                                   */
194
195 /*
196  * get_attname
197  *              Given the relation id and the attribute number,
198  *              return the "attname" field from the attribute relation.
199  *
200  * Note: returns a palloc'd copy of the string, or NULL if no such attribute.
201  */
202 char *
203 get_attname(Oid relid, AttrNumber attnum)
204 {
205         HeapTuple       tp;
206
207         tp = SearchSysCache(ATTNUM,
208                                                 ObjectIdGetDatum(relid),
209                                                 Int16GetDatum(attnum),
210                                                 0, 0);
211         if (HeapTupleIsValid(tp))
212         {
213                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
214                 char       *result;
215
216                 result = pstrdup(NameStr(att_tup->attname));
217                 ReleaseSysCache(tp);
218                 return result;
219         }
220         else
221                 return NULL;
222 }
223
224 /*
225  * get_relid_attribute_name
226  *
227  * Same as above routine get_attname(), except that error
228  * is handled by elog() instead of returning NULL.
229  */
230 char *
231 get_relid_attribute_name(Oid relid, AttrNumber attnum)
232 {
233         char       *attname;
234
235         attname = get_attname(relid, attnum);
236         if (attname == NULL)
237                 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
238                          attnum, relid);
239         return attname;
240 }
241
242 /*
243  * get_attnum
244  *
245  *              Given the relation id and the attribute name,
246  *              return the "attnum" field from the attribute relation.
247  *
248  *              Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
249  */
250 AttrNumber
251 get_attnum(Oid relid, const char *attname)
252 {
253         HeapTuple       tp;
254
255         tp = SearchSysCacheAttName(relid, attname);
256         if (HeapTupleIsValid(tp))
257         {
258                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
259                 AttrNumber      result;
260
261                 result = att_tup->attnum;
262                 ReleaseSysCache(tp);
263                 return result;
264         }
265         else
266                 return InvalidAttrNumber;
267 }
268
269 /*
270  * get_atttype
271  *
272  *              Given the relation OID and the attribute number with the relation,
273  *              return the attribute type OID.
274  */
275 Oid
276 get_atttype(Oid relid, AttrNumber attnum)
277 {
278         HeapTuple       tp;
279
280         tp = SearchSysCache(ATTNUM,
281                                                 ObjectIdGetDatum(relid),
282                                                 Int16GetDatum(attnum),
283                                                 0, 0);
284         if (HeapTupleIsValid(tp))
285         {
286                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
287                 Oid                     result;
288
289                 result = att_tup->atttypid;
290                 ReleaseSysCache(tp);
291                 return result;
292         }
293         else
294                 return InvalidOid;
295 }
296
297 /*
298  * get_atttypmod
299  *
300  *              Given the relation id and the attribute number,
301  *              return the "atttypmod" field from the attribute relation.
302  */
303 int32
304 get_atttypmod(Oid relid, AttrNumber attnum)
305 {
306         HeapTuple       tp;
307
308         tp = SearchSysCache(ATTNUM,
309                                                 ObjectIdGetDatum(relid),
310                                                 Int16GetDatum(attnum),
311                                                 0, 0);
312         if (HeapTupleIsValid(tp))
313         {
314                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
315                 int32           result;
316
317                 result = att_tup->atttypmod;
318                 ReleaseSysCache(tp);
319                 return result;
320         }
321         else
322                 return -1;
323 }
324
325 /*
326  * get_atttypetypmod
327  *
328  *              A two-fer: given the relation id and the attribute number,
329  *              fetch both type OID and atttypmod in a single cache lookup.
330  *
331  * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
332  * raises an error if it can't obtain the information.
333  */
334 void
335 get_atttypetypmod(Oid relid, AttrNumber attnum,
336                                   Oid *typid, int32 *typmod)
337 {
338         HeapTuple       tp;
339         Form_pg_attribute att_tup;
340
341         tp = SearchSysCache(ATTNUM,
342                                                 ObjectIdGetDatum(relid),
343                                                 Int16GetDatum(attnum),
344                                                 0, 0);
345         if (!HeapTupleIsValid(tp))
346                 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
347                          attnum, relid);
348         att_tup = (Form_pg_attribute) GETSTRUCT(tp);
349
350         *typid = att_tup->atttypid;
351         *typmod = att_tup->atttypmod;
352         ReleaseSysCache(tp);
353 }
354
355 /*                              ---------- INDEX CACHE ----------                                                */
356
357 /*              watch this space...
358  */
359
360 /*                              ---------- OPCLASS CACHE ----------                                              */
361
362 /*
363  * opclass_is_btree
364  *
365  *              Returns TRUE iff the specified opclass is associated with the
366  *              btree index access method.
367  */
368 bool
369 opclass_is_btree(Oid opclass)
370 {
371         HeapTuple       tp;
372         Form_pg_opclass cla_tup;
373         bool            result;
374
375         tp = SearchSysCache(CLAOID,
376                                                 ObjectIdGetDatum(opclass),
377                                                 0, 0, 0);
378         if (!HeapTupleIsValid(tp))
379                 elog(ERROR, "cache lookup failed for opclass %u", opclass);
380         cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
381
382         result = (cla_tup->opcamid == BTREE_AM_OID);
383         ReleaseSysCache(tp);
384         return result;
385 }
386
387 /*
388  * opclass_is_hash
389  *
390  *              Returns TRUE iff the specified opclass is associated with the
391  *              hash index access method.
392  */
393 bool
394 opclass_is_hash(Oid opclass)
395 {
396         HeapTuple       tp;
397         Form_pg_opclass cla_tup;
398         bool            result;
399
400         tp = SearchSysCache(CLAOID,
401                                                 ObjectIdGetDatum(opclass),
402                                                 0, 0, 0);
403         if (!HeapTupleIsValid(tp))
404                 elog(ERROR, "cache lookup failed for opclass %u", opclass);
405         cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
406
407         result = (cla_tup->opcamid == HASH_AM_OID);
408         ReleaseSysCache(tp);
409         return result;
410 }
411
412 /*                              ---------- OPERATOR CACHE ----------                                     */
413
414 /*
415  * get_opcode
416  *
417  *              Returns the regproc id of the routine used to implement an
418  *              operator given the operator oid.
419  */
420 RegProcedure
421 get_opcode(Oid opno)
422 {
423         HeapTuple       tp;
424
425         tp = SearchSysCache(OPEROID,
426                                                 ObjectIdGetDatum(opno),
427                                                 0, 0, 0);
428         if (HeapTupleIsValid(tp))
429         {
430                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
431                 RegProcedure result;
432
433                 result = optup->oprcode;
434                 ReleaseSysCache(tp);
435                 return result;
436         }
437         else
438                 return (RegProcedure) InvalidOid;
439 }
440
441 /*
442  * get_opname
443  *        returns the name of the operator with the given opno
444  *
445  * Note: returns a palloc'd copy of the string, or NULL if no such operator.
446  */
447 char *
448 get_opname(Oid opno)
449 {
450         HeapTuple       tp;
451
452         tp = SearchSysCache(OPEROID,
453                                                 ObjectIdGetDatum(opno),
454                                                 0, 0, 0);
455         if (HeapTupleIsValid(tp))
456         {
457                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
458                 char       *result;
459
460                 result = pstrdup(NameStr(optup->oprname));
461                 ReleaseSysCache(tp);
462                 return result;
463         }
464         else
465                 return NULL;
466 }
467
468 /*
469  * op_input_types
470  *
471  *              Returns the left and right input datatypes for an operator
472  *              (InvalidOid if not relevant).
473  */
474 void
475 op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
476 {
477         HeapTuple       tp;
478         Form_pg_operator optup;
479
480         tp = SearchSysCache(OPEROID,
481                                                 ObjectIdGetDatum(opno),
482                                                 0, 0, 0);
483         if (!HeapTupleIsValid(tp))      /* shouldn't happen */
484                 elog(ERROR, "cache lookup failed for operator %u", opno);
485         optup = (Form_pg_operator) GETSTRUCT(tp);
486         *lefttype = optup->oprleft;
487         *righttype = optup->oprright;
488         ReleaseSysCache(tp);
489 }
490
491 /*
492  * op_mergejoinable
493  *
494  *              Returns the left and right sort operators corresponding to a
495  *              mergejoinable operator, or false if the operator is not mergejoinable.
496  */
497 bool
498 op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp)
499 {
500         HeapTuple       tp;
501         bool            result = false;
502
503         tp = SearchSysCache(OPEROID,
504                                                 ObjectIdGetDatum(opno),
505                                                 0, 0, 0);
506         if (HeapTupleIsValid(tp))
507         {
508                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
509
510                 if (optup->oprlsortop &&
511                         optup->oprrsortop)
512                 {
513                         *leftOp = optup->oprlsortop;
514                         *rightOp = optup->oprrsortop;
515                         result = true;
516                 }
517                 ReleaseSysCache(tp);
518         }
519         return result;
520 }
521
522 /*
523  * op_mergejoin_crossops
524  *
525  *              Returns the cross-type comparison operators (ltype "<" rtype and
526  *              ltype ">" rtype) for an operator previously determined to be
527  *              mergejoinable.  Optionally, fetches the regproc ids of these
528  *              operators, as well as their operator OIDs.
529  */
530 void
531 op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
532                                           RegProcedure *ltproc, RegProcedure *gtproc)
533 {
534         HeapTuple       tp;
535         Form_pg_operator optup;
536
537         /*
538          * Get the declared comparison operators of the operator.
539          */
540         tp = SearchSysCache(OPEROID,
541                                                 ObjectIdGetDatum(opno),
542                                                 0, 0, 0);
543         if (!HeapTupleIsValid(tp))      /* shouldn't happen */
544                 elog(ERROR, "cache lookup failed for operator %u", opno);
545         optup = (Form_pg_operator) GETSTRUCT(tp);
546         *ltop = optup->oprltcmpop;
547         *gtop = optup->oprgtcmpop;
548         ReleaseSysCache(tp);
549
550         /* Check < op provided */
551         if (!OidIsValid(*ltop))
552                 elog(ERROR, "mergejoin operator %u has no matching < operator",
553                          opno);
554         if (ltproc)
555                 *ltproc = get_opcode(*ltop);
556
557         /* Check > op provided */
558         if (!OidIsValid(*gtop))
559                 elog(ERROR, "mergejoin operator %u has no matching > operator",
560                          opno);
561         if (gtproc)
562                 *gtproc = get_opcode(*gtop);
563 }
564
565 /*
566  * op_hashjoinable
567  *
568  * Returns true if the operator is hashjoinable.
569  */
570 bool
571 op_hashjoinable(Oid opno)
572 {
573         HeapTuple       tp;
574         bool            result = false;
575
576         tp = SearchSysCache(OPEROID,
577                                                 ObjectIdGetDatum(opno),
578                                                 0, 0, 0);
579         if (HeapTupleIsValid(tp))
580         {
581                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
582
583                 result = optup->oprcanhash;
584                 ReleaseSysCache(tp);
585         }
586         return result;
587 }
588
589 /*
590  * op_strict
591  *
592  * Get the proisstrict flag for the operator's underlying function.
593  */
594 bool
595 op_strict(Oid opno)
596 {
597         RegProcedure funcid = get_opcode(opno);
598
599         if (funcid == (RegProcedure) InvalidOid)
600                 elog(ERROR, "operator %u does not exist", opno);
601
602         return func_strict((Oid) funcid);
603 }
604
605 /*
606  * op_volatile
607  *
608  * Get the provolatile flag for the operator's underlying function.
609  */
610 char
611 op_volatile(Oid opno)
612 {
613         RegProcedure funcid = get_opcode(opno);
614
615         if (funcid == (RegProcedure) InvalidOid)
616                 elog(ERROR, "operator %u does not exist", opno);
617
618         return func_volatile((Oid) funcid);
619 }
620
621 /*
622  * get_commutator
623  *
624  *              Returns the corresponding commutator of an operator.
625  */
626 Oid
627 get_commutator(Oid opno)
628 {
629         HeapTuple       tp;
630
631         tp = SearchSysCache(OPEROID,
632                                                 ObjectIdGetDatum(opno),
633                                                 0, 0, 0);
634         if (HeapTupleIsValid(tp))
635         {
636                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
637                 Oid                     result;
638
639                 result = optup->oprcom;
640                 ReleaseSysCache(tp);
641                 return result;
642         }
643         else
644                 return InvalidOid;
645 }
646
647 /*
648  * get_negator
649  *
650  *              Returns the corresponding negator of an operator.
651  */
652 Oid
653 get_negator(Oid opno)
654 {
655         HeapTuple       tp;
656
657         tp = SearchSysCache(OPEROID,
658                                                 ObjectIdGetDatum(opno),
659                                                 0, 0, 0);
660         if (HeapTupleIsValid(tp))
661         {
662                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
663                 Oid                     result;
664
665                 result = optup->oprnegate;
666                 ReleaseSysCache(tp);
667                 return result;
668         }
669         else
670                 return InvalidOid;
671 }
672
673 /*
674  * get_oprrest
675  *
676  *              Returns procedure id for computing selectivity of an operator.
677  */
678 RegProcedure
679 get_oprrest(Oid opno)
680 {
681         HeapTuple       tp;
682
683         tp = SearchSysCache(OPEROID,
684                                                 ObjectIdGetDatum(opno),
685                                                 0, 0, 0);
686         if (HeapTupleIsValid(tp))
687         {
688                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
689                 RegProcedure result;
690
691                 result = optup->oprrest;
692                 ReleaseSysCache(tp);
693                 return result;
694         }
695         else
696                 return (RegProcedure) InvalidOid;
697 }
698
699 /*
700  * get_oprjoin
701  *
702  *              Returns procedure id for computing selectivity of a join.
703  */
704 RegProcedure
705 get_oprjoin(Oid opno)
706 {
707         HeapTuple       tp;
708
709         tp = SearchSysCache(OPEROID,
710                                                 ObjectIdGetDatum(opno),
711                                                 0, 0, 0);
712         if (HeapTupleIsValid(tp))
713         {
714                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
715                 RegProcedure result;
716
717                 result = optup->oprjoin;
718                 ReleaseSysCache(tp);
719                 return result;
720         }
721         else
722                 return (RegProcedure) InvalidOid;
723 }
724
725 /*                              ---------- FUNCTION CACHE ----------                                     */
726
727 /*
728  * get_func_name
729  *        returns the name of the function with the given funcid
730  *
731  * Note: returns a palloc'd copy of the string, or NULL if no such function.
732  */
733 char *
734 get_func_name(Oid funcid)
735 {
736         HeapTuple       tp;
737
738         tp = SearchSysCache(PROCOID,
739                                                 ObjectIdGetDatum(funcid),
740                                                 0, 0, 0);
741         if (HeapTupleIsValid(tp))
742         {
743                 Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
744                 char       *result;
745
746                 result = pstrdup(NameStr(functup->proname));
747                 ReleaseSysCache(tp);
748                 return result;
749         }
750         else
751                 return NULL;
752 }
753
754 /*
755  * get_func_rettype
756  *              Given procedure id, return the function's result type.
757  */
758 Oid
759 get_func_rettype(Oid funcid)
760 {
761         HeapTuple       tp;
762         Oid                     result;
763
764         tp = SearchSysCache(PROCOID,
765                                                 ObjectIdGetDatum(funcid),
766                                                 0, 0, 0);
767         if (!HeapTupleIsValid(tp))
768                 elog(ERROR, "cache lookup failed for function %u", funcid);
769
770         result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
771         ReleaseSysCache(tp);
772         return result;
773 }
774
775 /*
776  * get_func_signature
777  *              Given procedure id, return the function's argument and result types.
778  *              (The return value is the result type.)
779  *
780  * argtypes must point to a vector of size FUNC_MAX_ARGS.
781  */
782 Oid
783 get_func_signature(Oid funcid, Oid *argtypes, int *nargs)
784 {
785         HeapTuple       tp;
786         Form_pg_proc procstruct;
787         Oid                     result;
788
789         tp = SearchSysCache(PROCOID,
790                                                 ObjectIdGetDatum(funcid),
791                                                 0, 0, 0);
792         if (!HeapTupleIsValid(tp))
793                 elog(ERROR, "cache lookup failed for function %u", funcid);
794
795         procstruct = (Form_pg_proc) GETSTRUCT(tp);
796
797         result = procstruct->prorettype;
798         memcpy(argtypes, procstruct->proargtypes, FUNC_MAX_ARGS * sizeof(Oid));
799         *nargs = (int) procstruct->pronargs;
800
801         ReleaseSysCache(tp);
802         return result;
803 }
804
805 /*
806  * get_func_retset
807  *              Given procedure id, return the function's proretset flag.
808  */
809 bool
810 get_func_retset(Oid funcid)
811 {
812         HeapTuple       tp;
813         bool            result;
814
815         tp = SearchSysCache(PROCOID,
816                                                 ObjectIdGetDatum(funcid),
817                                                 0, 0, 0);
818         if (!HeapTupleIsValid(tp))
819                 elog(ERROR, "cache lookup failed for function %u", funcid);
820
821         result = ((Form_pg_proc) GETSTRUCT(tp))->proretset;
822         ReleaseSysCache(tp);
823         return result;
824 }
825
826 /*
827  * func_strict
828  *              Given procedure id, return the function's proisstrict flag.
829  */
830 bool
831 func_strict(Oid funcid)
832 {
833         HeapTuple       tp;
834         bool            result;
835
836         tp = SearchSysCache(PROCOID,
837                                                 ObjectIdGetDatum(funcid),
838                                                 0, 0, 0);
839         if (!HeapTupleIsValid(tp))
840                 elog(ERROR, "cache lookup failed for function %u", funcid);
841
842         result = ((Form_pg_proc) GETSTRUCT(tp))->proisstrict;
843         ReleaseSysCache(tp);
844         return result;
845 }
846
847 /*
848  * func_volatile
849  *              Given procedure id, return the function's provolatile flag.
850  */
851 char
852 func_volatile(Oid funcid)
853 {
854         HeapTuple       tp;
855         char            result;
856
857         tp = SearchSysCache(PROCOID,
858                                                 ObjectIdGetDatum(funcid),
859                                                 0, 0, 0);
860         if (!HeapTupleIsValid(tp))
861                 elog(ERROR, "cache lookup failed for function %u", funcid);
862
863         result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
864         ReleaseSysCache(tp);
865         return result;
866 }
867
868 /*                              ---------- RELATION CACHE ----------                                     */
869
870 /*
871  * get_relname_relid
872  *              Given name and namespace of a relation, look up the OID.
873  *
874  * Returns InvalidOid if there is no such relation.
875  */
876 Oid
877 get_relname_relid(const char *relname, Oid relnamespace)
878 {
879         return GetSysCacheOid(RELNAMENSP,
880                                                   PointerGetDatum(relname),
881                                                   ObjectIdGetDatum(relnamespace),
882                                                   0, 0);
883 }
884
885 /*
886  * get_system_catalog_relid
887  *              Get the OID of a system catalog identified by name.
888  */
889 Oid
890 get_system_catalog_relid(const char *catname)
891 {
892         Oid                     relid;
893
894         relid = GetSysCacheOid(RELNAMENSP,
895                                                    PointerGetDatum(catname),
896                                                    ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
897                                                    0, 0);
898         if (!OidIsValid(relid))
899                 elog(ERROR, "cache lookup failed for system relation %s", catname);
900
901         return relid;
902 }
903
904 #ifdef NOT_USED
905 /*
906  * get_relnatts
907  *
908  *              Returns the number of attributes for a given relation.
909  */
910 int
911 get_relnatts(Oid relid)
912 {
913         HeapTuple       tp;
914
915         tp = SearchSysCache(RELOID,
916                                                 ObjectIdGetDatum(relid),
917                                                 0, 0, 0);
918         if (HeapTupleIsValid(tp))
919         {
920                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
921                 int                     result;
922
923                 result = reltup->relnatts;
924                 ReleaseSysCache(tp);
925                 return result;
926         }
927         else
928                 return InvalidAttrNumber;
929 }
930 #endif
931
932 /*
933  * get_rel_name
934  *              Returns the name of a given relation.
935  *
936  * Returns a palloc'd copy of the string, or NULL if no such relation.
937  *
938  * NOTE: since relation name is not unique, be wary of code that uses this
939  * for anything except preparing error messages.
940  */
941 char *
942 get_rel_name(Oid relid)
943 {
944         HeapTuple       tp;
945
946         tp = SearchSysCache(RELOID,
947                                                 ObjectIdGetDatum(relid),
948                                                 0, 0, 0);
949         if (HeapTupleIsValid(tp))
950         {
951                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
952                 char       *result;
953
954                 result = pstrdup(NameStr(reltup->relname));
955                 ReleaseSysCache(tp);
956                 return result;
957         }
958         else
959                 return NULL;
960 }
961
962 /*
963  * get_rel_namespace
964  *
965  *              Returns the pg_namespace OID associated with a given relation.
966  */
967 Oid
968 get_rel_namespace(Oid relid)
969 {
970         HeapTuple       tp;
971
972         tp = SearchSysCache(RELOID,
973                                                 ObjectIdGetDatum(relid),
974                                                 0, 0, 0);
975         if (HeapTupleIsValid(tp))
976         {
977                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
978                 Oid                     result;
979
980                 result = reltup->relnamespace;
981                 ReleaseSysCache(tp);
982                 return result;
983         }
984         else
985                 return InvalidOid;
986 }
987
988 /*
989  * get_rel_type_id
990  *
991  *              Returns the pg_type OID associated with a given relation.
992  *
993  * Note: not all pg_class entries have associated pg_type OIDs; so be
994  * careful to check for InvalidOid result.
995  */
996 Oid
997 get_rel_type_id(Oid relid)
998 {
999         HeapTuple       tp;
1000
1001         tp = SearchSysCache(RELOID,
1002                                                 ObjectIdGetDatum(relid),
1003                                                 0, 0, 0);
1004         if (HeapTupleIsValid(tp))
1005         {
1006                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1007                 Oid                     result;
1008
1009                 result = reltup->reltype;
1010                 ReleaseSysCache(tp);
1011                 return result;
1012         }
1013         else
1014                 return InvalidOid;
1015 }
1016
1017 /*
1018  * get_rel_relkind
1019  *
1020  *              Returns the relkind associated with a given relation.
1021  */
1022 char
1023 get_rel_relkind(Oid relid)
1024 {
1025         HeapTuple       tp;
1026
1027         tp = SearchSysCache(RELOID,
1028                                                 ObjectIdGetDatum(relid),
1029                                                 0, 0, 0);
1030         if (HeapTupleIsValid(tp))
1031         {
1032                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1033                 char            result;
1034
1035                 result = reltup->relkind;
1036                 ReleaseSysCache(tp);
1037                 return result;
1038         }
1039         else
1040                 return '\0';
1041 }
1042
1043
1044 /*                              ---------- TYPE CACHE ----------                                                 */
1045
1046 /*
1047  * get_typisdefined
1048  *
1049  *              Given the type OID, determine whether the type is defined
1050  *              (if not, it's only a shell).
1051  */
1052 bool
1053 get_typisdefined(Oid typid)
1054 {
1055         HeapTuple       tp;
1056
1057         tp = SearchSysCache(TYPEOID,
1058                                                 ObjectIdGetDatum(typid),
1059                                                 0, 0, 0);
1060         if (HeapTupleIsValid(tp))
1061         {
1062                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1063                 bool            result;
1064
1065                 result = typtup->typisdefined;
1066                 ReleaseSysCache(tp);
1067                 return result;
1068         }
1069         else
1070                 return false;
1071 }
1072
1073 /*
1074  * get_typlen
1075  *
1076  *              Given the type OID, return the length of the type.
1077  */
1078 int16
1079 get_typlen(Oid typid)
1080 {
1081         HeapTuple       tp;
1082
1083         tp = SearchSysCache(TYPEOID,
1084                                                 ObjectIdGetDatum(typid),
1085                                                 0, 0, 0);
1086         if (HeapTupleIsValid(tp))
1087         {
1088                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1089                 int16           result;
1090
1091                 result = typtup->typlen;
1092                 ReleaseSysCache(tp);
1093                 return result;
1094         }
1095         else
1096                 return 0;
1097 }
1098
1099 /*
1100  * get_typbyval
1101  *
1102  *              Given the type OID, determine whether the type is returned by value or
1103  *              not.  Returns true if by value, false if by reference.
1104  */
1105 bool
1106 get_typbyval(Oid typid)
1107 {
1108         HeapTuple       tp;
1109
1110         tp = SearchSysCache(TYPEOID,
1111                                                 ObjectIdGetDatum(typid),
1112                                                 0, 0, 0);
1113         if (HeapTupleIsValid(tp))
1114         {
1115                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1116                 bool            result;
1117
1118                 result = typtup->typbyval;
1119                 ReleaseSysCache(tp);
1120                 return result;
1121         }
1122         else
1123                 return false;
1124 }
1125
1126 /*
1127  * get_typlenbyval
1128  *
1129  *              A two-fer: given the type OID, return both typlen and typbyval.
1130  *
1131  *              Since both pieces of info are needed to know how to copy a Datum,
1132  *              many places need both.  Might as well get them with one cache lookup
1133  *              instead of two.  Also, this routine raises an error instead of
1134  *              returning a bogus value when given a bad type OID.
1135  */
1136 void
1137 get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
1138 {
1139         HeapTuple       tp;
1140         Form_pg_type typtup;
1141
1142         tp = SearchSysCache(TYPEOID,
1143                                                 ObjectIdGetDatum(typid),
1144                                                 0, 0, 0);
1145         if (!HeapTupleIsValid(tp))
1146                 elog(ERROR, "cache lookup failed for type %u", typid);
1147         typtup = (Form_pg_type) GETSTRUCT(tp);
1148         *typlen = typtup->typlen;
1149         *typbyval = typtup->typbyval;
1150         ReleaseSysCache(tp);
1151 }
1152
1153 /*
1154  * get_typlenbyvalalign
1155  *
1156  *              A three-fer: given the type OID, return typlen, typbyval, typalign.
1157  */
1158 void
1159 get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
1160                                          char *typalign)
1161 {
1162         HeapTuple       tp;
1163         Form_pg_type typtup;
1164
1165         tp = SearchSysCache(TYPEOID,
1166                                                 ObjectIdGetDatum(typid),
1167                                                 0, 0, 0);
1168         if (!HeapTupleIsValid(tp))
1169                 elog(ERROR, "cache lookup failed for type %u", typid);
1170         typtup = (Form_pg_type) GETSTRUCT(tp);
1171         *typlen = typtup->typlen;
1172         *typbyval = typtup->typbyval;
1173         *typalign = typtup->typalign;
1174         ReleaseSysCache(tp);
1175 }
1176
1177 /*
1178  * get_type_io_data
1179  *
1180  *              A six-fer:      given the type OID, return typlen, typbyval, typalign,
1181  *                                      typdelim, typelem, and IO function OID. The IO function
1182  *                                      returned is controlled by IOFuncSelector
1183  */
1184 void
1185 get_type_io_data(Oid typid,
1186                                  IOFuncSelector which_func,
1187                                  int16 *typlen,
1188                                  bool *typbyval,
1189                                  char *typalign,
1190                                  char *typdelim,
1191                                  Oid *typelem,
1192                                  Oid *func)
1193 {
1194         HeapTuple       typeTuple;
1195         Form_pg_type typeStruct;
1196
1197         typeTuple = SearchSysCache(TYPEOID,
1198                                                            ObjectIdGetDatum(typid),
1199                                                            0, 0, 0);
1200         if (!HeapTupleIsValid(typeTuple))
1201                 elog(ERROR, "cache lookup failed for type %u", typid);
1202         typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
1203
1204         *typlen = typeStruct->typlen;
1205         *typbyval = typeStruct->typbyval;
1206         *typalign = typeStruct->typalign;
1207         *typdelim = typeStruct->typdelim;
1208         *typelem = typeStruct->typelem;
1209         switch (which_func)
1210         {
1211                 case IOFunc_input:
1212                         *func = typeStruct->typinput;
1213                         break;
1214                 case IOFunc_output:
1215                         *func = typeStruct->typoutput;
1216                         break;
1217                 case IOFunc_receive:
1218                         *func = typeStruct->typreceive;
1219                         break;
1220                 case IOFunc_send:
1221                         *func = typeStruct->typsend;
1222                         break;
1223         }
1224         ReleaseSysCache(typeTuple);
1225 }
1226
1227 #ifdef NOT_USED
1228 char
1229 get_typalign(Oid typid)
1230 {
1231         HeapTuple       tp;
1232
1233         tp = SearchSysCache(TYPEOID,
1234                                                 ObjectIdGetDatum(typid),
1235                                                 0, 0, 0);
1236         if (HeapTupleIsValid(tp))
1237         {
1238                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1239                 char            result;
1240
1241                 result = typtup->typalign;
1242                 ReleaseSysCache(tp);
1243                 return result;
1244         }
1245         else
1246                 return 'i';
1247 }
1248 #endif
1249
1250 char
1251 get_typstorage(Oid typid)
1252 {
1253         HeapTuple       tp;
1254
1255         tp = SearchSysCache(TYPEOID,
1256                                                 ObjectIdGetDatum(typid),
1257                                                 0, 0, 0);
1258         if (HeapTupleIsValid(tp))
1259         {
1260                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1261                 char            result;
1262
1263                 result = typtup->typstorage;
1264                 ReleaseSysCache(tp);
1265                 return result;
1266         }
1267         else
1268                 return 'p';
1269 }
1270
1271 /*
1272  * get_typtypmod
1273  *
1274  *              Given the type OID, return the typtypmod field (domain's typmod
1275  *              for base type)
1276  */
1277 int32
1278 get_typtypmod(Oid typid)
1279 {
1280         HeapTuple       tp;
1281
1282         tp = SearchSysCache(TYPEOID,
1283                                                 ObjectIdGetDatum(typid),
1284                                                 0, 0, 0);
1285         if (HeapTupleIsValid(tp))
1286         {
1287                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1288                 int32           result;
1289
1290                 result = typtup->typtypmod;
1291                 ReleaseSysCache(tp);
1292                 return result;
1293         }
1294         else
1295                 return -1;
1296 }
1297
1298 /*
1299  * get_typdefault
1300  *        Given a type OID, return the type's default value, if any.
1301  *
1302  *        The result is a palloc'd expression node tree, or NULL if there
1303  *        is no defined default for the datatype.
1304  *
1305  * NB: caller should be prepared to coerce result to correct datatype;
1306  * the returned expression tree might produce something of the wrong type.
1307  */
1308 Node *
1309 get_typdefault(Oid typid)
1310 {
1311         HeapTuple       typeTuple;
1312         Form_pg_type type;
1313         Datum           datum;
1314         bool            isNull;
1315         Node       *expr;
1316
1317         typeTuple = SearchSysCache(TYPEOID,
1318                                                            ObjectIdGetDatum(typid),
1319                                                            0, 0, 0);
1320         if (!HeapTupleIsValid(typeTuple))
1321                 elog(ERROR, "cache lookup failed for type %u", typid);
1322         type = (Form_pg_type) GETSTRUCT(typeTuple);
1323
1324         /*
1325          * typdefault and typdefaultbin are potentially null, so don't try to
1326          * access 'em as struct fields. Must do it the hard way with
1327          * SysCacheGetAttr.
1328          */
1329         datum = SysCacheGetAttr(TYPEOID,
1330                                                         typeTuple,
1331                                                         Anum_pg_type_typdefaultbin,
1332                                                         &isNull);
1333
1334         if (!isNull)
1335         {
1336                 /* We have an expression default */
1337                 expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
1338                                                                                                                                 datum)));
1339         }
1340         else
1341         {
1342                 /* Perhaps we have a plain literal default */
1343                 datum = SysCacheGetAttr(TYPEOID,
1344                                                                 typeTuple,
1345                                                                 Anum_pg_type_typdefault,
1346                                                                 &isNull);
1347
1348                 if (!isNull)
1349                 {
1350                         char       *strDefaultVal;
1351
1352                         /* Convert text datum to C string */
1353                         strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
1354                                                                                                                                 datum));
1355                         /* Convert C string to a value of the given type */
1356                         datum = OidFunctionCall3(type->typinput,
1357                                                                          CStringGetDatum(strDefaultVal),
1358                                                                          ObjectIdGetDatum(type->typelem),
1359                                                                          Int32GetDatum(-1));
1360                         /* Build a Const node containing the value */
1361                         expr = (Node *) makeConst(typid,
1362                                                                           type->typlen,
1363                                                                           datum,
1364                                                                           false,
1365                                                                           type->typbyval);
1366                         pfree(strDefaultVal);
1367                 }
1368                 else
1369                 {
1370                         /* No default */
1371                         expr = NULL;
1372                 }
1373         }
1374
1375         ReleaseSysCache(typeTuple);
1376
1377         return expr;
1378 }
1379
1380 /*
1381  * getBaseType
1382  *              If the given type is a domain, return its base type;
1383  *              otherwise return the type's own OID.
1384  */
1385 Oid
1386 getBaseType(Oid typid)
1387 {
1388         /*
1389          * We loop to find the bottom base type in a stack of domains.
1390          */
1391         for (;;)
1392         {
1393                 HeapTuple       tup;
1394                 Form_pg_type typTup;
1395
1396                 tup = SearchSysCache(TYPEOID,
1397                                                          ObjectIdGetDatum(typid),
1398                                                          0, 0, 0);
1399                 if (!HeapTupleIsValid(tup))
1400                         elog(ERROR, "cache lookup failed for type %u", typid);
1401                 typTup = (Form_pg_type) GETSTRUCT(tup);
1402                 if (typTup->typtype != 'd')
1403                 {
1404                         /* Not a domain, so done */
1405                         ReleaseSysCache(tup);
1406                         break;
1407                 }
1408
1409                 typid = typTup->typbasetype;
1410                 ReleaseSysCache(tup);
1411         }
1412
1413         return typid;
1414 }
1415
1416 /*
1417  * get_typavgwidth
1418  *
1419  *        Given a type OID and a typmod value (pass -1 if typmod is unknown),
1420  *        estimate the average width of values of the type.  This is used by
1421  *        the planner, which doesn't require absolutely correct results;
1422  *        it's OK (and expected) to guess if we don't know for sure.
1423  */
1424 int32
1425 get_typavgwidth(Oid typid, int32 typmod)
1426 {
1427         int                     typlen = get_typlen(typid);
1428         int32           maxwidth;
1429
1430         /*
1431          * Easy if it's a fixed-width type
1432          */
1433         if (typlen > 0)
1434                 return typlen;
1435
1436         /*
1437          * type_maximum_size knows the encoding of typmod for some datatypes;
1438          * don't duplicate that knowledge here.
1439          */
1440         maxwidth = type_maximum_size(typid, typmod);
1441         if (maxwidth > 0)
1442         {
1443                 /*
1444                  * For BPCHAR, the max width is also the only width.  Otherwise we
1445                  * need to guess about the typical data width given the max. A
1446                  * sliding scale for percentage of max width seems reasonable.
1447                  */
1448                 if (typid == BPCHAROID)
1449                         return maxwidth;
1450                 if (maxwidth <= 32)
1451                         return maxwidth;        /* assume full width */
1452                 if (maxwidth < 1000)
1453                         return 32 + (maxwidth - 32) / 2;        /* assume 50% */
1454
1455                 /*
1456                  * Beyond 1000, assume we're looking at something like
1457                  * "varchar(10000)" where the limit isn't actually reached often,
1458                  * and use a fixed estimate.
1459                  */
1460                 return 32 + (1000 - 32) / 2;
1461         }
1462
1463         /*
1464          * Ooops, we have no idea ... wild guess time.
1465          */
1466         return 32;
1467 }
1468
1469 /*
1470  * get_typtype
1471  *
1472  *              Given the type OID, find if it is a basic type, a complex type, etc.
1473  *              It returns the null char if the cache lookup fails...
1474  */
1475 char
1476 get_typtype(Oid typid)
1477 {
1478         HeapTuple       tp;
1479
1480         tp = SearchSysCache(TYPEOID,
1481                                                 ObjectIdGetDatum(typid),
1482                                                 0, 0, 0);
1483         if (HeapTupleIsValid(tp))
1484         {
1485                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1486                 char            result;
1487
1488                 result = typtup->typtype;
1489                 ReleaseSysCache(tp);
1490                 return result;
1491         }
1492         else
1493                 return '\0';
1494 }
1495
1496 /*
1497  * get_typ_typrelid
1498  *
1499  *              Given the type OID, get the typrelid (InvalidOid if not a complex
1500  *              type).
1501  */
1502 Oid
1503 get_typ_typrelid(Oid typid)
1504 {
1505         HeapTuple       tp;
1506
1507         tp = SearchSysCache(TYPEOID,
1508                                                 ObjectIdGetDatum(typid),
1509                                                 0, 0, 0);
1510         if (HeapTupleIsValid(tp))
1511         {
1512                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1513                 Oid                     result;
1514
1515                 result = typtup->typrelid;
1516                 ReleaseSysCache(tp);
1517                 return result;
1518         }
1519         else
1520                 return InvalidOid;
1521 }
1522
1523 /*
1524  * get_element_type
1525  *
1526  *              Given the type OID, get the typelem (InvalidOid if not an array type).
1527  *
1528  * NB: this only considers varlena arrays to be true arrays; InvalidOid is
1529  * returned if the input is a fixed-length array type.
1530  */
1531 Oid
1532 get_element_type(Oid typid)
1533 {
1534         HeapTuple       tp;
1535
1536         tp = SearchSysCache(TYPEOID,
1537                                                 ObjectIdGetDatum(typid),
1538                                                 0, 0, 0);
1539         if (HeapTupleIsValid(tp))
1540         {
1541                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1542                 Oid                     result;
1543
1544                 if (typtup->typlen == -1)
1545                         result = typtup->typelem;
1546                 else
1547                         result = InvalidOid;
1548                 ReleaseSysCache(tp);
1549                 return result;
1550         }
1551         else
1552                 return InvalidOid;
1553 }
1554
1555 /*
1556  * get_array_type
1557  *
1558  *              Given the type OID, get the corresponding array type.
1559  *              Returns InvalidOid if no array type can be found.
1560  *
1561  * NB: this only considers varlena arrays to be true arrays.
1562  */
1563 Oid
1564 get_array_type(Oid typid)
1565 {
1566         HeapTuple       tp;
1567
1568         tp = SearchSysCache(TYPEOID,
1569                                                 ObjectIdGetDatum(typid),
1570                                                 0, 0, 0);
1571         if (HeapTupleIsValid(tp))
1572         {
1573                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1574                 char       *array_typename;
1575                 Oid                     namespaceId;
1576
1577                 array_typename = makeArrayTypeName(NameStr(typtup->typname));
1578                 namespaceId = typtup->typnamespace;
1579                 ReleaseSysCache(tp);
1580
1581                 tp = SearchSysCache(TYPENAMENSP,
1582                                                         PointerGetDatum(array_typename),
1583                                                         ObjectIdGetDatum(namespaceId),
1584                                                         0, 0);
1585
1586                 pfree(array_typename);
1587
1588                 if (HeapTupleIsValid(tp))
1589                 {
1590                         Oid                     result;
1591
1592                         typtup = (Form_pg_type) GETSTRUCT(tp);
1593                         if (typtup->typlen == -1 && typtup->typelem == typid)
1594                                 result = HeapTupleGetOid(tp);
1595                         else
1596                                 result = InvalidOid;
1597                         ReleaseSysCache(tp);
1598                         return result;
1599                 }
1600         }
1601         return InvalidOid;
1602 }
1603
1604 /*
1605  * getTypeInputInfo
1606  *
1607  *              Get info needed for converting values of a type to internal form
1608  */
1609 void
1610 getTypeInputInfo(Oid type, Oid *typInput, Oid *typElem)
1611 {
1612         HeapTuple       typeTuple;
1613         Form_pg_type pt;
1614
1615         typeTuple = SearchSysCache(TYPEOID,
1616                                                            ObjectIdGetDatum(type),
1617                                                            0, 0, 0);
1618         if (!HeapTupleIsValid(typeTuple))
1619                 elog(ERROR, "cache lookup failed for type %u", type);
1620         pt = (Form_pg_type) GETSTRUCT(typeTuple);
1621
1622         if (!pt->typisdefined)
1623                 ereport(ERROR,
1624                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1625                                  errmsg("type %s is only a shell",
1626                                                 format_type_be(type))));
1627         if (!OidIsValid(pt->typinput))
1628                 ereport(ERROR,
1629                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1630                                  errmsg("no input function available for type %s",
1631                                                 format_type_be(type))));
1632
1633         *typInput = pt->typinput;
1634         *typElem = pt->typelem;
1635
1636         ReleaseSysCache(typeTuple);
1637 }
1638
1639 /*
1640  * getTypeOutputInfo
1641  *
1642  *              Get info needed for printing values of a type
1643  */
1644 void
1645 getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
1646                                   bool *typIsVarlena)
1647 {
1648         HeapTuple       typeTuple;
1649         Form_pg_type pt;
1650
1651         typeTuple = SearchSysCache(TYPEOID,
1652                                                            ObjectIdGetDatum(type),
1653                                                            0, 0, 0);
1654         if (!HeapTupleIsValid(typeTuple))
1655                 elog(ERROR, "cache lookup failed for type %u", type);
1656         pt = (Form_pg_type) GETSTRUCT(typeTuple);
1657
1658         if (!pt->typisdefined)
1659                 ereport(ERROR,
1660                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1661                                  errmsg("type %s is only a shell",
1662                                                 format_type_be(type))));
1663         if (!OidIsValid(pt->typoutput))
1664                 ereport(ERROR,
1665                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1666                                  errmsg("no output function available for type %s",
1667                                                 format_type_be(type))));
1668
1669         *typOutput = pt->typoutput;
1670         *typElem = pt->typelem;
1671         *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
1672
1673         ReleaseSysCache(typeTuple);
1674 }
1675
1676 /*
1677  * getTypeBinaryInputInfo
1678  *
1679  *              Get info needed for binary input of values of a type
1680  */
1681 void
1682 getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typElem)
1683 {
1684         HeapTuple       typeTuple;
1685         Form_pg_type pt;
1686
1687         typeTuple = SearchSysCache(TYPEOID,
1688                                                            ObjectIdGetDatum(type),
1689                                                            0, 0, 0);
1690         if (!HeapTupleIsValid(typeTuple))
1691                 elog(ERROR, "cache lookup failed for type %u", type);
1692         pt = (Form_pg_type) GETSTRUCT(typeTuple);
1693
1694         if (!pt->typisdefined)
1695                 ereport(ERROR,
1696                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1697                                  errmsg("type %s is only a shell",
1698                                                 format_type_be(type))));
1699         if (!OidIsValid(pt->typreceive))
1700                 ereport(ERROR,
1701                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1702                                  errmsg("no binary input function available for type %s",
1703                                                 format_type_be(type))));
1704
1705         *typReceive = pt->typreceive;
1706         *typElem = pt->typelem;
1707
1708         ReleaseSysCache(typeTuple);
1709 }
1710
1711 /*
1712  * getTypeBinaryOutputInfo
1713  *
1714  *              Get info needed for binary output of values of a type
1715  */
1716 void
1717 getTypeBinaryOutputInfo(Oid type, Oid *typSend, Oid *typElem,
1718                                                 bool *typIsVarlena)
1719 {
1720         HeapTuple       typeTuple;
1721         Form_pg_type pt;
1722
1723         typeTuple = SearchSysCache(TYPEOID,
1724                                                            ObjectIdGetDatum(type),
1725                                                            0, 0, 0);
1726         if (!HeapTupleIsValid(typeTuple))
1727                 elog(ERROR, "cache lookup failed for type %u", type);
1728         pt = (Form_pg_type) GETSTRUCT(typeTuple);
1729
1730         if (!pt->typisdefined)
1731                 ereport(ERROR,
1732                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1733                                  errmsg("type %s is only a shell",
1734                                                 format_type_be(type))));
1735         if (!OidIsValid(pt->typsend))
1736                 ereport(ERROR,
1737                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1738                                  errmsg("no binary output function available for type %s",
1739                                                 format_type_be(type))));
1740
1741         *typSend = pt->typsend;
1742         *typElem = pt->typelem;
1743         *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
1744
1745         ReleaseSysCache(typeTuple);
1746 }
1747
1748
1749 /*                              ---------- STATISTICS CACHE ----------                                   */
1750
1751 /*
1752  * get_attavgwidth
1753  *
1754  *        Given the table and attribute number of a column, get the average
1755  *        width of entries in the column.  Return zero if no data available.
1756  */
1757 int32
1758 get_attavgwidth(Oid relid, AttrNumber attnum)
1759 {
1760         HeapTuple       tp;
1761
1762         tp = SearchSysCache(STATRELATT,
1763                                                 ObjectIdGetDatum(relid),
1764                                                 Int16GetDatum(attnum),
1765                                                 0, 0);
1766         if (HeapTupleIsValid(tp))
1767         {
1768                 int32           stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
1769
1770                 ReleaseSysCache(tp);
1771                 if (stawidth > 0)
1772                         return stawidth;
1773         }
1774         return 0;
1775 }
1776
1777 /*
1778  * get_attstatsslot
1779  *
1780  *              Extract the contents of a "slot" of a pg_statistic tuple.
1781  *              Returns TRUE if requested slot type was found, else FALSE.
1782  *
1783  * Unlike other routines in this file, this takes a pointer to an
1784  * already-looked-up tuple in the pg_statistic cache.  We do this since
1785  * most callers will want to extract more than one value from the cache
1786  * entry, and we don't want to repeat the cache lookup unnecessarily.
1787  *
1788  * statstuple: pg_statistics tuple to be examined.
1789  * atttype: type OID of attribute.
1790  * atttypmod: typmod of attribute.
1791  * reqkind: STAKIND code for desired statistics slot kind.
1792  * reqop: STAOP value wanted, or InvalidOid if don't care.
1793  * values, nvalues: if not NULL, the slot's stavalues are extracted.
1794  * numbers, nnumbers: if not NULL, the slot's stanumbers are extracted.
1795  *
1796  * If assigned, values and numbers are set to point to palloc'd arrays.
1797  * If the attribute type is pass-by-reference, the values referenced by
1798  * the values array are themselves palloc'd.  The palloc'd stuff can be
1799  * freed by calling free_attstatsslot.
1800  */
1801 bool
1802 get_attstatsslot(HeapTuple statstuple,
1803                                  Oid atttype, int32 atttypmod,
1804                                  int reqkind, Oid reqop,
1805                                  Datum **values, int *nvalues,
1806                                  float4 **numbers, int *nnumbers)
1807 {
1808         Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
1809         int                     i,
1810                                 j;
1811         Datum           val;
1812         bool            isnull;
1813         ArrayType  *statarray;
1814         int                     narrayelem;
1815         HeapTuple       typeTuple;
1816         Form_pg_type typeForm;
1817
1818         for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
1819         {
1820                 if ((&stats->stakind1)[i] == reqkind &&
1821                         (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
1822                         break;
1823         }
1824         if (i >= STATISTIC_NUM_SLOTS)
1825                 return false;                   /* not there */
1826
1827         if (values)
1828         {
1829                 val = SysCacheGetAttr(STATRELATT, statstuple,
1830                                                           Anum_pg_statistic_stavalues1 + i,
1831                                                           &isnull);
1832                 if (isnull)
1833                         elog(ERROR, "stavalues is null");
1834                 statarray = DatumGetArrayTypeP(val);
1835
1836                 /* Need to get info about the array element type */
1837                 typeTuple = SearchSysCache(TYPEOID,
1838                                                                    ObjectIdGetDatum(atttype),
1839                                                                    0, 0, 0);
1840                 if (!HeapTupleIsValid(typeTuple))
1841                         elog(ERROR, "cache lookup failed for type %u", atttype);
1842                 typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
1843
1844                 /* Deconstruct array into Datum elements */
1845                 deconstruct_array(statarray,
1846                                                   atttype,
1847                                                   typeForm->typlen,
1848                                                   typeForm->typbyval,
1849                                                   typeForm->typalign,
1850                                                   values, nvalues);
1851
1852                 /*
1853                  * If the element type is pass-by-reference, we now have a bunch
1854                  * of Datums that are pointers into the syscache value.  Copy them
1855                  * to avoid problems if syscache decides to drop the entry.
1856                  */
1857                 if (!typeForm->typbyval)
1858                 {
1859                         for (j = 0; j < *nvalues; j++)
1860                         {
1861                                 (*values)[j] = datumCopy((*values)[j],
1862                                                                                  typeForm->typbyval,
1863                                                                                  typeForm->typlen);
1864                         }
1865                 }
1866
1867                 ReleaseSysCache(typeTuple);
1868
1869                 /*
1870                  * Free statarray if it's a detoasted copy.
1871                  */
1872                 if ((Pointer) statarray != DatumGetPointer(val))
1873                         pfree(statarray);
1874         }
1875
1876         if (numbers)
1877         {
1878                 val = SysCacheGetAttr(STATRELATT, statstuple,
1879                                                           Anum_pg_statistic_stanumbers1 + i,
1880                                                           &isnull);
1881                 if (isnull)
1882                         elog(ERROR, "stanumbers is null");
1883                 statarray = DatumGetArrayTypeP(val);
1884
1885                 /*
1886                  * We expect the array to be a 1-D float4 array; verify that. We
1887                  * don't need to use deconstruct_array() since the array data is
1888                  * just going to look like a C array of float4 values.
1889                  */
1890                 narrayelem = ARR_DIMS(statarray)[0];
1891                 if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
1892                         ARR_ELEMTYPE(statarray) != FLOAT4OID)
1893                         elog(ERROR, "stanumbers is not a 1-D float4 array");
1894                 *numbers = (float4 *) palloc(narrayelem * sizeof(float4));
1895                 memcpy(*numbers, ARR_DATA_PTR(statarray), narrayelem * sizeof(float4));
1896                 *nnumbers = narrayelem;
1897
1898                 /*
1899                  * Free statarray if it's a detoasted copy.
1900                  */
1901                 if ((Pointer) statarray != DatumGetPointer(val))
1902                         pfree(statarray);
1903         }
1904
1905         return true;
1906 }
1907
1908 void
1909 free_attstatsslot(Oid atttype,
1910                                   Datum *values, int nvalues,
1911                                   float4 *numbers, int nnumbers)
1912 {
1913         if (values)
1914         {
1915                 if (!get_typbyval(atttype))
1916                 {
1917                         int                     i;
1918
1919                         for (i = 0; i < nvalues; i++)
1920                                 pfree(DatumGetPointer(values[i]));
1921                 }
1922                 pfree(values);
1923         }
1924         if (numbers)
1925                 pfree(numbers);
1926 }
1927
1928 /*                              ---------- PG_NAMESPACE CACHE ----------                                 */
1929
1930 /*
1931  * get_namespace_name
1932  *              Returns the name of a given namespace
1933  *
1934  * Returns a palloc'd copy of the string, or NULL if no such namespace.
1935  */
1936 char *
1937 get_namespace_name(Oid nspid)
1938 {
1939         HeapTuple       tp;
1940
1941         tp = SearchSysCache(NAMESPACEOID,
1942                                                 ObjectIdGetDatum(nspid),
1943                                                 0, 0, 0);
1944         if (HeapTupleIsValid(tp))
1945         {
1946                 Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
1947                 char       *result;
1948
1949                 result = pstrdup(NameStr(nsptup->nspname));
1950                 ReleaseSysCache(tp);
1951                 return result;
1952         }
1953         else
1954                 return NULL;
1955 }
1956
1957 /*                              ---------- PG_SHADOW CACHE ----------                                    */
1958
1959 /*
1960  * get_usesysid
1961  *
1962  *        Given a user name, look up the user's sysid.
1963  *        Raises an error if no such user (rather than returning zero,
1964  *        which might possibly be a valid usesysid).
1965  *
1966  * Note: the type of usesysid is currently int4, but may change to Oid
1967  * someday.  It'd be reasonable to return zero on failure if we were
1968  * using Oid ...
1969  */
1970 AclId
1971 get_usesysid(const char *username)
1972 {
1973         int32           result;
1974         HeapTuple       userTup;
1975
1976         userTup = SearchSysCache(SHADOWNAME,
1977                                                          PointerGetDatum(username),
1978                                                          0, 0, 0);
1979         if (!HeapTupleIsValid(userTup))
1980                 ereport(ERROR,
1981                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1982                                  errmsg("user \"%s\" does not exist", username)));
1983
1984         result = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
1985
1986         ReleaseSysCache(userTup);
1987
1988         return result;
1989 }