]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/lsyscache.c
c449ad6e74220b93dbabfb0acff342a379464f19
[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.146 2007/01/22 01:35:21 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 /*
1299  * get_func_cost
1300  *              Given procedure id, return the function's procost field.
1301  */
1302 float4
1303 get_func_cost(Oid funcid)
1304 {
1305         HeapTuple       tp;
1306         float4          result;
1307
1308         tp = SearchSysCache(PROCOID,
1309                                                 ObjectIdGetDatum(funcid),
1310                                                 0, 0, 0);
1311         if (!HeapTupleIsValid(tp))
1312                 elog(ERROR, "cache lookup failed for function %u", funcid);
1313
1314         result = ((Form_pg_proc) GETSTRUCT(tp))->procost;
1315         ReleaseSysCache(tp);
1316         return result;
1317 }
1318
1319 /*
1320  * get_func_rows
1321  *              Given procedure id, return the function's prorows field.
1322  */
1323 float4
1324 get_func_rows(Oid funcid)
1325 {
1326         HeapTuple       tp;
1327         float4          result;
1328
1329         tp = SearchSysCache(PROCOID,
1330                                                 ObjectIdGetDatum(funcid),
1331                                                 0, 0, 0);
1332         if (!HeapTupleIsValid(tp))
1333                 elog(ERROR, "cache lookup failed for function %u", funcid);
1334
1335         result = ((Form_pg_proc) GETSTRUCT(tp))->prorows;
1336         ReleaseSysCache(tp);
1337         return result;
1338 }
1339
1340 /*                              ---------- RELATION CACHE ----------                                     */
1341
1342 /*
1343  * get_relname_relid
1344  *              Given name and namespace of a relation, look up the OID.
1345  *
1346  * Returns InvalidOid if there is no such relation.
1347  */
1348 Oid
1349 get_relname_relid(const char *relname, Oid relnamespace)
1350 {
1351         return GetSysCacheOid(RELNAMENSP,
1352                                                   PointerGetDatum(relname),
1353                                                   ObjectIdGetDatum(relnamespace),
1354                                                   0, 0);
1355 }
1356
1357 #ifdef NOT_USED
1358 /*
1359  * get_relnatts
1360  *
1361  *              Returns the number of attributes for a given relation.
1362  */
1363 int
1364 get_relnatts(Oid relid)
1365 {
1366         HeapTuple       tp;
1367
1368         tp = SearchSysCache(RELOID,
1369                                                 ObjectIdGetDatum(relid),
1370                                                 0, 0, 0);
1371         if (HeapTupleIsValid(tp))
1372         {
1373                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1374                 int                     result;
1375
1376                 result = reltup->relnatts;
1377                 ReleaseSysCache(tp);
1378                 return result;
1379         }
1380         else
1381                 return InvalidAttrNumber;
1382 }
1383 #endif
1384
1385 /*
1386  * get_rel_name
1387  *              Returns the name of a given relation.
1388  *
1389  * Returns a palloc'd copy of the string, or NULL if no such relation.
1390  *
1391  * NOTE: since relation name is not unique, be wary of code that uses this
1392  * for anything except preparing error messages.
1393  */
1394 char *
1395 get_rel_name(Oid relid)
1396 {
1397         HeapTuple       tp;
1398
1399         tp = SearchSysCache(RELOID,
1400                                                 ObjectIdGetDatum(relid),
1401                                                 0, 0, 0);
1402         if (HeapTupleIsValid(tp))
1403         {
1404                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1405                 char       *result;
1406
1407                 result = pstrdup(NameStr(reltup->relname));
1408                 ReleaseSysCache(tp);
1409                 return result;
1410         }
1411         else
1412                 return NULL;
1413 }
1414
1415 /*
1416  * get_rel_namespace
1417  *
1418  *              Returns the pg_namespace OID associated with a given relation.
1419  */
1420 Oid
1421 get_rel_namespace(Oid relid)
1422 {
1423         HeapTuple       tp;
1424
1425         tp = SearchSysCache(RELOID,
1426                                                 ObjectIdGetDatum(relid),
1427                                                 0, 0, 0);
1428         if (HeapTupleIsValid(tp))
1429         {
1430                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1431                 Oid                     result;
1432
1433                 result = reltup->relnamespace;
1434                 ReleaseSysCache(tp);
1435                 return result;
1436         }
1437         else
1438                 return InvalidOid;
1439 }
1440
1441 /*
1442  * get_rel_type_id
1443  *
1444  *              Returns the pg_type OID associated with a given relation.
1445  *
1446  * Note: not all pg_class entries have associated pg_type OIDs; so be
1447  * careful to check for InvalidOid result.
1448  */
1449 Oid
1450 get_rel_type_id(Oid relid)
1451 {
1452         HeapTuple       tp;
1453
1454         tp = SearchSysCache(RELOID,
1455                                                 ObjectIdGetDatum(relid),
1456                                                 0, 0, 0);
1457         if (HeapTupleIsValid(tp))
1458         {
1459                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1460                 Oid                     result;
1461
1462                 result = reltup->reltype;
1463                 ReleaseSysCache(tp);
1464                 return result;
1465         }
1466         else
1467                 return InvalidOid;
1468 }
1469
1470 /*
1471  * get_rel_relkind
1472  *
1473  *              Returns the relkind associated with a given relation.
1474  */
1475 char
1476 get_rel_relkind(Oid relid)
1477 {
1478         HeapTuple       tp;
1479
1480         tp = SearchSysCache(RELOID,
1481                                                 ObjectIdGetDatum(relid),
1482                                                 0, 0, 0);
1483         if (HeapTupleIsValid(tp))
1484         {
1485                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1486                 char            result;
1487
1488                 result = reltup->relkind;
1489                 ReleaseSysCache(tp);
1490                 return result;
1491         }
1492         else
1493                 return '\0';
1494 }
1495
1496
1497 /*                              ---------- TYPE CACHE ----------                                                 */
1498
1499 /*
1500  * get_typisdefined
1501  *
1502  *              Given the type OID, determine whether the type is defined
1503  *              (if not, it's only a shell).
1504  */
1505 bool
1506 get_typisdefined(Oid typid)
1507 {
1508         HeapTuple       tp;
1509
1510         tp = SearchSysCache(TYPEOID,
1511                                                 ObjectIdGetDatum(typid),
1512                                                 0, 0, 0);
1513         if (HeapTupleIsValid(tp))
1514         {
1515                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1516                 bool            result;
1517
1518                 result = typtup->typisdefined;
1519                 ReleaseSysCache(tp);
1520                 return result;
1521         }
1522         else
1523                 return false;
1524 }
1525
1526 /*
1527  * get_typlen
1528  *
1529  *              Given the type OID, return the length of the type.
1530  */
1531 int16
1532 get_typlen(Oid typid)
1533 {
1534         HeapTuple       tp;
1535
1536         tp = SearchSysCache(TYPEOID,
1537                                                 ObjectIdGetDatum(typid),
1538                                                 0, 0, 0);
1539         if (HeapTupleIsValid(tp))
1540         {
1541                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1542                 int16           result;
1543
1544                 result = typtup->typlen;
1545                 ReleaseSysCache(tp);
1546                 return result;
1547         }
1548         else
1549                 return 0;
1550 }
1551
1552 /*
1553  * get_typbyval
1554  *
1555  *              Given the type OID, determine whether the type is returned by value or
1556  *              not.  Returns true if by value, false if by reference.
1557  */
1558 bool
1559 get_typbyval(Oid typid)
1560 {
1561         HeapTuple       tp;
1562
1563         tp = SearchSysCache(TYPEOID,
1564                                                 ObjectIdGetDatum(typid),
1565                                                 0, 0, 0);
1566         if (HeapTupleIsValid(tp))
1567         {
1568                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1569                 bool            result;
1570
1571                 result = typtup->typbyval;
1572                 ReleaseSysCache(tp);
1573                 return result;
1574         }
1575         else
1576                 return false;
1577 }
1578
1579 /*
1580  * get_typlenbyval
1581  *
1582  *              A two-fer: given the type OID, return both typlen and typbyval.
1583  *
1584  *              Since both pieces of info are needed to know how to copy a Datum,
1585  *              many places need both.  Might as well get them with one cache lookup
1586  *              instead of two.  Also, this routine raises an error instead of
1587  *              returning a bogus value when given a bad type OID.
1588  */
1589 void
1590 get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
1591 {
1592         HeapTuple       tp;
1593         Form_pg_type typtup;
1594
1595         tp = SearchSysCache(TYPEOID,
1596                                                 ObjectIdGetDatum(typid),
1597                                                 0, 0, 0);
1598         if (!HeapTupleIsValid(tp))
1599                 elog(ERROR, "cache lookup failed for type %u", typid);
1600         typtup = (Form_pg_type) GETSTRUCT(tp);
1601         *typlen = typtup->typlen;
1602         *typbyval = typtup->typbyval;
1603         ReleaseSysCache(tp);
1604 }
1605
1606 /*
1607  * get_typlenbyvalalign
1608  *
1609  *              A three-fer: given the type OID, return typlen, typbyval, typalign.
1610  */
1611 void
1612 get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
1613                                          char *typalign)
1614 {
1615         HeapTuple       tp;
1616         Form_pg_type typtup;
1617
1618         tp = SearchSysCache(TYPEOID,
1619                                                 ObjectIdGetDatum(typid),
1620                                                 0, 0, 0);
1621         if (!HeapTupleIsValid(tp))
1622                 elog(ERROR, "cache lookup failed for type %u", typid);
1623         typtup = (Form_pg_type) GETSTRUCT(tp);
1624         *typlen = typtup->typlen;
1625         *typbyval = typtup->typbyval;
1626         *typalign = typtup->typalign;
1627         ReleaseSysCache(tp);
1628 }
1629
1630 /*
1631  * getTypeIOParam
1632  *              Given a pg_type row, select the type OID to pass to I/O functions
1633  *
1634  * Formerly, all I/O functions were passed pg_type.typelem as their second
1635  * parameter, but we now have a more complex rule about what to pass.
1636  * This knowledge is intended to be centralized here --- direct references
1637  * to typelem elsewhere in the code are wrong, if they are associated with
1638  * I/O calls and not with actual subscripting operations!  (But see
1639  * bootstrap.c's boot_get_type_io_data() if you need to change this.)
1640  *
1641  * As of PostgreSQL 8.1, output functions receive only the value itself
1642  * and not any auxiliary parameters, so the name of this routine is now
1643  * a bit of a misnomer ... it should be getTypeInputParam.
1644  */
1645 Oid
1646 getTypeIOParam(HeapTuple typeTuple)
1647 {
1648         Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
1649
1650         /*
1651          * Array types get their typelem as parameter; everybody else gets their
1652          * own type OID as parameter.  (This is a change from 8.0, in which only
1653          * composite types got their own OID as parameter.)
1654          */
1655         if (OidIsValid(typeStruct->typelem))
1656                 return typeStruct->typelem;
1657         else
1658                 return HeapTupleGetOid(typeTuple);
1659 }
1660
1661 /*
1662  * get_type_io_data
1663  *
1664  *              A six-fer:      given the type OID, return typlen, typbyval, typalign,
1665  *                                      typdelim, typioparam, and IO function OID. The IO function
1666  *                                      returned is controlled by IOFuncSelector
1667  */
1668 void
1669 get_type_io_data(Oid typid,
1670                                  IOFuncSelector which_func,
1671                                  int16 *typlen,
1672                                  bool *typbyval,
1673                                  char *typalign,
1674                                  char *typdelim,
1675                                  Oid *typioparam,
1676                                  Oid *func)
1677 {
1678         HeapTuple       typeTuple;
1679         Form_pg_type typeStruct;
1680
1681         /*
1682          * In bootstrap mode, pass it off to bootstrap.c.  This hack allows us to
1683          * use array_in and array_out during bootstrap.
1684          */
1685         if (IsBootstrapProcessingMode())
1686         {
1687                 Oid                     typinput;
1688                 Oid                     typoutput;
1689
1690                 boot_get_type_io_data(typid,
1691                                                           typlen,
1692                                                           typbyval,
1693                                                           typalign,
1694                                                           typdelim,
1695                                                           typioparam,
1696                                                           &typinput,
1697                                                           &typoutput);
1698                 switch (which_func)
1699                 {
1700                         case IOFunc_input:
1701                                 *func = typinput;
1702                                 break;
1703                         case IOFunc_output:
1704                                 *func = typoutput;
1705                                 break;
1706                         default:
1707                                 elog(ERROR, "binary I/O not supported during bootstrap");
1708                                 break;
1709                 }
1710                 return;
1711         }
1712
1713         typeTuple = SearchSysCache(TYPEOID,
1714                                                            ObjectIdGetDatum(typid),
1715                                                            0, 0, 0);
1716         if (!HeapTupleIsValid(typeTuple))
1717                 elog(ERROR, "cache lookup failed for type %u", typid);
1718         typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
1719
1720         *typlen = typeStruct->typlen;
1721         *typbyval = typeStruct->typbyval;
1722         *typalign = typeStruct->typalign;
1723         *typdelim = typeStruct->typdelim;
1724         *typioparam = getTypeIOParam(typeTuple);
1725         switch (which_func)
1726         {
1727                 case IOFunc_input:
1728                         *func = typeStruct->typinput;
1729                         break;
1730                 case IOFunc_output:
1731                         *func = typeStruct->typoutput;
1732                         break;
1733                 case IOFunc_receive:
1734                         *func = typeStruct->typreceive;
1735                         break;
1736                 case IOFunc_send:
1737                         *func = typeStruct->typsend;
1738                         break;
1739         }
1740         ReleaseSysCache(typeTuple);
1741 }
1742
1743 #ifdef NOT_USED
1744 char
1745 get_typalign(Oid typid)
1746 {
1747         HeapTuple       tp;
1748
1749         tp = SearchSysCache(TYPEOID,
1750                                                 ObjectIdGetDatum(typid),
1751                                                 0, 0, 0);
1752         if (HeapTupleIsValid(tp))
1753         {
1754                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1755                 char            result;
1756
1757                 result = typtup->typalign;
1758                 ReleaseSysCache(tp);
1759                 return result;
1760         }
1761         else
1762                 return 'i';
1763 }
1764 #endif
1765
1766 char
1767 get_typstorage(Oid typid)
1768 {
1769         HeapTuple       tp;
1770
1771         tp = SearchSysCache(TYPEOID,
1772                                                 ObjectIdGetDatum(typid),
1773                                                 0, 0, 0);
1774         if (HeapTupleIsValid(tp))
1775         {
1776                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1777                 char            result;
1778
1779                 result = typtup->typstorage;
1780                 ReleaseSysCache(tp);
1781                 return result;
1782         }
1783         else
1784                 return 'p';
1785 }
1786
1787 /*
1788  * get_typdefault
1789  *        Given a type OID, return the type's default value, if any.
1790  *
1791  *        The result is a palloc'd expression node tree, or NULL if there
1792  *        is no defined default for the datatype.
1793  *
1794  * NB: caller should be prepared to coerce result to correct datatype;
1795  * the returned expression tree might produce something of the wrong type.
1796  */
1797 Node *
1798 get_typdefault(Oid typid)
1799 {
1800         HeapTuple       typeTuple;
1801         Form_pg_type type;
1802         Datum           datum;
1803         bool            isNull;
1804         Node       *expr;
1805
1806         typeTuple = SearchSysCache(TYPEOID,
1807                                                            ObjectIdGetDatum(typid),
1808                                                            0, 0, 0);
1809         if (!HeapTupleIsValid(typeTuple))
1810                 elog(ERROR, "cache lookup failed for type %u", typid);
1811         type = (Form_pg_type) GETSTRUCT(typeTuple);
1812
1813         /*
1814          * typdefault and typdefaultbin are potentially null, so don't try to
1815          * access 'em as struct fields. Must do it the hard way with
1816          * SysCacheGetAttr.
1817          */
1818         datum = SysCacheGetAttr(TYPEOID,
1819                                                         typeTuple,
1820                                                         Anum_pg_type_typdefaultbin,
1821                                                         &isNull);
1822
1823         if (!isNull)
1824         {
1825                 /* We have an expression default */
1826                 expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
1827                                                                                                                                 datum)));
1828         }
1829         else
1830         {
1831                 /* Perhaps we have a plain literal default */
1832                 datum = SysCacheGetAttr(TYPEOID,
1833                                                                 typeTuple,
1834                                                                 Anum_pg_type_typdefault,
1835                                                                 &isNull);
1836
1837                 if (!isNull)
1838                 {
1839                         char       *strDefaultVal;
1840
1841                         /* Convert text datum to C string */
1842                         strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
1843                                                                                                                                 datum));
1844                         /* Convert C string to a value of the given type */
1845                         datum = OidInputFunctionCall(type->typinput, strDefaultVal,
1846                                                                                  getTypeIOParam(typeTuple), -1);
1847                         /* Build a Const node containing the value */
1848                         expr = (Node *) makeConst(typid,
1849                                                                           type->typlen,
1850                                                                           datum,
1851                                                                           false,
1852                                                                           type->typbyval);
1853                         pfree(strDefaultVal);
1854                 }
1855                 else
1856                 {
1857                         /* No default */
1858                         expr = NULL;
1859                 }
1860         }
1861
1862         ReleaseSysCache(typeTuple);
1863
1864         return expr;
1865 }
1866
1867 /*
1868  * getBaseType
1869  *              If the given type is a domain, return its base type;
1870  *              otherwise return the type's own OID.
1871  */
1872 Oid
1873 getBaseType(Oid typid)
1874 {
1875         int32           typmod = -1;
1876
1877         return getBaseTypeAndTypmod(typid, &typmod);
1878 }
1879
1880 /*
1881  * getBaseTypeAndTypmod
1882  *              If the given type is a domain, return its base type and typmod;
1883  *              otherwise return the type's own OID, and leave *typmod unchanged.
1884  *
1885  * Note that the "applied typmod" should be -1 for every domain level
1886  * above the bottommost; therefore, if the passed-in typid is indeed
1887  * a domain, *typmod should be -1.
1888  */
1889 Oid
1890 getBaseTypeAndTypmod(Oid typid, int32 *typmod)
1891 {
1892         /*
1893          * We loop to find the bottom base type in a stack of domains.
1894          */
1895         for (;;)
1896         {
1897                 HeapTuple       tup;
1898                 Form_pg_type typTup;
1899
1900                 tup = SearchSysCache(TYPEOID,
1901                                                          ObjectIdGetDatum(typid),
1902                                                          0, 0, 0);
1903                 if (!HeapTupleIsValid(tup))
1904                         elog(ERROR, "cache lookup failed for type %u", typid);
1905                 typTup = (Form_pg_type) GETSTRUCT(tup);
1906                 if (typTup->typtype != 'd')
1907                 {
1908                         /* Not a domain, so done */
1909                         ReleaseSysCache(tup);
1910                         break;
1911                 }
1912
1913                 Assert(*typmod == -1);
1914                 typid = typTup->typbasetype;
1915                 *typmod = typTup->typtypmod;
1916
1917                 ReleaseSysCache(tup);
1918         }
1919
1920         return typid;
1921 }
1922
1923 /*
1924  * get_typavgwidth
1925  *
1926  *        Given a type OID and a typmod value (pass -1 if typmod is unknown),
1927  *        estimate the average width of values of the type.  This is used by
1928  *        the planner, which doesn't require absolutely correct results;
1929  *        it's OK (and expected) to guess if we don't know for sure.
1930  */
1931 int32
1932 get_typavgwidth(Oid typid, int32 typmod)
1933 {
1934         int                     typlen = get_typlen(typid);
1935         int32           maxwidth;
1936
1937         /*
1938          * Easy if it's a fixed-width type
1939          */
1940         if (typlen > 0)
1941                 return typlen;
1942
1943         /*
1944          * type_maximum_size knows the encoding of typmod for some datatypes;
1945          * don't duplicate that knowledge here.
1946          */
1947         maxwidth = type_maximum_size(typid, typmod);
1948         if (maxwidth > 0)
1949         {
1950                 /*
1951                  * For BPCHAR, the max width is also the only width.  Otherwise we
1952                  * need to guess about the typical data width given the max. A sliding
1953                  * scale for percentage of max width seems reasonable.
1954                  */
1955                 if (typid == BPCHAROID)
1956                         return maxwidth;
1957                 if (maxwidth <= 32)
1958                         return maxwidth;        /* assume full width */
1959                 if (maxwidth < 1000)
1960                         return 32 + (maxwidth - 32) / 2;        /* assume 50% */
1961
1962                 /*
1963                  * Beyond 1000, assume we're looking at something like
1964                  * "varchar(10000)" where the limit isn't actually reached often, and
1965                  * use a fixed estimate.
1966                  */
1967                 return 32 + (1000 - 32) / 2;
1968         }
1969
1970         /*
1971          * Ooops, we have no idea ... wild guess time.
1972          */
1973         return 32;
1974 }
1975
1976 /*
1977  * get_typtype
1978  *
1979  *              Given the type OID, find if it is a basic type, a complex type, etc.
1980  *              It returns the null char if the cache lookup fails...
1981  */
1982 char
1983 get_typtype(Oid typid)
1984 {
1985         HeapTuple       tp;
1986
1987         tp = SearchSysCache(TYPEOID,
1988                                                 ObjectIdGetDatum(typid),
1989                                                 0, 0, 0);
1990         if (HeapTupleIsValid(tp))
1991         {
1992                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1993                 char            result;
1994
1995                 result = typtup->typtype;
1996                 ReleaseSysCache(tp);
1997                 return result;
1998         }
1999         else
2000                 return '\0';
2001 }
2002
2003 /*
2004  * type_is_rowtype
2005  *
2006  *              Convenience function to determine whether a type OID represents
2007  *              a "rowtype" type --- either RECORD or a named composite type.
2008  */
2009 bool
2010 type_is_rowtype(Oid typid)
2011 {
2012         return (typid == RECORDOID || get_typtype(typid) == 'c');
2013 }
2014
2015 /*
2016  * get_typ_typrelid
2017  *
2018  *              Given the type OID, get the typrelid (InvalidOid if not a complex
2019  *              type).
2020  */
2021 Oid
2022 get_typ_typrelid(Oid typid)
2023 {
2024         HeapTuple       tp;
2025
2026         tp = SearchSysCache(TYPEOID,
2027                                                 ObjectIdGetDatum(typid),
2028                                                 0, 0, 0);
2029         if (HeapTupleIsValid(tp))
2030         {
2031                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2032                 Oid                     result;
2033
2034                 result = typtup->typrelid;
2035                 ReleaseSysCache(tp);
2036                 return result;
2037         }
2038         else
2039                 return InvalidOid;
2040 }
2041
2042 /*
2043  * get_element_type
2044  *
2045  *              Given the type OID, get the typelem (InvalidOid if not an array type).
2046  *
2047  * NB: this only considers varlena arrays to be true arrays; InvalidOid is
2048  * returned if the input is a fixed-length array type.
2049  */
2050 Oid
2051 get_element_type(Oid typid)
2052 {
2053         HeapTuple       tp;
2054
2055         tp = SearchSysCache(TYPEOID,
2056                                                 ObjectIdGetDatum(typid),
2057                                                 0, 0, 0);
2058         if (HeapTupleIsValid(tp))
2059         {
2060                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2061                 Oid                     result;
2062
2063                 if (typtup->typlen == -1)
2064                         result = typtup->typelem;
2065                 else
2066                         result = InvalidOid;
2067                 ReleaseSysCache(tp);
2068                 return result;
2069         }
2070         else
2071                 return InvalidOid;
2072 }
2073
2074 /*
2075  * get_array_type
2076  *
2077  *              Given the type OID, get the corresponding array type.
2078  *              Returns InvalidOid if no array type can be found.
2079  *
2080  * NB: this only considers varlena arrays to be true arrays.
2081  */
2082 Oid
2083 get_array_type(Oid typid)
2084 {
2085         HeapTuple       tp;
2086
2087         tp = SearchSysCache(TYPEOID,
2088                                                 ObjectIdGetDatum(typid),
2089                                                 0, 0, 0);
2090         if (HeapTupleIsValid(tp))
2091         {
2092                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2093                 char       *array_typename;
2094                 Oid                     namespaceId;
2095
2096                 array_typename = makeArrayTypeName(NameStr(typtup->typname));
2097                 namespaceId = typtup->typnamespace;
2098                 ReleaseSysCache(tp);
2099
2100                 tp = SearchSysCache(TYPENAMENSP,
2101                                                         PointerGetDatum(array_typename),
2102                                                         ObjectIdGetDatum(namespaceId),
2103                                                         0, 0);
2104
2105                 pfree(array_typename);
2106
2107                 if (HeapTupleIsValid(tp))
2108                 {
2109                         Oid                     result;
2110
2111                         typtup = (Form_pg_type) GETSTRUCT(tp);
2112                         if (typtup->typlen == -1 && typtup->typelem == typid)
2113                                 result = HeapTupleGetOid(tp);
2114                         else
2115                                 result = InvalidOid;
2116                         ReleaseSysCache(tp);
2117                         return result;
2118                 }
2119         }
2120         return InvalidOid;
2121 }
2122
2123 /*
2124  * getTypeInputInfo
2125  *
2126  *              Get info needed for converting values of a type to internal form
2127  */
2128 void
2129 getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
2130 {
2131         HeapTuple       typeTuple;
2132         Form_pg_type pt;
2133
2134         typeTuple = SearchSysCache(TYPEOID,
2135                                                            ObjectIdGetDatum(type),
2136                                                            0, 0, 0);
2137         if (!HeapTupleIsValid(typeTuple))
2138                 elog(ERROR, "cache lookup failed for type %u", type);
2139         pt = (Form_pg_type) GETSTRUCT(typeTuple);
2140
2141         if (!pt->typisdefined)
2142                 ereport(ERROR,
2143                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2144                                  errmsg("type %s is only a shell",
2145                                                 format_type_be(type))));
2146         if (!OidIsValid(pt->typinput))
2147                 ereport(ERROR,
2148                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2149                                  errmsg("no input function available for type %s",
2150                                                 format_type_be(type))));
2151
2152         *typInput = pt->typinput;
2153         *typIOParam = getTypeIOParam(typeTuple);
2154
2155         ReleaseSysCache(typeTuple);
2156 }
2157
2158 /*
2159  * getTypeOutputInfo
2160  *
2161  *              Get info needed for printing values of a type
2162  */
2163 void
2164 getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
2165 {
2166         HeapTuple       typeTuple;
2167         Form_pg_type pt;
2168
2169         typeTuple = SearchSysCache(TYPEOID,
2170                                                            ObjectIdGetDatum(type),
2171                                                            0, 0, 0);
2172         if (!HeapTupleIsValid(typeTuple))
2173                 elog(ERROR, "cache lookup failed for type %u", type);
2174         pt = (Form_pg_type) GETSTRUCT(typeTuple);
2175
2176         if (!pt->typisdefined)
2177                 ereport(ERROR,
2178                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2179                                  errmsg("type %s is only a shell",
2180                                                 format_type_be(type))));
2181         if (!OidIsValid(pt->typoutput))
2182                 ereport(ERROR,
2183                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2184                                  errmsg("no output function available for type %s",
2185                                                 format_type_be(type))));
2186
2187         *typOutput = pt->typoutput;
2188         *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
2189
2190         ReleaseSysCache(typeTuple);
2191 }
2192
2193 /*
2194  * getTypeBinaryInputInfo
2195  *
2196  *              Get info needed for binary input of values of a type
2197  */
2198 void
2199 getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
2200 {
2201         HeapTuple       typeTuple;
2202         Form_pg_type pt;
2203
2204         typeTuple = SearchSysCache(TYPEOID,
2205                                                            ObjectIdGetDatum(type),
2206                                                            0, 0, 0);
2207         if (!HeapTupleIsValid(typeTuple))
2208                 elog(ERROR, "cache lookup failed for type %u", type);
2209         pt = (Form_pg_type) GETSTRUCT(typeTuple);
2210
2211         if (!pt->typisdefined)
2212                 ereport(ERROR,
2213                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2214                                  errmsg("type %s is only a shell",
2215                                                 format_type_be(type))));
2216         if (!OidIsValid(pt->typreceive))
2217                 ereport(ERROR,
2218                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2219                                  errmsg("no binary input function available for type %s",
2220                                                 format_type_be(type))));
2221
2222         *typReceive = pt->typreceive;
2223         *typIOParam = getTypeIOParam(typeTuple);
2224
2225         ReleaseSysCache(typeTuple);
2226 }
2227
2228 /*
2229  * getTypeBinaryOutputInfo
2230  *
2231  *              Get info needed for binary output of values of a type
2232  */
2233 void
2234 getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
2235 {
2236         HeapTuple       typeTuple;
2237         Form_pg_type pt;
2238
2239         typeTuple = SearchSysCache(TYPEOID,
2240                                                            ObjectIdGetDatum(type),
2241                                                            0, 0, 0);
2242         if (!HeapTupleIsValid(typeTuple))
2243                 elog(ERROR, "cache lookup failed for type %u", type);
2244         pt = (Form_pg_type) GETSTRUCT(typeTuple);
2245
2246         if (!pt->typisdefined)
2247                 ereport(ERROR,
2248                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2249                                  errmsg("type %s is only a shell",
2250                                                 format_type_be(type))));
2251         if (!OidIsValid(pt->typsend))
2252                 ereport(ERROR,
2253                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2254                                  errmsg("no binary output function available for type %s",
2255                                                 format_type_be(type))));
2256
2257         *typSend = pt->typsend;
2258         *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
2259
2260         ReleaseSysCache(typeTuple);
2261 }
2262
2263 /*
2264  * get_typmodin
2265  *
2266  *              Given the type OID, return the type's typmodin procedure, if any.
2267  */
2268 Oid
2269 get_typmodin(Oid typid)
2270 {
2271         HeapTuple       tp;
2272
2273         tp = SearchSysCache(TYPEOID,
2274                                                 ObjectIdGetDatum(typid),
2275                                                 0, 0, 0);
2276         if (HeapTupleIsValid(tp))
2277         {
2278                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2279                 Oid                     result;
2280
2281                 result = typtup->typmodin;
2282                 ReleaseSysCache(tp);
2283                 return result;
2284         }
2285         else
2286                 return InvalidOid;
2287 }
2288
2289 #ifdef NOT_USED
2290 /*
2291  * get_typmodout
2292  *
2293  *              Given the type OID, return the type's typmodout procedure, if any.
2294  */
2295 Oid
2296 get_typmodout(Oid typid)
2297 {
2298         HeapTuple       tp;
2299
2300         tp = SearchSysCache(TYPEOID,
2301                                                 ObjectIdGetDatum(typid),
2302                                                 0, 0, 0);
2303         if (HeapTupleIsValid(tp))
2304         {
2305                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2306                 Oid                     result;
2307
2308                 result = typtup->typmodout;
2309                 ReleaseSysCache(tp);
2310                 return result;
2311         }
2312         else
2313                 return InvalidOid;
2314 }
2315 #endif /* NOT_USED */
2316
2317
2318 /*                              ---------- STATISTICS CACHE ----------                                   */
2319
2320 /*
2321  * get_attavgwidth
2322  *
2323  *        Given the table and attribute number of a column, get the average
2324  *        width of entries in the column.  Return zero if no data available.
2325  */
2326 int32
2327 get_attavgwidth(Oid relid, AttrNumber attnum)
2328 {
2329         HeapTuple       tp;
2330
2331         tp = SearchSysCache(STATRELATT,
2332                                                 ObjectIdGetDatum(relid),
2333                                                 Int16GetDatum(attnum),
2334                                                 0, 0);
2335         if (HeapTupleIsValid(tp))
2336         {
2337                 int32           stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
2338
2339                 ReleaseSysCache(tp);
2340                 if (stawidth > 0)
2341                         return stawidth;
2342         }
2343         return 0;
2344 }
2345
2346 /*
2347  * get_attstatsslot
2348  *
2349  *              Extract the contents of a "slot" of a pg_statistic tuple.
2350  *              Returns TRUE if requested slot type was found, else FALSE.
2351  *
2352  * Unlike other routines in this file, this takes a pointer to an
2353  * already-looked-up tuple in the pg_statistic cache.  We do this since
2354  * most callers will want to extract more than one value from the cache
2355  * entry, and we don't want to repeat the cache lookup unnecessarily.
2356  *
2357  * statstuple: pg_statistics tuple to be examined.
2358  * atttype: type OID of attribute (can be InvalidOid if values == NULL).
2359  * atttypmod: typmod of attribute (can be 0 if values == NULL).
2360  * reqkind: STAKIND code for desired statistics slot kind.
2361  * reqop: STAOP value wanted, or InvalidOid if don't care.
2362  * values, nvalues: if not NULL, the slot's stavalues are extracted.
2363  * numbers, nnumbers: if not NULL, the slot's stanumbers are extracted.
2364  *
2365  * If assigned, values and numbers are set to point to palloc'd arrays.
2366  * If the attribute type is pass-by-reference, the values referenced by
2367  * the values array are themselves palloc'd.  The palloc'd stuff can be
2368  * freed by calling free_attstatsslot.
2369  */
2370 bool
2371 get_attstatsslot(HeapTuple statstuple,
2372                                  Oid atttype, int32 atttypmod,
2373                                  int reqkind, Oid reqop,
2374                                  Datum **values, int *nvalues,
2375                                  float4 **numbers, int *nnumbers)
2376 {
2377         Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
2378         int                     i,
2379                                 j;
2380         Datum           val;
2381         bool            isnull;
2382         ArrayType  *statarray;
2383         int                     narrayelem;
2384         HeapTuple       typeTuple;
2385         Form_pg_type typeForm;
2386
2387         for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
2388         {
2389                 if ((&stats->stakind1)[i] == reqkind &&
2390                         (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
2391                         break;
2392         }
2393         if (i >= STATISTIC_NUM_SLOTS)
2394                 return false;                   /* not there */
2395
2396         if (values)
2397         {
2398                 val = SysCacheGetAttr(STATRELATT, statstuple,
2399                                                           Anum_pg_statistic_stavalues1 + i,
2400                                                           &isnull);
2401                 if (isnull)
2402                         elog(ERROR, "stavalues is null");
2403                 statarray = DatumGetArrayTypeP(val);
2404
2405                 /* Need to get info about the array element type */
2406                 typeTuple = SearchSysCache(TYPEOID,
2407                                                                    ObjectIdGetDatum(atttype),
2408                                                                    0, 0, 0);
2409                 if (!HeapTupleIsValid(typeTuple))
2410                         elog(ERROR, "cache lookup failed for type %u", atttype);
2411                 typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
2412
2413                 /* Deconstruct array into Datum elements; NULLs not expected */
2414                 deconstruct_array(statarray,
2415                                                   atttype,
2416                                                   typeForm->typlen,
2417                                                   typeForm->typbyval,
2418                                                   typeForm->typalign,
2419                                                   values, NULL, nvalues);
2420
2421                 /*
2422                  * If the element type is pass-by-reference, we now have a bunch of
2423                  * Datums that are pointers into the syscache value.  Copy them to
2424                  * avoid problems if syscache decides to drop the entry.
2425                  */
2426                 if (!typeForm->typbyval)
2427                 {
2428                         for (j = 0; j < *nvalues; j++)
2429                         {
2430                                 (*values)[j] = datumCopy((*values)[j],
2431                                                                                  typeForm->typbyval,
2432                                                                                  typeForm->typlen);
2433                         }
2434                 }
2435
2436                 ReleaseSysCache(typeTuple);
2437
2438                 /*
2439                  * Free statarray if it's a detoasted copy.
2440                  */
2441                 if ((Pointer) statarray != DatumGetPointer(val))
2442                         pfree(statarray);
2443         }
2444
2445         if (numbers)
2446         {
2447                 val = SysCacheGetAttr(STATRELATT, statstuple,
2448                                                           Anum_pg_statistic_stanumbers1 + i,
2449                                                           &isnull);
2450                 if (isnull)
2451                         elog(ERROR, "stanumbers is null");
2452                 statarray = DatumGetArrayTypeP(val);
2453
2454                 /*
2455                  * We expect the array to be a 1-D float4 array; verify that. We don't
2456                  * need to use deconstruct_array() since the array data is just going
2457                  * to look like a C array of float4 values.
2458                  */
2459                 narrayelem = ARR_DIMS(statarray)[0];
2460                 if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
2461                         ARR_HASNULL(statarray) ||
2462                         ARR_ELEMTYPE(statarray) != FLOAT4OID)
2463                         elog(ERROR, "stanumbers is not a 1-D float4 array");
2464                 *numbers = (float4 *) palloc(narrayelem * sizeof(float4));
2465                 memcpy(*numbers, ARR_DATA_PTR(statarray), narrayelem * sizeof(float4));
2466                 *nnumbers = narrayelem;
2467
2468                 /*
2469                  * Free statarray if it's a detoasted copy.
2470                  */
2471                 if ((Pointer) statarray != DatumGetPointer(val))
2472                         pfree(statarray);
2473         }
2474
2475         return true;
2476 }
2477
2478 /*
2479  * free_attstatsslot
2480  *              Free data allocated by get_attstatsslot
2481  *
2482  * atttype need be valid only if values != NULL.
2483  */
2484 void
2485 free_attstatsslot(Oid atttype,
2486                                   Datum *values, int nvalues,
2487                                   float4 *numbers, int nnumbers)
2488 {
2489         if (values)
2490         {
2491                 if (!get_typbyval(atttype))
2492                 {
2493                         int                     i;
2494
2495                         for (i = 0; i < nvalues; i++)
2496                                 pfree(DatumGetPointer(values[i]));
2497                 }
2498                 pfree(values);
2499         }
2500         if (numbers)
2501                 pfree(numbers);
2502 }
2503
2504 /*                              ---------- PG_NAMESPACE CACHE ----------                                 */
2505
2506 /*
2507  * get_namespace_name
2508  *              Returns the name of a given namespace
2509  *
2510  * Returns a palloc'd copy of the string, or NULL if no such namespace.
2511  */
2512 char *
2513 get_namespace_name(Oid nspid)
2514 {
2515         HeapTuple       tp;
2516
2517         tp = SearchSysCache(NAMESPACEOID,
2518                                                 ObjectIdGetDatum(nspid),
2519                                                 0, 0, 0);
2520         if (HeapTupleIsValid(tp))
2521         {
2522                 Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
2523                 char       *result;
2524
2525                 result = pstrdup(NameStr(nsptup->nspname));
2526                 ReleaseSysCache(tp);
2527                 return result;
2528         }
2529         else
2530                 return NULL;
2531 }
2532
2533 /*                              ---------- PG_AUTHID CACHE ----------                                    */
2534
2535 /*
2536  * get_roleid
2537  *        Given a role name, look up the role's OID.
2538  *        Returns InvalidOid if no such role.
2539  */
2540 Oid
2541 get_roleid(const char *rolname)
2542 {
2543         return GetSysCacheOid(AUTHNAME,
2544                                                   PointerGetDatum(rolname),
2545                                                   0, 0, 0);
2546 }
2547
2548 /*
2549  * get_roleid_checked
2550  *        Given a role name, look up the role's OID.
2551  *        ereports if no such role.
2552  */
2553 Oid
2554 get_roleid_checked(const char *rolname)
2555 {
2556         Oid                     roleid;
2557
2558         roleid = get_roleid(rolname);
2559         if (!OidIsValid(roleid))
2560                 ereport(ERROR,
2561                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2562                                  errmsg("role \"%s\" does not exist", rolname)));
2563         return roleid;
2564 }