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