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