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