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