]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/lsyscache.c
d2041a507d0eb46feeeca440c0308fe725922d0a
[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-2007, 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.145 2007/01/21 00:57:15 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/hash.h"
19 #include "access/nbtree.h"
20 #include "bootstrap/bootstrap.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_statistic.h"
28 #include "catalog/pg_type.h"
29 #include "miscadmin.h"
30 #include "nodes/makefuncs.h"
31 #include "utils/array.h"
32 #include "utils/builtins.h"
33 #include "utils/datum.h"
34 #include "utils/lsyscache.h"
35 #include "utils/syscache.h"
36
37
38 /*                              ---------- AMOP CACHES ----------                                                */
39
40 /*
41  * op_in_opfamily
42  *
43  *              Return t iff operator 'opno' is in operator family 'opfamily'.
44  */
45 bool
46 op_in_opfamily(Oid opno, Oid opfamily)
47 {
48         return SearchSysCacheExists(AMOPOPID,
49                                                                 ObjectIdGetDatum(opno),
50                                                                 ObjectIdGetDatum(opfamily),
51                                                                 0, 0);
52 }
53
54 /*
55  * get_op_opfamily_strategy
56  *
57  *              Get the operator's strategy number within the specified opfamily,
58  *              or 0 if it's not a member of the opfamily.
59  */
60 int
61 get_op_opfamily_strategy(Oid opno, Oid opfamily)
62 {
63         HeapTuple       tp;
64         Form_pg_amop amop_tup;
65         int                     result;
66
67         tp = SearchSysCache(AMOPOPID,
68                                                 ObjectIdGetDatum(opno),
69                                                 ObjectIdGetDatum(opfamily),
70                                                 0, 0);
71         if (!HeapTupleIsValid(tp))
72                 return 0;
73         amop_tup = (Form_pg_amop) GETSTRUCT(tp);
74         result = amop_tup->amopstrategy;
75         ReleaseSysCache(tp);
76         return result;
77 }
78
79 /*
80  * get_op_opfamily_properties
81  *
82  *              Get the operator's strategy number, input types, and recheck (lossy)
83  *              flag within the specified opfamily.
84  *
85  * Caller should already have verified that opno is a member of opfamily,
86  * therefore we raise an error if the tuple is not found.
87  */
88 void
89 get_op_opfamily_properties(Oid opno, Oid opfamily,
90                                                    int *strategy,
91                                                    Oid *lefttype,
92                                                    Oid *righttype,
93                                                    bool *recheck)
94 {
95         HeapTuple       tp;
96         Form_pg_amop amop_tup;
97
98         tp = SearchSysCache(AMOPOPID,
99                                                 ObjectIdGetDatum(opno),
100                                                 ObjectIdGetDatum(opfamily),
101                                                 0, 0);
102         if (!HeapTupleIsValid(tp))
103                 elog(ERROR, "operator %u is not a member of opfamily %u",
104                          opno, opfamily);
105         amop_tup = (Form_pg_amop) GETSTRUCT(tp);
106         *strategy = amop_tup->amopstrategy;
107         *lefttype = amop_tup->amoplefttype;
108         *righttype = amop_tup->amoprighttype;
109         *recheck = amop_tup->amopreqcheck;
110         ReleaseSysCache(tp);
111 }
112
113 /*
114  * get_opfamily_member
115  *              Get the OID of the operator that implements the specified strategy
116  *              with the specified datatypes for the specified opfamily.
117  *
118  * Returns InvalidOid if there is no pg_amop entry for the given keys.
119  */
120 Oid
121 get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
122                                         int16 strategy)
123 {
124         HeapTuple       tp;
125         Form_pg_amop amop_tup;
126         Oid                     result;
127
128         tp = SearchSysCache(AMOPSTRATEGY,
129                                                 ObjectIdGetDatum(opfamily),
130                                                 ObjectIdGetDatum(lefttype),
131                                                 ObjectIdGetDatum(righttype),
132                                                 Int16GetDatum(strategy));
133         if (!HeapTupleIsValid(tp))
134                 return InvalidOid;
135         amop_tup = (Form_pg_amop) GETSTRUCT(tp);
136         result = amop_tup->amopopr;
137         ReleaseSysCache(tp);
138         return result;
139 }
140
141 /*
142  * get_ordering_op_properties
143  *              Given the OID of an ordering operator (a btree "<" or ">" operator),
144  *              determine its opfamily, its declared input datatype, and its
145  *              strategy number (BTLessStrategyNumber or BTGreaterStrategyNumber).
146  *
147  * Returns TRUE if successful, FALSE if no matching pg_amop entry exists.
148  * (This indicates that the operator is not a valid ordering operator.)
149  *
150  * Note: the operator could be registered in multiple families, for example
151  * if someone were to build a "reverse sort" opfamily.  This would result in
152  * uncertainty as to whether "ORDER BY USING op" would default to NULLS FIRST
153  * or NULLS LAST, as well as inefficient planning due to failure to match up
154  * pathkeys that should be the same.  So we want a determinate result here.
155  * Because of the way the syscache search works, we'll use the interpretation
156  * associated with the opfamily with smallest OID, which is probably
157  * determinate enough.  Since there is no longer any particularly good reason
158  * to build reverse-sort opfamilies, it doesn't seem worth expending any
159  * additional effort on ensuring consistency.
160  */
161 bool
162 get_ordering_op_properties(Oid opno,
163                                                    Oid *opfamily, Oid *opcintype, int16 *strategy)
164 {
165         bool            result = false;
166         CatCList   *catlist;
167         int                     i;
168
169         /* ensure outputs are initialized on failure */
170         *opfamily = InvalidOid;
171         *opcintype = InvalidOid;
172         *strategy = 0;
173
174         /*
175          * Search pg_amop to see if the target operator is registered as the "<"
176          * or ">" operator of any btree opfamily.
177          */
178         catlist = SearchSysCacheList(AMOPOPID, 1,
179                                                                  ObjectIdGetDatum(opno),
180                                                                  0, 0, 0);
181
182         for (i = 0; i < catlist->n_members; i++)
183         {
184                 HeapTuple       tuple = &catlist->members[i]->tuple;
185                 Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
186
187                 /* must be btree */
188                 if (aform->amopmethod != BTREE_AM_OID)
189                         continue;
190
191                 if (aform->amopstrategy == BTLessStrategyNumber ||
192                         aform->amopstrategy == BTGreaterStrategyNumber)
193                 {
194                         /* Found it ... should have consistent input types */
195                         if (aform->amoplefttype == aform->amoprighttype)
196                         {
197                                 /* Found a suitable opfamily, return info */
198                                 *opfamily = aform->amopfamily;
199                                 *opcintype = aform->amoplefttype;
200                                 *strategy = aform->amopstrategy;
201                                 result = true;
202                                 break;
203                         }
204                 }
205         }
206
207         ReleaseSysCacheList(catlist);
208
209         return result;
210 }
211
212 /*
213  * get_compare_function_for_ordering_op
214  *              Get the OID of the datatype-specific btree comparison function
215  *              associated with an ordering operator (a "<" or ">" operator).
216  *
217  * *cmpfunc receives the comparison function OID.
218  * *reverse is set FALSE if the operator is "<", TRUE if it's ">"
219  * (indicating the comparison result must be negated before use).
220  *
221  * Returns TRUE if successful, FALSE if no btree function can be found.
222  * (This indicates that the operator is not a valid ordering operator.)
223  */
224 bool
225 get_compare_function_for_ordering_op(Oid opno, Oid *cmpfunc, bool *reverse)
226 {
227         Oid                     opfamily;
228         Oid                     opcintype;
229         int16           strategy;
230
231         /* Find the operator in pg_amop */
232         if (get_ordering_op_properties(opno,
233                                                                    &opfamily, &opcintype, &strategy))
234         {
235                 /* Found a suitable opfamily, get matching support function */
236                 *cmpfunc = get_opfamily_proc(opfamily,
237                                                                          opcintype,
238                                                                          opcintype,
239                                                                          BTORDER_PROC);
240                 if (!OidIsValid(*cmpfunc))                              /* should not happen */
241                         elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
242                                  BTORDER_PROC, opcintype, opcintype, opfamily);
243                 *reverse = (strategy == BTGreaterStrategyNumber);
244                 return true;
245         }
246
247         /* ensure outputs are set on failure */
248         *cmpfunc = InvalidOid;
249         *reverse = false;
250         return false;
251 }
252
253 /*
254  * get_equality_op_for_ordering_op
255  *              Get the OID of the datatype-specific btree equality operator
256  *              associated with an ordering operator (a "<" or ">" operator).
257  *
258  * Returns InvalidOid if no matching equality operator can be found.
259  * (This indicates that the operator is not a valid ordering operator.)
260  */
261 Oid
262 get_equality_op_for_ordering_op(Oid opno)
263 {
264         Oid                     result = InvalidOid;
265         Oid                     opfamily;
266         Oid                     opcintype;
267         int16           strategy;
268
269         /* Find the operator in pg_amop */
270         if (get_ordering_op_properties(opno,
271                                                                    &opfamily, &opcintype, &strategy))
272         {
273                 /* Found a suitable opfamily, get matching equality operator */
274                 result = get_opfamily_member(opfamily,
275                                                                          opcintype,
276                                                                          opcintype,
277                                                                          BTEqualStrategyNumber);
278         }
279
280         return result;
281 }
282
283 /*
284  * get_ordering_op_for_equality_op
285  *              Get the OID of a datatype-specific btree ordering operator
286  *              associated with an equality operator.  (If there are multiple
287  *              possibilities, assume any one will do.)
288  *
289  * This function is used when we have to sort data before unique-ifying,
290  * and don't much care which sorting op is used as long as it's compatible
291  * with the intended equality operator.  Since we need a sorting operator,
292  * it should be single-data-type even if the given operator is cross-type.
293  * The caller specifies whether to find an op for the LHS or RHS data type.
294  *
295  * Returns InvalidOid if no matching ordering operator can be found.
296  */
297 Oid
298 get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
299 {
300         Oid                     result = InvalidOid;
301         CatCList   *catlist;
302         int                     i;
303
304         /*
305          * Search pg_amop to see if the target operator is registered as the "="
306          * operator of any btree opfamily.
307          */
308         catlist = SearchSysCacheList(AMOPOPID, 1,
309                                                                  ObjectIdGetDatum(opno),
310                                                                  0, 0, 0);
311
312         for (i = 0; i < catlist->n_members; i++)
313         {
314                 HeapTuple       tuple = &catlist->members[i]->tuple;
315                 Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
316
317                 /* must be btree */
318                 if (aform->amopmethod != BTREE_AM_OID)
319                         continue;
320
321                 if (aform->amopstrategy == BTEqualStrategyNumber)
322                 {
323                         /* Found a suitable opfamily, get matching ordering operator */
324                         Oid             typid;
325
326                         typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
327                         result = get_opfamily_member(aform->amopfamily,
328                                                                                  typid, typid,
329                                                                                  BTLessStrategyNumber);
330                         if (OidIsValid(result))
331                                 break;
332                         /* failure probably shouldn't happen, but keep looking if so */
333                 }
334         }
335
336         ReleaseSysCacheList(catlist);
337
338         return result;
339 }
340
341 /*
342  * get_mergejoin_opfamilies
343  *              Given a putatively mergejoinable operator, return a list of the OIDs
344  *              of the btree opfamilies in which it represents equality.
345  *
346  * It is possible (though at present unusual) for an operator to be equality
347  * in more than one opfamily, hence the result is a list.  This also lets us
348  * return NIL if the operator is not found in any opfamilies.
349  *
350  * The planner currently uses simple equal() tests to compare the lists
351  * returned by this function, which makes the list order relevant, though
352  * strictly speaking it should not be.  Because of the way syscache list
353  * searches are handled, in normal operation the result will be sorted by OID
354  * so everything works fine.  If running with system index usage disabled,
355  * the result ordering is unspecified and hence the planner might fail to
356  * recognize optimization opportunities ... but that's hardly a scenario in
357  * which performance is good anyway, so there's no point in expending code
358  * or cycles here to guarantee the ordering in that case.
359  */
360 List *
361 get_mergejoin_opfamilies(Oid opno)
362 {
363         List       *result = NIL;
364         CatCList   *catlist;
365         int                     i;
366
367         /*
368          * Search pg_amop to see if the target operator is registered as the "="
369          * operator of any btree opfamily.
370          */
371         catlist = SearchSysCacheList(AMOPOPID, 1,
372                                                                  ObjectIdGetDatum(opno),
373                                                                  0, 0, 0);
374
375         for (i = 0; i < catlist->n_members; i++)
376         {
377                 HeapTuple       tuple = &catlist->members[i]->tuple;
378                 Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
379
380                 /* must be btree equality */
381                 if (aform->amopmethod == BTREE_AM_OID &&
382                         aform->amopstrategy == BTEqualStrategyNumber)
383                         result = lappend_oid(result, aform->amopfamily);
384         }
385
386         ReleaseSysCacheList(catlist);
387
388         return result;
389 }
390
391 /*
392  * get_compatible_hash_operator
393  *              Get the OID of a hash equality operator compatible with the given
394  *              operator, but operating on its LHS or RHS datatype as specified.
395  *
396  * If the given operator is not cross-type, the result should be the same
397  * operator, but in cross-type situations it is different.
398  *
399  * Returns InvalidOid if no compatible operator can be found.  (This indicates
400  * that the operator should not have been marked oprcanhash.)
401  */
402 Oid
403 get_compatible_hash_operator(Oid opno, bool use_lhs_type)
404 {
405         Oid                     result = InvalidOid;
406         CatCList   *catlist;
407         int                     i;
408
409         /*
410          * Search pg_amop to see if the target operator is registered as the "="
411          * operator of any hash opfamily.  If the operator is registered in
412          * multiple opfamilies, assume we can use any one.
413          */
414         catlist = SearchSysCacheList(AMOPOPID, 1,
415                                                                  ObjectIdGetDatum(opno),
416                                                                  0, 0, 0);
417
418         for (i = 0; i < catlist->n_members; i++)
419         {
420                 HeapTuple       tuple = &catlist->members[i]->tuple;
421                 Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
422
423                 if (aform->amopmethod == HASH_AM_OID &&
424                         aform->amopstrategy == HTEqualStrategyNumber)
425                 {
426                         /* Found a suitable opfamily, get matching single-type operator */
427                         Oid             typid;
428
429                         /* No extra lookup needed if given operator is single-type */
430                         if (aform->amoplefttype == aform->amoprighttype)
431                         {
432                                 result = opno;
433                                 break;
434                         }
435                         typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
436                         result = get_opfamily_member(aform->amopfamily,
437                                                                                  typid, typid,
438                                                                                  HTEqualStrategyNumber);
439                         if (OidIsValid(result))
440                                 break;
441                         /* failure probably shouldn't happen, but keep looking if so */
442                 }
443         }
444
445         ReleaseSysCacheList(catlist);
446
447         return result;
448 }
449
450 /*
451  * get_op_hash_function
452  *              Get the OID of the datatype-specific hash function associated with
453  *              a hashable equality operator.
454  *
455  * XXX API needs to be generalized for the case of different left and right
456  * datatypes.
457  *
458  * Returns InvalidOid if no hash function can be found.  (This indicates
459  * that the operator should not have been marked oprcanhash.)
460  */
461 Oid
462 get_op_hash_function(Oid opno)
463 {
464         Oid                     result = InvalidOid;
465         CatCList   *catlist;
466         int                     i;
467
468         /*
469          * Search pg_amop to see if the target operator is registered as the "="
470          * operator of any hash opfamily.  If the operator is registered in
471          * multiple opfamilies, assume we can use the associated hash function from
472          * any one.
473          */
474         catlist = SearchSysCacheList(AMOPOPID, 1,
475                                                                  ObjectIdGetDatum(opno),
476                                                                  0, 0, 0);
477
478         for (i = 0; i < catlist->n_members; i++)
479         {
480                 HeapTuple       tuple = &catlist->members[i]->tuple;
481                 Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
482
483                 if (aform->amopmethod == HASH_AM_OID &&
484                         aform->amopstrategy == HTEqualStrategyNumber)
485                 {
486                         /* Found a suitable opfamily, get matching hash support function */
487                         result = get_opfamily_proc(aform->amopfamily,
488                                                                            aform->amoplefttype,
489                                                                            aform->amoprighttype,
490                                                                            HASHPROC);
491                         break;
492                 }
493         }
494
495         ReleaseSysCacheList(catlist);
496
497         return result;
498 }
499
500 /*
501  * get_op_btree_interpretation
502  *              Given an operator's OID, find out which btree opfamilies it belongs to,
503  *              and what strategy number it has within each one.  The results are
504  *              returned as an OID list and a parallel integer list.
505  *
506  * In addition to the normal btree operators, we consider a <> operator to be
507  * a "member" of an opfamily if its negator is an equality operator of the
508  * opfamily.  ROWCOMPARE_NE is returned as the strategy number for this case.
509  */
510 void
511 get_op_btree_interpretation(Oid opno, List **opfamilies, List **opstrats)
512 {
513         CatCList   *catlist;
514         bool            op_negated;
515         int                     i;
516
517         *opfamilies = NIL;
518         *opstrats = NIL;
519
520         /*
521          * Find all the pg_amop entries containing the operator.
522          */
523         catlist = SearchSysCacheList(AMOPOPID, 1,
524                                                                  ObjectIdGetDatum(opno),
525                                                                  0, 0, 0);
526
527         /*
528          * If we can't find any opfamily containing the op, perhaps it is a <>
529          * operator.  See if it has a negator that is in an opfamily.
530          */
531         op_negated = false;
532         if (catlist->n_members == 0)
533         {
534                 Oid                     op_negator = get_negator(opno);
535
536                 if (OidIsValid(op_negator))
537                 {
538                         op_negated = true;
539                         ReleaseSysCacheList(catlist);
540                         catlist = SearchSysCacheList(AMOPOPID, 1,
541                                                                                  ObjectIdGetDatum(op_negator),
542                                                                                  0, 0, 0);
543                 }
544         }
545
546         /* Now search the opfamilies */
547         for (i = 0; i < catlist->n_members; i++)
548         {
549                 HeapTuple       op_tuple = &catlist->members[i]->tuple;
550                 Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
551                 Oid                     opfamily_id;
552                 StrategyNumber op_strategy;
553
554                 /* must be btree */
555                 if (op_form->amopmethod != BTREE_AM_OID)
556                         continue;
557
558                 /* Get the operator's btree strategy number */
559                 opfamily_id = op_form->amopfamily;
560                 op_strategy = (StrategyNumber) op_form->amopstrategy;
561                 Assert(op_strategy >= 1 && op_strategy <= 5);
562
563                 if (op_negated)
564                 {
565                         /* Only consider negators that are = */
566                         if (op_strategy != BTEqualStrategyNumber)
567                                 continue;
568                         op_strategy = ROWCOMPARE_NE;
569                 }
570
571                 *opfamilies = lappend_oid(*opfamilies, opfamily_id);
572                 *opstrats = lappend_int(*opstrats, op_strategy);
573         }
574
575         ReleaseSysCacheList(catlist);
576 }
577
578 /*
579  * ops_in_same_btree_opfamily
580  *              Return TRUE if there exists a btree opfamily containing both operators.
581  *              (This implies that they have compatible notions of equality.)
582  */
583 bool
584 ops_in_same_btree_opfamily(Oid opno1, Oid opno2)
585 {
586         bool            result = false;
587         CatCList   *catlist;
588         int                     i;
589
590         /*
591          * We search through all the pg_amop entries for opno1.
592          */
593         catlist = SearchSysCacheList(AMOPOPID, 1,
594                                                                  ObjectIdGetDatum(opno1),
595                                                                  0, 0, 0);
596         for (i = 0; i < catlist->n_members; i++)
597         {
598                 HeapTuple       op_tuple = &catlist->members[i]->tuple;
599                 Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
600
601                 /* must be btree */
602                 if (op_form->amopmethod != BTREE_AM_OID)
603                         continue;
604
605                 if (op_in_opfamily(opno2, op_form->amopfamily))
606                 {
607                         result = true;
608                         break;
609                 }
610         }
611
612         ReleaseSysCacheList(catlist);
613
614         return result;
615 }
616
617
618 /*                              ---------- AMPROC CACHES ----------                                              */
619
620 /*
621  * get_opfamily_proc
622  *              Get the OID of the specified support function
623  *              for the specified opfamily and datatypes.
624  *
625  * Returns InvalidOid if there is no pg_amproc entry for the given keys.
626  */
627 Oid
628 get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
629 {
630         HeapTuple       tp;
631         Form_pg_amproc amproc_tup;
632         RegProcedure result;
633
634         tp = SearchSysCache(AMPROCNUM,
635                                                 ObjectIdGetDatum(opfamily),
636                                                 ObjectIdGetDatum(lefttype),
637                                                 ObjectIdGetDatum(righttype),
638                                                 Int16GetDatum(procnum));
639         if (!HeapTupleIsValid(tp))
640                 return InvalidOid;
641         amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
642         result = amproc_tup->amproc;
643         ReleaseSysCache(tp);
644         return result;
645 }
646
647
648 /*                              ---------- ATTRIBUTE CACHES ----------                                   */
649
650 /*
651  * get_attname
652  *              Given the relation id and the attribute number,
653  *              return the "attname" field from the attribute relation.
654  *
655  * Note: returns a palloc'd copy of the string, or NULL if no such attribute.
656  */
657 char *
658 get_attname(Oid relid, AttrNumber attnum)
659 {
660         HeapTuple       tp;
661
662         tp = SearchSysCache(ATTNUM,
663                                                 ObjectIdGetDatum(relid),
664                                                 Int16GetDatum(attnum),
665                                                 0, 0);
666         if (HeapTupleIsValid(tp))
667         {
668                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
669                 char       *result;
670
671                 result = pstrdup(NameStr(att_tup->attname));
672                 ReleaseSysCache(tp);
673                 return result;
674         }
675         else
676                 return NULL;
677 }
678
679 /*
680  * get_relid_attribute_name
681  *
682  * Same as above routine get_attname(), except that error
683  * is handled by elog() instead of returning NULL.
684  */
685 char *
686 get_relid_attribute_name(Oid relid, AttrNumber attnum)
687 {
688         char       *attname;
689
690         attname = get_attname(relid, attnum);
691         if (attname == NULL)
692                 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
693                          attnum, relid);
694         return attname;
695 }
696
697 /*
698  * get_attnum
699  *
700  *              Given the relation id and the attribute name,
701  *              return the "attnum" field from the attribute relation.
702  *
703  *              Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
704  */
705 AttrNumber
706 get_attnum(Oid relid, const char *attname)
707 {
708         HeapTuple       tp;
709
710         tp = SearchSysCacheAttName(relid, attname);
711         if (HeapTupleIsValid(tp))
712         {
713                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
714                 AttrNumber      result;
715
716                 result = att_tup->attnum;
717                 ReleaseSysCache(tp);
718                 return result;
719         }
720         else
721                 return InvalidAttrNumber;
722 }
723
724 /*
725  * get_atttype
726  *
727  *              Given the relation OID and the attribute number with the relation,
728  *              return the attribute type OID.
729  */
730 Oid
731 get_atttype(Oid relid, AttrNumber attnum)
732 {
733         HeapTuple       tp;
734
735         tp = SearchSysCache(ATTNUM,
736                                                 ObjectIdGetDatum(relid),
737                                                 Int16GetDatum(attnum),
738                                                 0, 0);
739         if (HeapTupleIsValid(tp))
740         {
741                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
742                 Oid                     result;
743
744                 result = att_tup->atttypid;
745                 ReleaseSysCache(tp);
746                 return result;
747         }
748         else
749                 return InvalidOid;
750 }
751
752 /*
753  * get_atttypmod
754  *
755  *              Given the relation id and the attribute number,
756  *              return the "atttypmod" field from the attribute relation.
757  */
758 int32
759 get_atttypmod(Oid relid, AttrNumber attnum)
760 {
761         HeapTuple       tp;
762
763         tp = SearchSysCache(ATTNUM,
764                                                 ObjectIdGetDatum(relid),
765                                                 Int16GetDatum(attnum),
766                                                 0, 0);
767         if (HeapTupleIsValid(tp))
768         {
769                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
770                 int32           result;
771
772                 result = att_tup->atttypmod;
773                 ReleaseSysCache(tp);
774                 return result;
775         }
776         else
777                 return -1;
778 }
779
780 /*
781  * get_atttypetypmod
782  *
783  *              A two-fer: given the relation id and the attribute number,
784  *              fetch both type OID and atttypmod in a single cache lookup.
785  *
786  * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
787  * raises an error if it can't obtain the information.
788  */
789 void
790 get_atttypetypmod(Oid relid, AttrNumber attnum,
791                                   Oid *typid, int32 *typmod)
792 {
793         HeapTuple       tp;
794         Form_pg_attribute att_tup;
795
796         tp = SearchSysCache(ATTNUM,
797                                                 ObjectIdGetDatum(relid),
798                                                 Int16GetDatum(attnum),
799                                                 0, 0);
800         if (!HeapTupleIsValid(tp))
801                 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
802                          attnum, relid);
803         att_tup = (Form_pg_attribute) GETSTRUCT(tp);
804
805         *typid = att_tup->atttypid;
806         *typmod = att_tup->atttypmod;
807         ReleaseSysCache(tp);
808 }
809
810 /*                              ---------- INDEX CACHE ----------                                                */
811
812 /*              watch this space...
813  */
814
815 /*                              ---------- OPCLASS CACHE ----------                                              */
816
817 /*
818  * get_opclass_family
819  *
820  *              Returns the OID of the operator family the opclass belongs to.
821  */
822 Oid
823 get_opclass_family(Oid opclass)
824 {
825         HeapTuple       tp;
826         Form_pg_opclass cla_tup;
827         Oid                     result;
828
829         tp = SearchSysCache(CLAOID,
830                                                 ObjectIdGetDatum(opclass),
831                                                 0, 0, 0);
832         if (!HeapTupleIsValid(tp))
833                 elog(ERROR, "cache lookup failed for opclass %u", opclass);
834         cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
835
836         result = cla_tup->opcfamily;
837         ReleaseSysCache(tp);
838         return result;
839 }
840
841 /*
842  * get_opclass_input_type
843  *
844  *              Returns the OID of the datatype the opclass indexes.
845  */
846 Oid
847 get_opclass_input_type(Oid opclass)
848 {
849         HeapTuple       tp;
850         Form_pg_opclass cla_tup;
851         Oid                     result;
852
853         tp = SearchSysCache(CLAOID,
854                                                 ObjectIdGetDatum(opclass),
855                                                 0, 0, 0);
856         if (!HeapTupleIsValid(tp))
857                 elog(ERROR, "cache lookup failed for opclass %u", opclass);
858         cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
859
860         result = cla_tup->opcintype;
861         ReleaseSysCache(tp);
862         return result;
863 }
864
865 /*                              ---------- OPERATOR CACHE ----------                                     */
866
867 /*
868  * get_opcode
869  *
870  *              Returns the regproc id of the routine used to implement an
871  *              operator given the operator oid.
872  */
873 RegProcedure
874 get_opcode(Oid opno)
875 {
876         HeapTuple       tp;
877
878         tp = SearchSysCache(OPEROID,
879                                                 ObjectIdGetDatum(opno),
880                                                 0, 0, 0);
881         if (HeapTupleIsValid(tp))
882         {
883                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
884                 RegProcedure result;
885
886                 result = optup->oprcode;
887                 ReleaseSysCache(tp);
888                 return result;
889         }
890         else
891                 return (RegProcedure) InvalidOid;
892 }
893
894 /*
895  * get_opname
896  *        returns the name of the operator with the given opno
897  *
898  * Note: returns a palloc'd copy of the string, or NULL if no such operator.
899  */
900 char *
901 get_opname(Oid opno)
902 {
903         HeapTuple       tp;
904
905         tp = SearchSysCache(OPEROID,
906                                                 ObjectIdGetDatum(opno),
907                                                 0, 0, 0);
908         if (HeapTupleIsValid(tp))
909         {
910                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
911                 char       *result;
912
913                 result = pstrdup(NameStr(optup->oprname));
914                 ReleaseSysCache(tp);
915                 return result;
916         }
917         else
918                 return NULL;
919 }
920
921 /*
922  * op_input_types
923  *
924  *              Returns the left and right input datatypes for an operator
925  *              (InvalidOid if not relevant).
926  */
927 void
928 op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
929 {
930         HeapTuple       tp;
931         Form_pg_operator optup;
932
933         tp = SearchSysCache(OPEROID,
934                                                 ObjectIdGetDatum(opno),
935                                                 0, 0, 0);
936         if (!HeapTupleIsValid(tp))      /* shouldn't happen */
937                 elog(ERROR, "cache lookup failed for operator %u", opno);
938         optup = (Form_pg_operator) GETSTRUCT(tp);
939         *lefttype = optup->oprleft;
940         *righttype = optup->oprright;
941         ReleaseSysCache(tp);
942 }
943
944 /*
945  * op_mergejoinable
946  *
947  * Returns true if the operator is potentially mergejoinable.  (The planner
948  * will fail to find any mergejoin plans unless there are suitable btree
949  * opfamily entries for this operator and associated sortops.  The pg_operator
950  * flag is just a hint to tell the planner whether to bother looking.)
951  */
952 bool
953 op_mergejoinable(Oid opno)
954 {
955         HeapTuple       tp;
956         bool            result = false;
957
958         tp = SearchSysCache(OPEROID,
959                                                 ObjectIdGetDatum(opno),
960                                                 0, 0, 0);
961         if (HeapTupleIsValid(tp))
962         {
963                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
964
965                 result = optup->oprcanmerge;
966                 ReleaseSysCache(tp);
967         }
968         return result;
969 }
970
971 /*
972  * op_hashjoinable
973  *
974  * Returns true if the operator is hashjoinable.  (There must be a suitable
975  * hash opfamily entry for this operator if it is so marked.)
976  */
977 bool
978 op_hashjoinable(Oid opno)
979 {
980         HeapTuple       tp;
981         bool            result = false;
982
983         tp = SearchSysCache(OPEROID,
984                                                 ObjectIdGetDatum(opno),
985                                                 0, 0, 0);
986         if (HeapTupleIsValid(tp))
987         {
988                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
989
990                 result = optup->oprcanhash;
991                 ReleaseSysCache(tp);
992         }
993         return result;
994 }
995
996 /*
997  * op_strict
998  *
999  * Get the proisstrict flag for the operator's underlying function.
1000  */
1001 bool
1002 op_strict(Oid opno)
1003 {
1004         RegProcedure funcid = get_opcode(opno);
1005
1006         if (funcid == (RegProcedure) InvalidOid)
1007                 elog(ERROR, "operator %u does not exist", opno);
1008
1009         return func_strict((Oid) funcid);
1010 }
1011
1012 /*
1013  * op_volatile
1014  *
1015  * Get the provolatile flag for the operator's underlying function.
1016  */
1017 char
1018 op_volatile(Oid opno)
1019 {
1020         RegProcedure funcid = get_opcode(opno);
1021
1022         if (funcid == (RegProcedure) InvalidOid)
1023                 elog(ERROR, "operator %u does not exist", opno);
1024
1025         return func_volatile((Oid) funcid);
1026 }
1027
1028 /*
1029  * get_commutator
1030  *
1031  *              Returns the corresponding commutator of an operator.
1032  */
1033 Oid
1034 get_commutator(Oid opno)
1035 {
1036         HeapTuple       tp;
1037
1038         tp = SearchSysCache(OPEROID,
1039                                                 ObjectIdGetDatum(opno),
1040                                                 0, 0, 0);
1041         if (HeapTupleIsValid(tp))
1042         {
1043                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1044                 Oid                     result;
1045
1046                 result = optup->oprcom;
1047                 ReleaseSysCache(tp);
1048                 return result;
1049         }
1050         else
1051                 return InvalidOid;
1052 }
1053
1054 /*
1055  * get_negator
1056  *
1057  *              Returns the corresponding negator of an operator.
1058  */
1059 Oid
1060 get_negator(Oid opno)
1061 {
1062         HeapTuple       tp;
1063
1064         tp = SearchSysCache(OPEROID,
1065                                                 ObjectIdGetDatum(opno),
1066                                                 0, 0, 0);
1067         if (HeapTupleIsValid(tp))
1068         {
1069                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1070                 Oid                     result;
1071
1072                 result = optup->oprnegate;
1073                 ReleaseSysCache(tp);
1074                 return result;
1075         }
1076         else
1077                 return InvalidOid;
1078 }
1079
1080 /*
1081  * get_oprrest
1082  *
1083  *              Returns procedure id for computing selectivity of an operator.
1084  */
1085 RegProcedure
1086 get_oprrest(Oid opno)
1087 {
1088         HeapTuple       tp;
1089
1090         tp = SearchSysCache(OPEROID,
1091                                                 ObjectIdGetDatum(opno),
1092                                                 0, 0, 0);
1093         if (HeapTupleIsValid(tp))
1094         {
1095                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1096                 RegProcedure result;
1097
1098                 result = optup->oprrest;
1099                 ReleaseSysCache(tp);
1100                 return result;
1101         }
1102         else
1103                 return (RegProcedure) InvalidOid;
1104 }
1105
1106 /*
1107  * get_oprjoin
1108  *
1109  *              Returns procedure id for computing selectivity of a join.
1110  */
1111 RegProcedure
1112 get_oprjoin(Oid opno)
1113 {
1114         HeapTuple       tp;
1115
1116         tp = SearchSysCache(OPEROID,
1117                                                 ObjectIdGetDatum(opno),
1118                                                 0, 0, 0);
1119         if (HeapTupleIsValid(tp))
1120         {
1121                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1122                 RegProcedure result;
1123
1124                 result = optup->oprjoin;
1125                 ReleaseSysCache(tp);
1126                 return result;
1127         }
1128         else
1129                 return (RegProcedure) InvalidOid;
1130 }
1131
1132 /*                              ---------- FUNCTION CACHE ----------                                     */
1133
1134 /*
1135  * get_func_name
1136  *        returns the name of the function with the given funcid
1137  *
1138  * Note: returns a palloc'd copy of the string, or NULL if no such function.
1139  */
1140 char *
1141 get_func_name(Oid funcid)
1142 {
1143         HeapTuple       tp;
1144
1145         tp = SearchSysCache(PROCOID,
1146                                                 ObjectIdGetDatum(funcid),
1147                                                 0, 0, 0);
1148         if (HeapTupleIsValid(tp))
1149         {
1150                 Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
1151                 char       *result;
1152
1153                 result = pstrdup(NameStr(functup->proname));
1154                 ReleaseSysCache(tp);
1155                 return result;
1156         }
1157         else
1158                 return NULL;
1159 }
1160
1161 /*
1162  * get_func_rettype
1163  *              Given procedure id, return the function's result type.
1164  */
1165 Oid
1166 get_func_rettype(Oid funcid)
1167 {
1168         HeapTuple       tp;
1169         Oid                     result;
1170
1171         tp = SearchSysCache(PROCOID,
1172                                                 ObjectIdGetDatum(funcid),
1173                                                 0, 0, 0);
1174         if (!HeapTupleIsValid(tp))
1175                 elog(ERROR, "cache lookup failed for function %u", funcid);
1176
1177         result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
1178         ReleaseSysCache(tp);
1179         return result;
1180 }
1181
1182 /*
1183  * get_func_nargs
1184  *              Given procedure id, return the number of arguments.
1185  */
1186 int
1187 get_func_nargs(Oid funcid)
1188 {
1189         HeapTuple       tp;
1190         int                     result;
1191
1192         tp = SearchSysCache(PROCOID,
1193                                                 ObjectIdGetDatum(funcid),
1194                                                 0, 0, 0);
1195         if (!HeapTupleIsValid(tp))
1196                 elog(ERROR, "cache lookup failed for function %u", funcid);
1197
1198         result = ((Form_pg_proc) GETSTRUCT(tp))->pronargs;
1199         ReleaseSysCache(tp);
1200         return result;
1201 }
1202
1203 /*
1204  * get_func_signature
1205  *              Given procedure id, return the function's argument and result types.
1206  *              (The return value is the result type.)
1207  *
1208  * The arguments are returned as a palloc'd array.
1209  */
1210 Oid
1211 get_func_signature(Oid funcid, Oid **argtypes, int *nargs)
1212 {
1213         HeapTuple       tp;
1214         Form_pg_proc procstruct;
1215         Oid                     result;
1216
1217         tp = SearchSysCache(PROCOID,
1218                                                 ObjectIdGetDatum(funcid),
1219                                                 0, 0, 0);
1220         if (!HeapTupleIsValid(tp))
1221                 elog(ERROR, "cache lookup failed for function %u", funcid);
1222
1223         procstruct = (Form_pg_proc) GETSTRUCT(tp);
1224
1225         result = procstruct->prorettype;
1226         *nargs = (int) procstruct->pronargs;
1227         Assert(*nargs == procstruct->proargtypes.dim1);
1228         *argtypes = (Oid *) palloc(*nargs * sizeof(Oid));
1229         memcpy(*argtypes, procstruct->proargtypes.values, *nargs * sizeof(Oid));
1230
1231         ReleaseSysCache(tp);
1232         return result;
1233 }
1234
1235 /*
1236  * get_func_retset
1237  *              Given procedure id, return the function's proretset flag.
1238  */
1239 bool
1240 get_func_retset(Oid funcid)
1241 {
1242         HeapTuple       tp;
1243         bool            result;
1244
1245         tp = SearchSysCache(PROCOID,
1246                                                 ObjectIdGetDatum(funcid),
1247                                                 0, 0, 0);
1248         if (!HeapTupleIsValid(tp))
1249                 elog(ERROR, "cache lookup failed for function %u", funcid);
1250
1251         result = ((Form_pg_proc) GETSTRUCT(tp))->proretset;
1252         ReleaseSysCache(tp);
1253         return result;
1254 }
1255
1256 /*
1257  * func_strict
1258  *              Given procedure id, return the function's proisstrict flag.
1259  */
1260 bool
1261 func_strict(Oid funcid)
1262 {
1263         HeapTuple       tp;
1264         bool            result;
1265
1266         tp = SearchSysCache(PROCOID,
1267                                                 ObjectIdGetDatum(funcid),
1268                                                 0, 0, 0);
1269         if (!HeapTupleIsValid(tp))
1270                 elog(ERROR, "cache lookup failed for function %u", funcid);
1271
1272         result = ((Form_pg_proc) GETSTRUCT(tp))->proisstrict;
1273         ReleaseSysCache(tp);
1274         return result;
1275 }
1276
1277 /*
1278  * func_volatile
1279  *              Given procedure id, return the function's provolatile flag.
1280  */
1281 char
1282 func_volatile(Oid funcid)
1283 {
1284         HeapTuple       tp;
1285         char            result;
1286
1287         tp = SearchSysCache(PROCOID,
1288                                                 ObjectIdGetDatum(funcid),
1289                                                 0, 0, 0);
1290         if (!HeapTupleIsValid(tp))
1291                 elog(ERROR, "cache lookup failed for function %u", funcid);
1292
1293         result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
1294         ReleaseSysCache(tp);
1295         return result;
1296 }
1297
1298 /*                              ---------- RELATION CACHE ----------                                     */
1299
1300 /*
1301  * get_relname_relid
1302  *              Given name and namespace of a relation, look up the OID.
1303  *
1304  * Returns InvalidOid if there is no such relation.
1305  */
1306 Oid
1307 get_relname_relid(const char *relname, Oid relnamespace)
1308 {
1309         return GetSysCacheOid(RELNAMENSP,
1310                                                   PointerGetDatum(relname),
1311                                                   ObjectIdGetDatum(relnamespace),
1312                                                   0, 0);
1313 }
1314
1315 #ifdef NOT_USED
1316 /*
1317  * get_relnatts
1318  *
1319  *              Returns the number of attributes for a given relation.
1320  */
1321 int
1322 get_relnatts(Oid relid)
1323 {
1324         HeapTuple       tp;
1325
1326         tp = SearchSysCache(RELOID,
1327                                                 ObjectIdGetDatum(relid),
1328                                                 0, 0, 0);
1329         if (HeapTupleIsValid(tp))
1330         {
1331                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1332                 int                     result;
1333
1334                 result = reltup->relnatts;
1335                 ReleaseSysCache(tp);
1336                 return result;
1337         }
1338         else
1339                 return InvalidAttrNumber;
1340 }
1341 #endif
1342
1343 /*
1344  * get_rel_name
1345  *              Returns the name of a given relation.
1346  *
1347  * Returns a palloc'd copy of the string, or NULL if no such relation.
1348  *
1349  * NOTE: since relation name is not unique, be wary of code that uses this
1350  * for anything except preparing error messages.
1351  */
1352 char *
1353 get_rel_name(Oid relid)
1354 {
1355         HeapTuple       tp;
1356
1357         tp = SearchSysCache(RELOID,
1358                                                 ObjectIdGetDatum(relid),
1359                                                 0, 0, 0);
1360         if (HeapTupleIsValid(tp))
1361         {
1362                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1363                 char       *result;
1364
1365                 result = pstrdup(NameStr(reltup->relname));
1366                 ReleaseSysCache(tp);
1367                 return result;
1368         }
1369         else
1370                 return NULL;
1371 }
1372
1373 /*
1374  * get_rel_namespace
1375  *
1376  *              Returns the pg_namespace OID associated with a given relation.
1377  */
1378 Oid
1379 get_rel_namespace(Oid relid)
1380 {
1381         HeapTuple       tp;
1382
1383         tp = SearchSysCache(RELOID,
1384                                                 ObjectIdGetDatum(relid),
1385                                                 0, 0, 0);
1386         if (HeapTupleIsValid(tp))
1387         {
1388                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1389                 Oid                     result;
1390
1391                 result = reltup->relnamespace;
1392                 ReleaseSysCache(tp);
1393                 return result;
1394         }
1395         else
1396                 return InvalidOid;
1397 }
1398
1399 /*
1400  * get_rel_type_id
1401  *
1402  *              Returns the pg_type OID associated with a given relation.
1403  *
1404  * Note: not all pg_class entries have associated pg_type OIDs; so be
1405  * careful to check for InvalidOid result.
1406  */
1407 Oid
1408 get_rel_type_id(Oid relid)
1409 {
1410         HeapTuple       tp;
1411
1412         tp = SearchSysCache(RELOID,
1413                                                 ObjectIdGetDatum(relid),
1414                                                 0, 0, 0);
1415         if (HeapTupleIsValid(tp))
1416         {
1417                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1418                 Oid                     result;
1419
1420                 result = reltup->reltype;
1421                 ReleaseSysCache(tp);
1422                 return result;
1423         }
1424         else
1425                 return InvalidOid;
1426 }
1427
1428 /*
1429  * get_rel_relkind
1430  *
1431  *              Returns the relkind associated with a given relation.
1432  */
1433 char
1434 get_rel_relkind(Oid relid)
1435 {
1436         HeapTuple       tp;
1437
1438         tp = SearchSysCache(RELOID,
1439                                                 ObjectIdGetDatum(relid),
1440                                                 0, 0, 0);
1441         if (HeapTupleIsValid(tp))
1442         {
1443                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1444                 char            result;
1445
1446                 result = reltup->relkind;
1447                 ReleaseSysCache(tp);
1448                 return result;
1449         }
1450         else
1451                 return '\0';
1452 }
1453
1454
1455 /*                              ---------- TYPE CACHE ----------                                                 */
1456
1457 /*
1458  * get_typisdefined
1459  *
1460  *              Given the type OID, determine whether the type is defined
1461  *              (if not, it's only a shell).
1462  */
1463 bool
1464 get_typisdefined(Oid typid)
1465 {
1466         HeapTuple       tp;
1467
1468         tp = SearchSysCache(TYPEOID,
1469                                                 ObjectIdGetDatum(typid),
1470                                                 0, 0, 0);
1471         if (HeapTupleIsValid(tp))
1472         {
1473                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1474                 bool            result;
1475
1476                 result = typtup->typisdefined;
1477                 ReleaseSysCache(tp);
1478                 return result;
1479         }
1480         else
1481                 return false;
1482 }
1483
1484 /*
1485  * get_typlen
1486  *
1487  *              Given the type OID, return the length of the type.
1488  */
1489 int16
1490 get_typlen(Oid typid)
1491 {
1492         HeapTuple       tp;
1493
1494         tp = SearchSysCache(TYPEOID,
1495                                                 ObjectIdGetDatum(typid),
1496                                                 0, 0, 0);
1497         if (HeapTupleIsValid(tp))
1498         {
1499                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1500                 int16           result;
1501
1502                 result = typtup->typlen;
1503                 ReleaseSysCache(tp);
1504                 return result;
1505         }
1506         else
1507                 return 0;
1508 }
1509
1510 /*
1511  * get_typbyval
1512  *
1513  *              Given the type OID, determine whether the type is returned by value or
1514  *              not.  Returns true if by value, false if by reference.
1515  */
1516 bool
1517 get_typbyval(Oid typid)
1518 {
1519         HeapTuple       tp;
1520
1521         tp = SearchSysCache(TYPEOID,
1522                                                 ObjectIdGetDatum(typid),
1523                                                 0, 0, 0);
1524         if (HeapTupleIsValid(tp))
1525         {
1526                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1527                 bool            result;
1528
1529                 result = typtup->typbyval;
1530                 ReleaseSysCache(tp);
1531                 return result;
1532         }
1533         else
1534                 return false;
1535 }
1536
1537 /*
1538  * get_typlenbyval
1539  *
1540  *              A two-fer: given the type OID, return both typlen and typbyval.
1541  *
1542  *              Since both pieces of info are needed to know how to copy a Datum,
1543  *              many places need both.  Might as well get them with one cache lookup
1544  *              instead of two.  Also, this routine raises an error instead of
1545  *              returning a bogus value when given a bad type OID.
1546  */
1547 void
1548 get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
1549 {
1550         HeapTuple       tp;
1551         Form_pg_type typtup;
1552
1553         tp = SearchSysCache(TYPEOID,
1554                                                 ObjectIdGetDatum(typid),
1555                                                 0, 0, 0);
1556         if (!HeapTupleIsValid(tp))
1557                 elog(ERROR, "cache lookup failed for type %u", typid);
1558         typtup = (Form_pg_type) GETSTRUCT(tp);
1559         *typlen = typtup->typlen;
1560         *typbyval = typtup->typbyval;
1561         ReleaseSysCache(tp);
1562 }
1563
1564 /*
1565  * get_typlenbyvalalign
1566  *
1567  *              A three-fer: given the type OID, return typlen, typbyval, typalign.
1568  */
1569 void
1570 get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
1571                                          char *typalign)
1572 {
1573         HeapTuple       tp;
1574         Form_pg_type typtup;
1575
1576         tp = SearchSysCache(TYPEOID,
1577                                                 ObjectIdGetDatum(typid),
1578                                                 0, 0, 0);
1579         if (!HeapTupleIsValid(tp))
1580                 elog(ERROR, "cache lookup failed for type %u", typid);
1581         typtup = (Form_pg_type) GETSTRUCT(tp);
1582         *typlen = typtup->typlen;
1583         *typbyval = typtup->typbyval;
1584         *typalign = typtup->typalign;
1585         ReleaseSysCache(tp);
1586 }
1587
1588 /*
1589  * getTypeIOParam
1590  *              Given a pg_type row, select the type OID to pass to I/O functions
1591  *
1592  * Formerly, all I/O functions were passed pg_type.typelem as their second
1593  * parameter, but we now have a more complex rule about what to pass.
1594  * This knowledge is intended to be centralized here --- direct references
1595  * to typelem elsewhere in the code are wrong, if they are associated with
1596  * I/O calls and not with actual subscripting operations!  (But see
1597  * bootstrap.c's boot_get_type_io_data() if you need to change this.)
1598  *
1599  * As of PostgreSQL 8.1, output functions receive only the value itself
1600  * and not any auxiliary parameters, so the name of this routine is now
1601  * a bit of a misnomer ... it should be getTypeInputParam.
1602  */
1603 Oid
1604 getTypeIOParam(HeapTuple typeTuple)
1605 {
1606         Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
1607
1608         /*
1609          * Array types get their typelem as parameter; everybody else gets their
1610          * own type OID as parameter.  (This is a change from 8.0, in which only
1611          * composite types got their own OID as parameter.)
1612          */
1613         if (OidIsValid(typeStruct->typelem))
1614                 return typeStruct->typelem;
1615         else
1616                 return HeapTupleGetOid(typeTuple);
1617 }
1618
1619 /*
1620  * get_type_io_data
1621  *
1622  *              A six-fer:      given the type OID, return typlen, typbyval, typalign,
1623  *                                      typdelim, typioparam, and IO function OID. The IO function
1624  *                                      returned is controlled by IOFuncSelector
1625  */
1626 void
1627 get_type_io_data(Oid typid,
1628                                  IOFuncSelector which_func,
1629                                  int16 *typlen,
1630                                  bool *typbyval,
1631                                  char *typalign,
1632                                  char *typdelim,
1633                                  Oid *typioparam,
1634                                  Oid *func)
1635 {
1636         HeapTuple       typeTuple;
1637         Form_pg_type typeStruct;
1638
1639         /*
1640          * In bootstrap mode, pass it off to bootstrap.c.  This hack allows us to
1641          * use array_in and array_out during bootstrap.
1642          */
1643         if (IsBootstrapProcessingMode())
1644         {
1645                 Oid                     typinput;
1646                 Oid                     typoutput;
1647
1648                 boot_get_type_io_data(typid,
1649                                                           typlen,
1650                                                           typbyval,
1651                                                           typalign,
1652                                                           typdelim,
1653                                                           typioparam,
1654                                                           &typinput,
1655                                                           &typoutput);
1656                 switch (which_func)
1657                 {
1658                         case IOFunc_input:
1659                                 *func = typinput;
1660                                 break;
1661                         case IOFunc_output:
1662                                 *func = typoutput;
1663                                 break;
1664                         default:
1665                                 elog(ERROR, "binary I/O not supported during bootstrap");
1666                                 break;
1667                 }
1668                 return;
1669         }
1670
1671         typeTuple = SearchSysCache(TYPEOID,
1672                                                            ObjectIdGetDatum(typid),
1673                                                            0, 0, 0);
1674         if (!HeapTupleIsValid(typeTuple))
1675                 elog(ERROR, "cache lookup failed for type %u", typid);
1676         typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
1677
1678         *typlen = typeStruct->typlen;
1679         *typbyval = typeStruct->typbyval;
1680         *typalign = typeStruct->typalign;
1681         *typdelim = typeStruct->typdelim;
1682         *typioparam = getTypeIOParam(typeTuple);
1683         switch (which_func)
1684         {
1685                 case IOFunc_input:
1686                         *func = typeStruct->typinput;
1687                         break;
1688                 case IOFunc_output:
1689                         *func = typeStruct->typoutput;
1690                         break;
1691                 case IOFunc_receive:
1692                         *func = typeStruct->typreceive;
1693                         break;
1694                 case IOFunc_send:
1695                         *func = typeStruct->typsend;
1696                         break;
1697         }
1698         ReleaseSysCache(typeTuple);
1699 }
1700
1701 #ifdef NOT_USED
1702 char
1703 get_typalign(Oid typid)
1704 {
1705         HeapTuple       tp;
1706
1707         tp = SearchSysCache(TYPEOID,
1708                                                 ObjectIdGetDatum(typid),
1709                                                 0, 0, 0);
1710         if (HeapTupleIsValid(tp))
1711         {
1712                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1713                 char            result;
1714
1715                 result = typtup->typalign;
1716                 ReleaseSysCache(tp);
1717                 return result;
1718         }
1719         else
1720                 return 'i';
1721 }
1722 #endif
1723
1724 char
1725 get_typstorage(Oid typid)
1726 {
1727         HeapTuple       tp;
1728
1729         tp = SearchSysCache(TYPEOID,
1730                                                 ObjectIdGetDatum(typid),
1731                                                 0, 0, 0);
1732         if (HeapTupleIsValid(tp))
1733         {
1734                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1735                 char            result;
1736
1737                 result = typtup->typstorage;
1738                 ReleaseSysCache(tp);
1739                 return result;
1740         }
1741         else
1742                 return 'p';
1743 }
1744
1745 /*
1746  * get_typdefault
1747  *        Given a type OID, return the type's default value, if any.
1748  *
1749  *        The result is a palloc'd expression node tree, or NULL if there
1750  *        is no defined default for the datatype.
1751  *
1752  * NB: caller should be prepared to coerce result to correct datatype;
1753  * the returned expression tree might produce something of the wrong type.
1754  */
1755 Node *
1756 get_typdefault(Oid typid)
1757 {
1758         HeapTuple       typeTuple;
1759         Form_pg_type type;
1760         Datum           datum;
1761         bool            isNull;
1762         Node       *expr;
1763
1764         typeTuple = SearchSysCache(TYPEOID,
1765                                                            ObjectIdGetDatum(typid),
1766                                                            0, 0, 0);
1767         if (!HeapTupleIsValid(typeTuple))
1768                 elog(ERROR, "cache lookup failed for type %u", typid);
1769         type = (Form_pg_type) GETSTRUCT(typeTuple);
1770
1771         /*
1772          * typdefault and typdefaultbin are potentially null, so don't try to
1773          * access 'em as struct fields. Must do it the hard way with
1774          * SysCacheGetAttr.
1775          */
1776         datum = SysCacheGetAttr(TYPEOID,
1777                                                         typeTuple,
1778                                                         Anum_pg_type_typdefaultbin,
1779                                                         &isNull);
1780
1781         if (!isNull)
1782         {
1783                 /* We have an expression default */
1784                 expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
1785                                                                                                                                 datum)));
1786         }
1787         else
1788         {
1789                 /* Perhaps we have a plain literal default */
1790                 datum = SysCacheGetAttr(TYPEOID,
1791                                                                 typeTuple,
1792                                                                 Anum_pg_type_typdefault,
1793                                                                 &isNull);
1794
1795                 if (!isNull)
1796                 {
1797                         char       *strDefaultVal;
1798
1799                         /* Convert text datum to C string */
1800                         strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
1801                                                                                                                                 datum));
1802                         /* Convert C string to a value of the given type */
1803                         datum = OidInputFunctionCall(type->typinput, strDefaultVal,
1804                                                                                  getTypeIOParam(typeTuple), -1);
1805                         /* Build a Const node containing the value */
1806                         expr = (Node *) makeConst(typid,
1807                                                                           type->typlen,
1808                                                                           datum,
1809                                                                           false,
1810                                                                           type->typbyval);
1811                         pfree(strDefaultVal);
1812                 }
1813                 else
1814                 {
1815                         /* No default */
1816                         expr = NULL;
1817                 }
1818         }
1819
1820         ReleaseSysCache(typeTuple);
1821
1822         return expr;
1823 }
1824
1825 /*
1826  * getBaseType
1827  *              If the given type is a domain, return its base type;
1828  *              otherwise return the type's own OID.
1829  */
1830 Oid
1831 getBaseType(Oid typid)
1832 {
1833         int32           typmod = -1;
1834
1835         return getBaseTypeAndTypmod(typid, &typmod);
1836 }
1837
1838 /*
1839  * getBaseTypeAndTypmod
1840  *              If the given type is a domain, return its base type and typmod;
1841  *              otherwise return the type's own OID, and leave *typmod unchanged.
1842  *
1843  * Note that the "applied typmod" should be -1 for every domain level
1844  * above the bottommost; therefore, if the passed-in typid is indeed
1845  * a domain, *typmod should be -1.
1846  */
1847 Oid
1848 getBaseTypeAndTypmod(Oid typid, int32 *typmod)
1849 {
1850         /*
1851          * We loop to find the bottom base type in a stack of domains.
1852          */
1853         for (;;)
1854         {
1855                 HeapTuple       tup;
1856                 Form_pg_type typTup;
1857
1858                 tup = SearchSysCache(TYPEOID,
1859                                                          ObjectIdGetDatum(typid),
1860                                                          0, 0, 0);
1861                 if (!HeapTupleIsValid(tup))
1862                         elog(ERROR, "cache lookup failed for type %u", typid);
1863                 typTup = (Form_pg_type) GETSTRUCT(tup);
1864                 if (typTup->typtype != 'd')
1865                 {
1866                         /* Not a domain, so done */
1867                         ReleaseSysCache(tup);
1868                         break;
1869                 }
1870
1871                 Assert(*typmod == -1);
1872                 typid = typTup->typbasetype;
1873                 *typmod = typTup->typtypmod;
1874
1875                 ReleaseSysCache(tup);
1876         }
1877
1878         return typid;
1879 }
1880
1881 /*
1882  * get_typavgwidth
1883  *
1884  *        Given a type OID and a typmod value (pass -1 if typmod is unknown),
1885  *        estimate the average width of values of the type.  This is used by
1886  *        the planner, which doesn't require absolutely correct results;
1887  *        it's OK (and expected) to guess if we don't know for sure.
1888  */
1889 int32
1890 get_typavgwidth(Oid typid, int32 typmod)
1891 {
1892         int                     typlen = get_typlen(typid);
1893         int32           maxwidth;
1894
1895         /*
1896          * Easy if it's a fixed-width type
1897          */
1898         if (typlen > 0)
1899                 return typlen;
1900
1901         /*
1902          * type_maximum_size knows the encoding of typmod for some datatypes;
1903          * don't duplicate that knowledge here.
1904          */
1905         maxwidth = type_maximum_size(typid, typmod);
1906         if (maxwidth > 0)
1907         {
1908                 /*
1909                  * For BPCHAR, the max width is also the only width.  Otherwise we
1910                  * need to guess about the typical data width given the max. A sliding
1911                  * scale for percentage of max width seems reasonable.
1912                  */
1913                 if (typid == BPCHAROID)
1914                         return maxwidth;
1915                 if (maxwidth <= 32)
1916                         return maxwidth;        /* assume full width */
1917                 if (maxwidth < 1000)
1918                         return 32 + (maxwidth - 32) / 2;        /* assume 50% */
1919
1920                 /*
1921                  * Beyond 1000, assume we're looking at something like
1922                  * "varchar(10000)" where the limit isn't actually reached often, and
1923                  * use a fixed estimate.
1924                  */
1925                 return 32 + (1000 - 32) / 2;
1926         }
1927
1928         /*
1929          * Ooops, we have no idea ... wild guess time.
1930          */
1931         return 32;
1932 }
1933
1934 /*
1935  * get_typtype
1936  *
1937  *              Given the type OID, find if it is a basic type, a complex type, etc.
1938  *              It returns the null char if the cache lookup fails...
1939  */
1940 char
1941 get_typtype(Oid typid)
1942 {
1943         HeapTuple       tp;
1944
1945         tp = SearchSysCache(TYPEOID,
1946                                                 ObjectIdGetDatum(typid),
1947                                                 0, 0, 0);
1948         if (HeapTupleIsValid(tp))
1949         {
1950                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1951                 char            result;
1952
1953                 result = typtup->typtype;
1954                 ReleaseSysCache(tp);
1955                 return result;
1956         }
1957         else
1958                 return '\0';
1959 }
1960
1961 /*
1962  * type_is_rowtype
1963  *
1964  *              Convenience function to determine whether a type OID represents
1965  *              a "rowtype" type --- either RECORD or a named composite type.
1966  */
1967 bool
1968 type_is_rowtype(Oid typid)
1969 {
1970         return (typid == RECORDOID || get_typtype(typid) == 'c');
1971 }
1972
1973 /*
1974  * get_typ_typrelid
1975  *
1976  *              Given the type OID, get the typrelid (InvalidOid if not a complex
1977  *              type).
1978  */
1979 Oid
1980 get_typ_typrelid(Oid typid)
1981 {
1982         HeapTuple       tp;
1983
1984         tp = SearchSysCache(TYPEOID,
1985                                                 ObjectIdGetDatum(typid),
1986                                                 0, 0, 0);
1987         if (HeapTupleIsValid(tp))
1988         {
1989                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1990                 Oid                     result;
1991
1992                 result = typtup->typrelid;
1993                 ReleaseSysCache(tp);
1994                 return result;
1995         }
1996         else
1997                 return InvalidOid;
1998 }
1999
2000 /*
2001  * get_element_type
2002  *
2003  *              Given the type OID, get the typelem (InvalidOid if not an array type).
2004  *
2005  * NB: this only considers varlena arrays to be true arrays; InvalidOid is
2006  * returned if the input is a fixed-length array type.
2007  */
2008 Oid
2009 get_element_type(Oid typid)
2010 {
2011         HeapTuple       tp;
2012
2013         tp = SearchSysCache(TYPEOID,
2014                                                 ObjectIdGetDatum(typid),
2015                                                 0, 0, 0);
2016         if (HeapTupleIsValid(tp))
2017         {
2018                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2019                 Oid                     result;
2020
2021                 if (typtup->typlen == -1)
2022                         result = typtup->typelem;
2023                 else
2024                         result = InvalidOid;
2025                 ReleaseSysCache(tp);
2026                 return result;
2027         }
2028         else
2029                 return InvalidOid;
2030 }
2031
2032 /*
2033  * get_array_type
2034  *
2035  *              Given the type OID, get the corresponding array type.
2036  *              Returns InvalidOid if no array type can be found.
2037  *
2038  * NB: this only considers varlena arrays to be true arrays.
2039  */
2040 Oid
2041 get_array_type(Oid typid)
2042 {
2043         HeapTuple       tp;
2044
2045         tp = SearchSysCache(TYPEOID,
2046                                                 ObjectIdGetDatum(typid),
2047                                                 0, 0, 0);
2048         if (HeapTupleIsValid(tp))
2049         {
2050                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2051                 char       *array_typename;
2052                 Oid                     namespaceId;
2053
2054                 array_typename = makeArrayTypeName(NameStr(typtup->typname));
2055                 namespaceId = typtup->typnamespace;
2056                 ReleaseSysCache(tp);
2057
2058                 tp = SearchSysCache(TYPENAMENSP,
2059                                                         PointerGetDatum(array_typename),
2060                                                         ObjectIdGetDatum(namespaceId),
2061                                                         0, 0);
2062
2063                 pfree(array_typename);
2064
2065                 if (HeapTupleIsValid(tp))
2066                 {
2067                         Oid                     result;
2068
2069                         typtup = (Form_pg_type) GETSTRUCT(tp);
2070                         if (typtup->typlen == -1 && typtup->typelem == typid)
2071                                 result = HeapTupleGetOid(tp);
2072                         else
2073                                 result = InvalidOid;
2074                         ReleaseSysCache(tp);
2075                         return result;
2076                 }
2077         }
2078         return InvalidOid;
2079 }
2080
2081 /*
2082  * getTypeInputInfo
2083  *
2084  *              Get info needed for converting values of a type to internal form
2085  */
2086 void
2087 getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
2088 {
2089         HeapTuple       typeTuple;
2090         Form_pg_type pt;
2091
2092         typeTuple = SearchSysCache(TYPEOID,
2093                                                            ObjectIdGetDatum(type),
2094                                                            0, 0, 0);
2095         if (!HeapTupleIsValid(typeTuple))
2096                 elog(ERROR, "cache lookup failed for type %u", type);
2097         pt = (Form_pg_type) GETSTRUCT(typeTuple);
2098
2099         if (!pt->typisdefined)
2100                 ereport(ERROR,
2101                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2102                                  errmsg("type %s is only a shell",
2103                                                 format_type_be(type))));
2104         if (!OidIsValid(pt->typinput))
2105                 ereport(ERROR,
2106                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2107                                  errmsg("no input function available for type %s",
2108                                                 format_type_be(type))));
2109
2110         *typInput = pt->typinput;
2111         *typIOParam = getTypeIOParam(typeTuple);
2112
2113         ReleaseSysCache(typeTuple);
2114 }
2115
2116 /*
2117  * getTypeOutputInfo
2118  *
2119  *              Get info needed for printing values of a type
2120  */
2121 void
2122 getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
2123 {
2124         HeapTuple       typeTuple;
2125         Form_pg_type pt;
2126
2127         typeTuple = SearchSysCache(TYPEOID,
2128                                                            ObjectIdGetDatum(type),
2129                                                            0, 0, 0);
2130         if (!HeapTupleIsValid(typeTuple))
2131                 elog(ERROR, "cache lookup failed for type %u", type);
2132         pt = (Form_pg_type) GETSTRUCT(typeTuple);
2133
2134         if (!pt->typisdefined)
2135                 ereport(ERROR,
2136                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2137                                  errmsg("type %s is only a shell",
2138                                                 format_type_be(type))));
2139         if (!OidIsValid(pt->typoutput))
2140                 ereport(ERROR,
2141                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2142                                  errmsg("no output function available for type %s",
2143                                                 format_type_be(type))));
2144
2145         *typOutput = pt->typoutput;
2146         *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
2147
2148         ReleaseSysCache(typeTuple);
2149 }
2150
2151 /*
2152  * getTypeBinaryInputInfo
2153  *
2154  *              Get info needed for binary input of values of a type
2155  */
2156 void
2157 getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
2158 {
2159         HeapTuple       typeTuple;
2160         Form_pg_type pt;
2161
2162         typeTuple = SearchSysCache(TYPEOID,
2163                                                            ObjectIdGetDatum(type),
2164                                                            0, 0, 0);
2165         if (!HeapTupleIsValid(typeTuple))
2166                 elog(ERROR, "cache lookup failed for type %u", type);
2167         pt = (Form_pg_type) GETSTRUCT(typeTuple);
2168
2169         if (!pt->typisdefined)
2170                 ereport(ERROR,
2171                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2172                                  errmsg("type %s is only a shell",
2173                                                 format_type_be(type))));
2174         if (!OidIsValid(pt->typreceive))
2175                 ereport(ERROR,
2176                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2177                                  errmsg("no binary input function available for type %s",
2178                                                 format_type_be(type))));
2179
2180         *typReceive = pt->typreceive;
2181         *typIOParam = getTypeIOParam(typeTuple);
2182
2183         ReleaseSysCache(typeTuple);
2184 }
2185
2186 /*
2187  * getTypeBinaryOutputInfo
2188  *
2189  *              Get info needed for binary output of values of a type
2190  */
2191 void
2192 getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
2193 {
2194         HeapTuple       typeTuple;
2195         Form_pg_type pt;
2196
2197         typeTuple = SearchSysCache(TYPEOID,
2198                                                            ObjectIdGetDatum(type),
2199                                                            0, 0, 0);
2200         if (!HeapTupleIsValid(typeTuple))
2201                 elog(ERROR, "cache lookup failed for type %u", type);
2202         pt = (Form_pg_type) GETSTRUCT(typeTuple);
2203
2204         if (!pt->typisdefined)
2205                 ereport(ERROR,
2206                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2207                                  errmsg("type %s is only a shell",
2208                                                 format_type_be(type))));
2209         if (!OidIsValid(pt->typsend))
2210                 ereport(ERROR,
2211                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2212                                  errmsg("no binary output function available for type %s",
2213                                                 format_type_be(type))));
2214
2215         *typSend = pt->typsend;
2216         *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
2217
2218         ReleaseSysCache(typeTuple);
2219 }
2220
2221 /*
2222  * get_typmodin
2223  *
2224  *              Given the type OID, return the type's typmodin procedure, if any.
2225  */
2226 Oid
2227 get_typmodin(Oid typid)
2228 {
2229         HeapTuple       tp;
2230
2231         tp = SearchSysCache(TYPEOID,
2232                                                 ObjectIdGetDatum(typid),
2233                                                 0, 0, 0);
2234         if (HeapTupleIsValid(tp))
2235         {
2236                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2237                 Oid                     result;
2238
2239                 result = typtup->typmodin;
2240                 ReleaseSysCache(tp);
2241                 return result;
2242         }
2243         else
2244                 return InvalidOid;
2245 }
2246
2247 #ifdef NOT_USED
2248 /*
2249  * get_typmodout
2250  *
2251  *              Given the type OID, return the type's typmodout procedure, if any.
2252  */
2253 Oid
2254 get_typmodout(Oid typid)
2255 {
2256         HeapTuple       tp;
2257
2258         tp = SearchSysCache(TYPEOID,
2259                                                 ObjectIdGetDatum(typid),
2260                                                 0, 0, 0);
2261         if (HeapTupleIsValid(tp))
2262         {
2263                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2264                 Oid                     result;
2265
2266                 result = typtup->typmodout;
2267                 ReleaseSysCache(tp);
2268                 return result;
2269         }
2270         else
2271                 return InvalidOid;
2272 }
2273 #endif /* NOT_USED */
2274
2275
2276 /*                              ---------- STATISTICS CACHE ----------                                   */
2277
2278 /*
2279  * get_attavgwidth
2280  *
2281  *        Given the table and attribute number of a column, get the average
2282  *        width of entries in the column.  Return zero if no data available.
2283  */
2284 int32
2285 get_attavgwidth(Oid relid, AttrNumber attnum)
2286 {
2287         HeapTuple       tp;
2288
2289         tp = SearchSysCache(STATRELATT,
2290                                                 ObjectIdGetDatum(relid),
2291                                                 Int16GetDatum(attnum),
2292                                                 0, 0);
2293         if (HeapTupleIsValid(tp))
2294         {
2295                 int32           stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
2296
2297                 ReleaseSysCache(tp);
2298                 if (stawidth > 0)
2299                         return stawidth;
2300         }
2301         return 0;
2302 }
2303
2304 /*
2305  * get_attstatsslot
2306  *
2307  *              Extract the contents of a "slot" of a pg_statistic tuple.
2308  *              Returns TRUE if requested slot type was found, else FALSE.
2309  *
2310  * Unlike other routines in this file, this takes a pointer to an
2311  * already-looked-up tuple in the pg_statistic cache.  We do this since
2312  * most callers will want to extract more than one value from the cache
2313  * entry, and we don't want to repeat the cache lookup unnecessarily.
2314  *
2315  * statstuple: pg_statistics tuple to be examined.
2316  * atttype: type OID of attribute (can be InvalidOid if values == NULL).
2317  * atttypmod: typmod of attribute (can be 0 if values == NULL).
2318  * reqkind: STAKIND code for desired statistics slot kind.
2319  * reqop: STAOP value wanted, or InvalidOid if don't care.
2320  * values, nvalues: if not NULL, the slot's stavalues are extracted.
2321  * numbers, nnumbers: if not NULL, the slot's stanumbers are extracted.
2322  *
2323  * If assigned, values and numbers are set to point to palloc'd arrays.
2324  * If the attribute type is pass-by-reference, the values referenced by
2325  * the values array are themselves palloc'd.  The palloc'd stuff can be
2326  * freed by calling free_attstatsslot.
2327  */
2328 bool
2329 get_attstatsslot(HeapTuple statstuple,
2330                                  Oid atttype, int32 atttypmod,
2331                                  int reqkind, Oid reqop,
2332                                  Datum **values, int *nvalues,
2333                                  float4 **numbers, int *nnumbers)
2334 {
2335         Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
2336         int                     i,
2337                                 j;
2338         Datum           val;
2339         bool            isnull;
2340         ArrayType  *statarray;
2341         int                     narrayelem;
2342         HeapTuple       typeTuple;
2343         Form_pg_type typeForm;
2344
2345         for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
2346         {
2347                 if ((&stats->stakind1)[i] == reqkind &&
2348                         (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
2349                         break;
2350         }
2351         if (i >= STATISTIC_NUM_SLOTS)
2352                 return false;                   /* not there */
2353
2354         if (values)
2355         {
2356                 val = SysCacheGetAttr(STATRELATT, statstuple,
2357                                                           Anum_pg_statistic_stavalues1 + i,
2358                                                           &isnull);
2359                 if (isnull)
2360                         elog(ERROR, "stavalues is null");
2361                 statarray = DatumGetArrayTypeP(val);
2362
2363                 /* Need to get info about the array element type */
2364                 typeTuple = SearchSysCache(TYPEOID,
2365                                                                    ObjectIdGetDatum(atttype),
2366                                                                    0, 0, 0);
2367                 if (!HeapTupleIsValid(typeTuple))
2368                         elog(ERROR, "cache lookup failed for type %u", atttype);
2369                 typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
2370
2371                 /* Deconstruct array into Datum elements; NULLs not expected */
2372                 deconstruct_array(statarray,
2373                                                   atttype,
2374                                                   typeForm->typlen,
2375                                                   typeForm->typbyval,
2376                                                   typeForm->typalign,
2377                                                   values, NULL, nvalues);
2378
2379                 /*
2380                  * If the element type is pass-by-reference, we now have a bunch of
2381                  * Datums that are pointers into the syscache value.  Copy them to
2382                  * avoid problems if syscache decides to drop the entry.
2383                  */
2384                 if (!typeForm->typbyval)
2385                 {
2386                         for (j = 0; j < *nvalues; j++)
2387                         {
2388                                 (*values)[j] = datumCopy((*values)[j],
2389                                                                                  typeForm->typbyval,
2390                                                                                  typeForm->typlen);
2391                         }
2392                 }
2393
2394                 ReleaseSysCache(typeTuple);
2395
2396                 /*
2397                  * Free statarray if it's a detoasted copy.
2398                  */
2399                 if ((Pointer) statarray != DatumGetPointer(val))
2400                         pfree(statarray);
2401         }
2402
2403         if (numbers)
2404         {
2405                 val = SysCacheGetAttr(STATRELATT, statstuple,
2406                                                           Anum_pg_statistic_stanumbers1 + i,
2407                                                           &isnull);
2408                 if (isnull)
2409                         elog(ERROR, "stanumbers is null");
2410                 statarray = DatumGetArrayTypeP(val);
2411
2412                 /*
2413                  * We expect the array to be a 1-D float4 array; verify that. We don't
2414                  * need to use deconstruct_array() since the array data is just going
2415                  * to look like a C array of float4 values.
2416                  */
2417                 narrayelem = ARR_DIMS(statarray)[0];
2418                 if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
2419                         ARR_HASNULL(statarray) ||
2420                         ARR_ELEMTYPE(statarray) != FLOAT4OID)
2421                         elog(ERROR, "stanumbers is not a 1-D float4 array");
2422                 *numbers = (float4 *) palloc(narrayelem * sizeof(float4));
2423                 memcpy(*numbers, ARR_DATA_PTR(statarray), narrayelem * sizeof(float4));
2424                 *nnumbers = narrayelem;
2425
2426                 /*
2427                  * Free statarray if it's a detoasted copy.
2428                  */
2429                 if ((Pointer) statarray != DatumGetPointer(val))
2430                         pfree(statarray);
2431         }
2432
2433         return true;
2434 }
2435
2436 /*
2437  * free_attstatsslot
2438  *              Free data allocated by get_attstatsslot
2439  *
2440  * atttype need be valid only if values != NULL.
2441  */
2442 void
2443 free_attstatsslot(Oid atttype,
2444                                   Datum *values, int nvalues,
2445                                   float4 *numbers, int nnumbers)
2446 {
2447         if (values)
2448         {
2449                 if (!get_typbyval(atttype))
2450                 {
2451                         int                     i;
2452
2453                         for (i = 0; i < nvalues; i++)
2454                                 pfree(DatumGetPointer(values[i]));
2455                 }
2456                 pfree(values);
2457         }
2458         if (numbers)
2459                 pfree(numbers);
2460 }
2461
2462 /*                              ---------- PG_NAMESPACE CACHE ----------                                 */
2463
2464 /*
2465  * get_namespace_name
2466  *              Returns the name of a given namespace
2467  *
2468  * Returns a palloc'd copy of the string, or NULL if no such namespace.
2469  */
2470 char *
2471 get_namespace_name(Oid nspid)
2472 {
2473         HeapTuple       tp;
2474
2475         tp = SearchSysCache(NAMESPACEOID,
2476                                                 ObjectIdGetDatum(nspid),
2477                                                 0, 0, 0);
2478         if (HeapTupleIsValid(tp))
2479         {
2480                 Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
2481                 char       *result;
2482
2483                 result = pstrdup(NameStr(nsptup->nspname));
2484                 ReleaseSysCache(tp);
2485                 return result;
2486         }
2487         else
2488                 return NULL;
2489 }
2490
2491 /*                              ---------- PG_AUTHID CACHE ----------                                    */
2492
2493 /*
2494  * get_roleid
2495  *        Given a role name, look up the role's OID.
2496  *        Returns InvalidOid if no such role.
2497  */
2498 Oid
2499 get_roleid(const char *rolname)
2500 {
2501         return GetSysCacheOid(AUTHNAME,
2502                                                   PointerGetDatum(rolname),
2503                                                   0, 0, 0);
2504 }
2505
2506 /*
2507  * get_roleid_checked
2508  *        Given a role name, look up the role's OID.
2509  *        ereports if no such role.
2510  */
2511 Oid
2512 get_roleid_checked(const char *rolname)
2513 {
2514         Oid                     roleid;
2515
2516         roleid = get_roleid(rolname);
2517         if (!OidIsValid(roleid))
2518                 ereport(ERROR,
2519                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2520                                  errmsg("role \"%s\" does not exist", rolname)));
2521         return roleid;
2522 }