]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/lsyscache.c
877e50d8737de664cb289238cf60651cd84fbfa3
[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_atttypetypmodcoll
908  *
909  *              A three-fer: given the relation id and the attribute number,
910  *              fetch atttypid, atttypmod, and attcollation in a single cache lookup.
911  *
912  * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
913  * raises an error if it can't obtain the information.
914  */
915 void
916 get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
917                                           Oid *typid, int32 *typmod, Oid *collid)
918 {
919         HeapTuple       tp;
920         Form_pg_attribute att_tup;
921
922         tp = SearchSysCache2(ATTNUM,
923                                                  ObjectIdGetDatum(relid),
924                                                  Int16GetDatum(attnum));
925         if (!HeapTupleIsValid(tp))
926                 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
927                          attnum, relid);
928         att_tup = (Form_pg_attribute) GETSTRUCT(tp);
929
930         *typid = att_tup->atttypid;
931         *typmod = att_tup->atttypmod;
932         *collid = att_tup->attcollation;
933         ReleaseSysCache(tp);
934 }
935
936 /*                              ---------- COLLATION CACHE ----------                                    */
937
938 /*
939  * get_collation_name
940  *              Returns the name of a given pg_collation entry.
941  *
942  * Returns a palloc'd copy of the string, or NULL if no such constraint.
943  *
944  * NOTE: since collation name is not unique, be wary of code that uses this
945  * for anything except preparing error messages.
946  */
947 char *
948 get_collation_name(Oid colloid)
949 {
950         HeapTuple       tp;
951
952         tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
953         if (HeapTupleIsValid(tp))
954         {
955                 Form_pg_collation colltup = (Form_pg_collation) GETSTRUCT(tp);
956                 char       *result;
957
958                 result = pstrdup(NameStr(colltup->collname));
959                 ReleaseSysCache(tp);
960                 return result;
961         }
962         else
963                 return NULL;
964 }
965
966 /*                              ---------- CONSTRAINT CACHE ----------                                   */
967
968 /*
969  * get_constraint_name
970  *              Returns the name of a given pg_constraint entry.
971  *
972  * Returns a palloc'd copy of the string, or NULL if no such constraint.
973  *
974  * NOTE: since constraint name is not unique, be wary of code that uses this
975  * for anything except preparing error messages.
976  */
977 char *
978 get_constraint_name(Oid conoid)
979 {
980         HeapTuple       tp;
981
982         tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
983         if (HeapTupleIsValid(tp))
984         {
985                 Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
986                 char       *result;
987
988                 result = pstrdup(NameStr(contup->conname));
989                 ReleaseSysCache(tp);
990                 return result;
991         }
992         else
993                 return NULL;
994 }
995
996 /*                              ---------- OPCLASS CACHE ----------                                              */
997
998 /*
999  * get_opclass_family
1000  *
1001  *              Returns the OID of the operator family the opclass belongs to.
1002  */
1003 Oid
1004 get_opclass_family(Oid opclass)
1005 {
1006         HeapTuple       tp;
1007         Form_pg_opclass cla_tup;
1008         Oid                     result;
1009
1010         tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
1011         if (!HeapTupleIsValid(tp))
1012                 elog(ERROR, "cache lookup failed for opclass %u", opclass);
1013         cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1014
1015         result = cla_tup->opcfamily;
1016         ReleaseSysCache(tp);
1017         return result;
1018 }
1019
1020 /*
1021  * get_opclass_input_type
1022  *
1023  *              Returns the OID of the datatype the opclass indexes.
1024  */
1025 Oid
1026 get_opclass_input_type(Oid opclass)
1027 {
1028         HeapTuple       tp;
1029         Form_pg_opclass cla_tup;
1030         Oid                     result;
1031
1032         tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
1033         if (!HeapTupleIsValid(tp))
1034                 elog(ERROR, "cache lookup failed for opclass %u", opclass);
1035         cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1036
1037         result = cla_tup->opcintype;
1038         ReleaseSysCache(tp);
1039         return result;
1040 }
1041
1042 /*                              ---------- OPERATOR CACHE ----------                                     */
1043
1044 /*
1045  * get_opcode
1046  *
1047  *              Returns the regproc id of the routine used to implement an
1048  *              operator given the operator oid.
1049  */
1050 RegProcedure
1051 get_opcode(Oid opno)
1052 {
1053         HeapTuple       tp;
1054
1055         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1056         if (HeapTupleIsValid(tp))
1057         {
1058                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1059                 RegProcedure result;
1060
1061                 result = optup->oprcode;
1062                 ReleaseSysCache(tp);
1063                 return result;
1064         }
1065         else
1066                 return (RegProcedure) InvalidOid;
1067 }
1068
1069 /*
1070  * get_opname
1071  *        returns the name of the operator with the given opno
1072  *
1073  * Note: returns a palloc'd copy of the string, or NULL if no such operator.
1074  */
1075 char *
1076 get_opname(Oid opno)
1077 {
1078         HeapTuple       tp;
1079
1080         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1081         if (HeapTupleIsValid(tp))
1082         {
1083                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1084                 char       *result;
1085
1086                 result = pstrdup(NameStr(optup->oprname));
1087                 ReleaseSysCache(tp);
1088                 return result;
1089         }
1090         else
1091                 return NULL;
1092 }
1093
1094 /*
1095  * op_input_types
1096  *
1097  *              Returns the left and right input datatypes for an operator
1098  *              (InvalidOid if not relevant).
1099  */
1100 void
1101 op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
1102 {
1103         HeapTuple       tp;
1104         Form_pg_operator optup;
1105
1106         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1107         if (!HeapTupleIsValid(tp))      /* shouldn't happen */
1108                 elog(ERROR, "cache lookup failed for operator %u", opno);
1109         optup = (Form_pg_operator) GETSTRUCT(tp);
1110         *lefttype = optup->oprleft;
1111         *righttype = optup->oprright;
1112         ReleaseSysCache(tp);
1113 }
1114
1115 /*
1116  * op_mergejoinable
1117  *
1118  * Returns true if the operator is potentially mergejoinable.  (The planner
1119  * will fail to find any mergejoin plans unless there are suitable btree
1120  * opfamily entries for this operator and associated sortops.  The pg_operator
1121  * flag is just a hint to tell the planner whether to bother looking.)
1122  *
1123  * In some cases (currently only array_eq), mergejoinability depends on the
1124  * specific input data type the operator is invoked for, so that must be
1125  * passed as well.  We currently assume that only one input's type is needed
1126  * to check this --- by convention, pass the left input's data type.
1127  */
1128 bool
1129 op_mergejoinable(Oid opno, Oid inputtype)
1130 {
1131         HeapTuple       tp;
1132         bool            result = false;
1133
1134         if (opno == ARRAY_EQ_OP)
1135         {
1136                 /*
1137                  * For array_eq, can sort if element type has a default btree opclass.
1138                  * We could use GetDefaultOpClass, but that's fairly expensive and not
1139                  * cached, so let's use the typcache instead.
1140                  */
1141                 Oid                     elem_type = get_base_element_type(inputtype);
1142
1143                 if (OidIsValid(elem_type))
1144                 {
1145                         TypeCacheEntry *typentry;
1146
1147                         typentry = lookup_type_cache(elem_type, TYPECACHE_BTREE_OPFAMILY);
1148                         if (OidIsValid(typentry->btree_opf))
1149                                 result = true;
1150                 }
1151         }
1152         else
1153         {
1154                 /* For all other operators, rely on pg_operator.oprcanmerge */
1155                 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1156                 if (HeapTupleIsValid(tp))
1157                 {
1158                         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1159
1160                         result = optup->oprcanmerge;
1161                         ReleaseSysCache(tp);
1162                 }
1163         }
1164         return result;
1165 }
1166
1167 /*
1168  * op_hashjoinable
1169  *
1170  * Returns true if the operator is hashjoinable.  (There must be a suitable
1171  * hash opfamily entry for this operator if it is so marked.)
1172  *
1173  * In some cases (currently only array_eq), hashjoinability depends on the
1174  * specific input data type the operator is invoked for, so that must be
1175  * passed as well.  We currently assume that only one input's type is needed
1176  * to check this --- by convention, pass the left input's data type.
1177  */
1178 bool
1179 op_hashjoinable(Oid opno, Oid inputtype)
1180 {
1181         HeapTuple       tp;
1182         bool            result = false;
1183
1184         if (opno == ARRAY_EQ_OP)
1185         {
1186                 /* For array_eq, can hash if element type has a default hash opclass */
1187                 Oid                     elem_type = get_base_element_type(inputtype);
1188
1189                 if (OidIsValid(elem_type))
1190                 {
1191                         TypeCacheEntry *typentry;
1192
1193                         typentry = lookup_type_cache(elem_type, TYPECACHE_HASH_OPFAMILY);
1194                         if (OidIsValid(typentry->hash_opf))
1195                                 result = true;
1196                 }
1197         }
1198         else
1199         {
1200                 /* For all other operators, rely on pg_operator.oprcanhash */
1201                 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1202                 if (HeapTupleIsValid(tp))
1203                 {
1204                         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1205
1206                         result = optup->oprcanhash;
1207                         ReleaseSysCache(tp);
1208                 }
1209         }
1210         return result;
1211 }
1212
1213 /*
1214  * op_strict
1215  *
1216  * Get the proisstrict flag for the operator's underlying function.
1217  */
1218 bool
1219 op_strict(Oid opno)
1220 {
1221         RegProcedure funcid = get_opcode(opno);
1222
1223         if (funcid == (RegProcedure) InvalidOid)
1224                 elog(ERROR, "operator %u does not exist", opno);
1225
1226         return func_strict((Oid) funcid);
1227 }
1228
1229 /*
1230  * op_volatile
1231  *
1232  * Get the provolatile flag for the operator's underlying function.
1233  */
1234 char
1235 op_volatile(Oid opno)
1236 {
1237         RegProcedure funcid = get_opcode(opno);
1238
1239         if (funcid == (RegProcedure) InvalidOid)
1240                 elog(ERROR, "operator %u does not exist", opno);
1241
1242         return func_volatile((Oid) funcid);
1243 }
1244
1245 /*
1246  * get_commutator
1247  *
1248  *              Returns the corresponding commutator of an operator.
1249  */
1250 Oid
1251 get_commutator(Oid opno)
1252 {
1253         HeapTuple       tp;
1254
1255         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1256         if (HeapTupleIsValid(tp))
1257         {
1258                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1259                 Oid                     result;
1260
1261                 result = optup->oprcom;
1262                 ReleaseSysCache(tp);
1263                 return result;
1264         }
1265         else
1266                 return InvalidOid;
1267 }
1268
1269 /*
1270  * get_negator
1271  *
1272  *              Returns the corresponding negator of an operator.
1273  */
1274 Oid
1275 get_negator(Oid opno)
1276 {
1277         HeapTuple       tp;
1278
1279         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1280         if (HeapTupleIsValid(tp))
1281         {
1282                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1283                 Oid                     result;
1284
1285                 result = optup->oprnegate;
1286                 ReleaseSysCache(tp);
1287                 return result;
1288         }
1289         else
1290                 return InvalidOid;
1291 }
1292
1293 /*
1294  * get_oprrest
1295  *
1296  *              Returns procedure id for computing selectivity of an operator.
1297  */
1298 RegProcedure
1299 get_oprrest(Oid opno)
1300 {
1301         HeapTuple       tp;
1302
1303         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1304         if (HeapTupleIsValid(tp))
1305         {
1306                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1307                 RegProcedure result;
1308
1309                 result = optup->oprrest;
1310                 ReleaseSysCache(tp);
1311                 return result;
1312         }
1313         else
1314                 return (RegProcedure) InvalidOid;
1315 }
1316
1317 /*
1318  * get_oprjoin
1319  *
1320  *              Returns procedure id for computing selectivity of a join.
1321  */
1322 RegProcedure
1323 get_oprjoin(Oid opno)
1324 {
1325         HeapTuple       tp;
1326
1327         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1328         if (HeapTupleIsValid(tp))
1329         {
1330                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1331                 RegProcedure result;
1332
1333                 result = optup->oprjoin;
1334                 ReleaseSysCache(tp);
1335                 return result;
1336         }
1337         else
1338                 return (RegProcedure) InvalidOid;
1339 }
1340
1341 /*                              ---------- FUNCTION CACHE ----------                                     */
1342
1343 /*
1344  * get_func_name
1345  *        returns the name of the function with the given funcid
1346  *
1347  * Note: returns a palloc'd copy of the string, or NULL if no such function.
1348  */
1349 char *
1350 get_func_name(Oid funcid)
1351 {
1352         HeapTuple       tp;
1353
1354         tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1355         if (HeapTupleIsValid(tp))
1356         {
1357                 Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
1358                 char       *result;
1359
1360                 result = pstrdup(NameStr(functup->proname));
1361                 ReleaseSysCache(tp);
1362                 return result;
1363         }
1364         else
1365                 return NULL;
1366 }
1367
1368 /*
1369  * get_func_namespace
1370  *
1371  *              Returns the pg_namespace OID associated with a given function.
1372  */
1373 Oid
1374 get_func_namespace(Oid funcid)
1375 {
1376         HeapTuple       tp;
1377
1378         tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1379         if (HeapTupleIsValid(tp))
1380         {
1381                 Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
1382                 Oid                     result;
1383
1384                 result = functup->pronamespace;
1385                 ReleaseSysCache(tp);
1386                 return result;
1387         }
1388         else
1389                 return InvalidOid;
1390 }
1391
1392 /*
1393  * get_func_rettype
1394  *              Given procedure id, return the function's result type.
1395  */
1396 Oid
1397 get_func_rettype(Oid funcid)
1398 {
1399         HeapTuple       tp;
1400         Oid                     result;
1401
1402         tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1403         if (!HeapTupleIsValid(tp))
1404                 elog(ERROR, "cache lookup failed for function %u", funcid);
1405
1406         result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
1407         ReleaseSysCache(tp);
1408         return result;
1409 }
1410
1411 /*
1412  * get_func_nargs
1413  *              Given procedure id, return the number of arguments.
1414  */
1415 int
1416 get_func_nargs(Oid funcid)
1417 {
1418         HeapTuple       tp;
1419         int                     result;
1420
1421         tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1422         if (!HeapTupleIsValid(tp))
1423                 elog(ERROR, "cache lookup failed for function %u", funcid);
1424
1425         result = ((Form_pg_proc) GETSTRUCT(tp))->pronargs;
1426         ReleaseSysCache(tp);
1427         return result;
1428 }
1429
1430 /*
1431  * get_func_signature
1432  *              Given procedure id, return the function's argument and result types.
1433  *              (The return value is the result type.)
1434  *
1435  * The arguments are returned as a palloc'd array.
1436  */
1437 Oid
1438 get_func_signature(Oid funcid, Oid **argtypes, int *nargs)
1439 {
1440         HeapTuple       tp;
1441         Form_pg_proc procstruct;
1442         Oid                     result;
1443
1444         tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1445         if (!HeapTupleIsValid(tp))
1446                 elog(ERROR, "cache lookup failed for function %u", funcid);
1447
1448         procstruct = (Form_pg_proc) GETSTRUCT(tp);
1449
1450         result = procstruct->prorettype;
1451         *nargs = (int) procstruct->pronargs;
1452         Assert(*nargs == procstruct->proargtypes.dim1);
1453         *argtypes = (Oid *) palloc(*nargs * sizeof(Oid));
1454         memcpy(*argtypes, procstruct->proargtypes.values, *nargs * sizeof(Oid));
1455
1456         ReleaseSysCache(tp);
1457         return result;
1458 }
1459
1460 /*
1461  * get_func_retset
1462  *              Given procedure id, return the function's proretset flag.
1463  */
1464 bool
1465 get_func_retset(Oid funcid)
1466 {
1467         HeapTuple       tp;
1468         bool            result;
1469
1470         tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1471         if (!HeapTupleIsValid(tp))
1472                 elog(ERROR, "cache lookup failed for function %u", funcid);
1473
1474         result = ((Form_pg_proc) GETSTRUCT(tp))->proretset;
1475         ReleaseSysCache(tp);
1476         return result;
1477 }
1478
1479 /*
1480  * func_strict
1481  *              Given procedure id, return the function's proisstrict flag.
1482  */
1483 bool
1484 func_strict(Oid funcid)
1485 {
1486         HeapTuple       tp;
1487         bool            result;
1488
1489         tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1490         if (!HeapTupleIsValid(tp))
1491                 elog(ERROR, "cache lookup failed for function %u", funcid);
1492
1493         result = ((Form_pg_proc) GETSTRUCT(tp))->proisstrict;
1494         ReleaseSysCache(tp);
1495         return result;
1496 }
1497
1498 /*
1499  * func_volatile
1500  *              Given procedure id, return the function's provolatile flag.
1501  */
1502 char
1503 func_volatile(Oid funcid)
1504 {
1505         HeapTuple       tp;
1506         char            result;
1507
1508         tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1509         if (!HeapTupleIsValid(tp))
1510                 elog(ERROR, "cache lookup failed for function %u", funcid);
1511
1512         result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
1513         ReleaseSysCache(tp);
1514         return result;
1515 }
1516
1517 /*
1518  * get_func_cost
1519  *              Given procedure id, return the function's procost field.
1520  */
1521 float4
1522 get_func_cost(Oid funcid)
1523 {
1524         HeapTuple       tp;
1525         float4          result;
1526
1527         tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1528         if (!HeapTupleIsValid(tp))
1529                 elog(ERROR, "cache lookup failed for function %u", funcid);
1530
1531         result = ((Form_pg_proc) GETSTRUCT(tp))->procost;
1532         ReleaseSysCache(tp);
1533         return result;
1534 }
1535
1536 /*
1537  * get_func_rows
1538  *              Given procedure id, return the function's prorows field.
1539  */
1540 float4
1541 get_func_rows(Oid funcid)
1542 {
1543         HeapTuple       tp;
1544         float4          result;
1545
1546         tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1547         if (!HeapTupleIsValid(tp))
1548                 elog(ERROR, "cache lookup failed for function %u", funcid);
1549
1550         result = ((Form_pg_proc) GETSTRUCT(tp))->prorows;
1551         ReleaseSysCache(tp);
1552         return result;
1553 }
1554
1555 /*                              ---------- RELATION CACHE ----------                                     */
1556
1557 /*
1558  * get_relname_relid
1559  *              Given name and namespace of a relation, look up the OID.
1560  *
1561  * Returns InvalidOid if there is no such relation.
1562  */
1563 Oid
1564 get_relname_relid(const char *relname, Oid relnamespace)
1565 {
1566         return GetSysCacheOid2(RELNAMENSP,
1567                                                    PointerGetDatum(relname),
1568                                                    ObjectIdGetDatum(relnamespace));
1569 }
1570
1571 #ifdef NOT_USED
1572 /*
1573  * get_relnatts
1574  *
1575  *              Returns the number of attributes for a given relation.
1576  */
1577 int
1578 get_relnatts(Oid relid)
1579 {
1580         HeapTuple       tp;
1581
1582         tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1583         if (HeapTupleIsValid(tp))
1584         {
1585                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1586                 int                     result;
1587
1588                 result = reltup->relnatts;
1589                 ReleaseSysCache(tp);
1590                 return result;
1591         }
1592         else
1593                 return InvalidAttrNumber;
1594 }
1595 #endif
1596
1597 /*
1598  * get_rel_name
1599  *              Returns the name of a given relation.
1600  *
1601  * Returns a palloc'd copy of the string, or NULL if no such relation.
1602  *
1603  * NOTE: since relation name is not unique, be wary of code that uses this
1604  * for anything except preparing error messages.
1605  */
1606 char *
1607 get_rel_name(Oid relid)
1608 {
1609         HeapTuple       tp;
1610
1611         tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1612         if (HeapTupleIsValid(tp))
1613         {
1614                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1615                 char       *result;
1616
1617                 result = pstrdup(NameStr(reltup->relname));
1618                 ReleaseSysCache(tp);
1619                 return result;
1620         }
1621         else
1622                 return NULL;
1623 }
1624
1625 /*
1626  * get_rel_namespace
1627  *
1628  *              Returns the pg_namespace OID associated with a given relation.
1629  */
1630 Oid
1631 get_rel_namespace(Oid relid)
1632 {
1633         HeapTuple       tp;
1634
1635         tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1636         if (HeapTupleIsValid(tp))
1637         {
1638                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1639                 Oid                     result;
1640
1641                 result = reltup->relnamespace;
1642                 ReleaseSysCache(tp);
1643                 return result;
1644         }
1645         else
1646                 return InvalidOid;
1647 }
1648
1649 /*
1650  * get_rel_type_id
1651  *
1652  *              Returns the pg_type OID associated with a given relation.
1653  *
1654  * Note: not all pg_class entries have associated pg_type OIDs; so be
1655  * careful to check for InvalidOid result.
1656  */
1657 Oid
1658 get_rel_type_id(Oid relid)
1659 {
1660         HeapTuple       tp;
1661
1662         tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1663         if (HeapTupleIsValid(tp))
1664         {
1665                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1666                 Oid                     result;
1667
1668                 result = reltup->reltype;
1669                 ReleaseSysCache(tp);
1670                 return result;
1671         }
1672         else
1673                 return InvalidOid;
1674 }
1675
1676 /*
1677  * get_rel_relkind
1678  *
1679  *              Returns the relkind associated with a given relation.
1680  */
1681 char
1682 get_rel_relkind(Oid relid)
1683 {
1684         HeapTuple       tp;
1685
1686         tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1687         if (HeapTupleIsValid(tp))
1688         {
1689                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1690                 char            result;
1691
1692                 result = reltup->relkind;
1693                 ReleaseSysCache(tp);
1694                 return result;
1695         }
1696         else
1697                 return '\0';
1698 }
1699
1700 /*
1701  * get_rel_tablespace
1702  *
1703  *              Returns the pg_tablespace OID associated with a given relation.
1704  *
1705  * Note: InvalidOid might mean either that we couldn't find the relation,
1706  * or that it is in the database's default tablespace.
1707  */
1708 Oid
1709 get_rel_tablespace(Oid relid)
1710 {
1711         HeapTuple       tp;
1712
1713         tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1714         if (HeapTupleIsValid(tp))
1715         {
1716                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1717                 Oid                     result;
1718
1719                 result = reltup->reltablespace;
1720                 ReleaseSysCache(tp);
1721                 return result;
1722         }
1723         else
1724                 return InvalidOid;
1725 }
1726
1727
1728 /*                              ---------- TYPE CACHE ----------                                                 */
1729
1730 /*
1731  * get_typisdefined
1732  *
1733  *              Given the type OID, determine whether the type is defined
1734  *              (if not, it's only a shell).
1735  */
1736 bool
1737 get_typisdefined(Oid typid)
1738 {
1739         HeapTuple       tp;
1740
1741         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1742         if (HeapTupleIsValid(tp))
1743         {
1744                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1745                 bool            result;
1746
1747                 result = typtup->typisdefined;
1748                 ReleaseSysCache(tp);
1749                 return result;
1750         }
1751         else
1752                 return false;
1753 }
1754
1755 /*
1756  * get_typlen
1757  *
1758  *              Given the type OID, return the length of the type.
1759  */
1760 int16
1761 get_typlen(Oid typid)
1762 {
1763         HeapTuple       tp;
1764
1765         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1766         if (HeapTupleIsValid(tp))
1767         {
1768                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1769                 int16           result;
1770
1771                 result = typtup->typlen;
1772                 ReleaseSysCache(tp);
1773                 return result;
1774         }
1775         else
1776                 return 0;
1777 }
1778
1779 /*
1780  * get_typbyval
1781  *
1782  *              Given the type OID, determine whether the type is returned by value or
1783  *              not.  Returns true if by value, false if by reference.
1784  */
1785 bool
1786 get_typbyval(Oid typid)
1787 {
1788         HeapTuple       tp;
1789
1790         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1791         if (HeapTupleIsValid(tp))
1792         {
1793                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1794                 bool            result;
1795
1796                 result = typtup->typbyval;
1797                 ReleaseSysCache(tp);
1798                 return result;
1799         }
1800         else
1801                 return false;
1802 }
1803
1804 /*
1805  * get_typlenbyval
1806  *
1807  *              A two-fer: given the type OID, return both typlen and typbyval.
1808  *
1809  *              Since both pieces of info are needed to know how to copy a Datum,
1810  *              many places need both.  Might as well get them with one cache lookup
1811  *              instead of two.  Also, this routine raises an error instead of
1812  *              returning a bogus value when given a bad type OID.
1813  */
1814 void
1815 get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
1816 {
1817         HeapTuple       tp;
1818         Form_pg_type typtup;
1819
1820         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1821         if (!HeapTupleIsValid(tp))
1822                 elog(ERROR, "cache lookup failed for type %u", typid);
1823         typtup = (Form_pg_type) GETSTRUCT(tp);
1824         *typlen = typtup->typlen;
1825         *typbyval = typtup->typbyval;
1826         ReleaseSysCache(tp);
1827 }
1828
1829 /*
1830  * get_typlenbyvalalign
1831  *
1832  *              A three-fer: given the type OID, return typlen, typbyval, typalign.
1833  */
1834 void
1835 get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
1836                                          char *typalign)
1837 {
1838         HeapTuple       tp;
1839         Form_pg_type typtup;
1840
1841         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1842         if (!HeapTupleIsValid(tp))
1843                 elog(ERROR, "cache lookup failed for type %u", typid);
1844         typtup = (Form_pg_type) GETSTRUCT(tp);
1845         *typlen = typtup->typlen;
1846         *typbyval = typtup->typbyval;
1847         *typalign = typtup->typalign;
1848         ReleaseSysCache(tp);
1849 }
1850
1851 /*
1852  * getTypeIOParam
1853  *              Given a pg_type row, select the type OID to pass to I/O functions
1854  *
1855  * Formerly, all I/O functions were passed pg_type.typelem as their second
1856  * parameter, but we now have a more complex rule about what to pass.
1857  * This knowledge is intended to be centralized here --- direct references
1858  * to typelem elsewhere in the code are wrong, if they are associated with
1859  * I/O calls and not with actual subscripting operations!  (But see
1860  * bootstrap.c's boot_get_type_io_data() if you need to change this.)
1861  *
1862  * As of PostgreSQL 8.1, output functions receive only the value itself
1863  * and not any auxiliary parameters, so the name of this routine is now
1864  * a bit of a misnomer ... it should be getTypeInputParam.
1865  */
1866 Oid
1867 getTypeIOParam(HeapTuple typeTuple)
1868 {
1869         Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
1870
1871         /*
1872          * Array types get their typelem as parameter; everybody else gets their
1873          * own type OID as parameter.  (As of 8.2, domains must get their own OID
1874          * even if their base type is an array.)
1875          */
1876         if (typeStruct->typtype == TYPTYPE_BASE && OidIsValid(typeStruct->typelem))
1877                 return typeStruct->typelem;
1878         else
1879                 return HeapTupleGetOid(typeTuple);
1880 }
1881
1882 /*
1883  * get_type_io_data
1884  *
1885  *              A six-fer:      given the type OID, return typlen, typbyval, typalign,
1886  *                                      typdelim, typioparam, and IO function OID. The IO function
1887  *                                      returned is controlled by IOFuncSelector
1888  */
1889 void
1890 get_type_io_data(Oid typid,
1891                                  IOFuncSelector which_func,
1892                                  int16 *typlen,
1893                                  bool *typbyval,
1894                                  char *typalign,
1895                                  char *typdelim,
1896                                  Oid *typioparam,
1897                                  Oid *func)
1898 {
1899         HeapTuple       typeTuple;
1900         Form_pg_type typeStruct;
1901
1902         /*
1903          * In bootstrap mode, pass it off to bootstrap.c.  This hack allows us to
1904          * use array_in and array_out during bootstrap.
1905          */
1906         if (IsBootstrapProcessingMode())
1907         {
1908                 Oid                     typinput;
1909                 Oid                     typoutput;
1910
1911                 boot_get_type_io_data(typid,
1912                                                           typlen,
1913                                                           typbyval,
1914                                                           typalign,
1915                                                           typdelim,
1916                                                           typioparam,
1917                                                           &typinput,
1918                                                           &typoutput);
1919                 switch (which_func)
1920                 {
1921                         case IOFunc_input:
1922                                 *func = typinput;
1923                                 break;
1924                         case IOFunc_output:
1925                                 *func = typoutput;
1926                                 break;
1927                         default:
1928                                 elog(ERROR, "binary I/O not supported during bootstrap");
1929                                 break;
1930                 }
1931                 return;
1932         }
1933
1934         typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1935         if (!HeapTupleIsValid(typeTuple))
1936                 elog(ERROR, "cache lookup failed for type %u", typid);
1937         typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
1938
1939         *typlen = typeStruct->typlen;
1940         *typbyval = typeStruct->typbyval;
1941         *typalign = typeStruct->typalign;
1942         *typdelim = typeStruct->typdelim;
1943         *typioparam = getTypeIOParam(typeTuple);
1944         switch (which_func)
1945         {
1946                 case IOFunc_input:
1947                         *func = typeStruct->typinput;
1948                         break;
1949                 case IOFunc_output:
1950                         *func = typeStruct->typoutput;
1951                         break;
1952                 case IOFunc_receive:
1953                         *func = typeStruct->typreceive;
1954                         break;
1955                 case IOFunc_send:
1956                         *func = typeStruct->typsend;
1957                         break;
1958         }
1959         ReleaseSysCache(typeTuple);
1960 }
1961
1962 #ifdef NOT_USED
1963 char
1964 get_typalign(Oid typid)
1965 {
1966         HeapTuple       tp;
1967
1968         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1969         if (HeapTupleIsValid(tp))
1970         {
1971                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1972                 char            result;
1973
1974                 result = typtup->typalign;
1975                 ReleaseSysCache(tp);
1976                 return result;
1977         }
1978         else
1979                 return 'i';
1980 }
1981 #endif
1982
1983 char
1984 get_typstorage(Oid typid)
1985 {
1986         HeapTuple       tp;
1987
1988         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1989         if (HeapTupleIsValid(tp))
1990         {
1991                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1992                 char            result;
1993
1994                 result = typtup->typstorage;
1995                 ReleaseSysCache(tp);
1996                 return result;
1997         }
1998         else
1999                 return 'p';
2000 }
2001
2002 /*
2003  * get_typdefault
2004  *        Given a type OID, return the type's default value, if any.
2005  *
2006  *        The result is a palloc'd expression node tree, or NULL if there
2007  *        is no defined default for the datatype.
2008  *
2009  * NB: caller should be prepared to coerce result to correct datatype;
2010  * the returned expression tree might produce something of the wrong type.
2011  */
2012 Node *
2013 get_typdefault(Oid typid)
2014 {
2015         HeapTuple       typeTuple;
2016         Form_pg_type type;
2017         Datum           datum;
2018         bool            isNull;
2019         Node       *expr;
2020
2021         typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2022         if (!HeapTupleIsValid(typeTuple))
2023                 elog(ERROR, "cache lookup failed for type %u", typid);
2024         type = (Form_pg_type) GETSTRUCT(typeTuple);
2025
2026         /*
2027          * typdefault and typdefaultbin are potentially null, so don't try to
2028          * access 'em as struct fields. Must do it the hard way with
2029          * SysCacheGetAttr.
2030          */
2031         datum = SysCacheGetAttr(TYPEOID,
2032                                                         typeTuple,
2033                                                         Anum_pg_type_typdefaultbin,
2034                                                         &isNull);
2035
2036         if (!isNull)
2037         {
2038                 /* We have an expression default */
2039                 expr = stringToNode(TextDatumGetCString(datum));
2040         }
2041         else
2042         {
2043                 /* Perhaps we have a plain literal default */
2044                 datum = SysCacheGetAttr(TYPEOID,
2045                                                                 typeTuple,
2046                                                                 Anum_pg_type_typdefault,
2047                                                                 &isNull);
2048
2049                 if (!isNull)
2050                 {
2051                         char       *strDefaultVal;
2052
2053                         /* Convert text datum to C string */
2054                         strDefaultVal = TextDatumGetCString(datum);
2055                         /* Convert C string to a value of the given type */
2056                         datum = OidInputFunctionCall(type->typinput, strDefaultVal,
2057                                                                                  getTypeIOParam(typeTuple), -1);
2058                         /* Build a Const node containing the value */
2059                         expr = (Node *) makeConst(typid,
2060                                                                           -1,
2061                                                                           type->typcollation,
2062                                                                           type->typlen,
2063                                                                           datum,
2064                                                                           false,
2065                                                                           type->typbyval);
2066                         pfree(strDefaultVal);
2067                 }
2068                 else
2069                 {
2070                         /* No default */
2071                         expr = NULL;
2072                 }
2073         }
2074
2075         ReleaseSysCache(typeTuple);
2076
2077         return expr;
2078 }
2079
2080 /*
2081  * getBaseType
2082  *              If the given type is a domain, return its base type;
2083  *              otherwise return the type's own OID.
2084  */
2085 Oid
2086 getBaseType(Oid typid)
2087 {
2088         int32           typmod = -1;
2089
2090         return getBaseTypeAndTypmod(typid, &typmod);
2091 }
2092
2093 /*
2094  * getBaseTypeAndTypmod
2095  *              If the given type is a domain, return its base type and typmod;
2096  *              otherwise return the type's own OID, and leave *typmod unchanged.
2097  *
2098  * Note that the "applied typmod" should be -1 for every domain level
2099  * above the bottommost; therefore, if the passed-in typid is indeed
2100  * a domain, *typmod should be -1.
2101  */
2102 Oid
2103 getBaseTypeAndTypmod(Oid typid, int32 *typmod)
2104 {
2105         /*
2106          * We loop to find the bottom base type in a stack of domains.
2107          */
2108         for (;;)
2109         {
2110                 HeapTuple       tup;
2111                 Form_pg_type typTup;
2112
2113                 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2114                 if (!HeapTupleIsValid(tup))
2115                         elog(ERROR, "cache lookup failed for type %u", typid);
2116                 typTup = (Form_pg_type) GETSTRUCT(tup);
2117                 if (typTup->typtype != TYPTYPE_DOMAIN)
2118                 {
2119                         /* Not a domain, so done */
2120                         ReleaseSysCache(tup);
2121                         break;
2122                 }
2123
2124                 Assert(*typmod == -1);
2125                 typid = typTup->typbasetype;
2126                 *typmod = typTup->typtypmod;
2127
2128                 ReleaseSysCache(tup);
2129         }
2130
2131         return typid;
2132 }
2133
2134 /*
2135  * get_typavgwidth
2136  *
2137  *        Given a type OID and a typmod value (pass -1 if typmod is unknown),
2138  *        estimate the average width of values of the type.  This is used by
2139  *        the planner, which doesn't require absolutely correct results;
2140  *        it's OK (and expected) to guess if we don't know for sure.
2141  */
2142 int32
2143 get_typavgwidth(Oid typid, int32 typmod)
2144 {
2145         int                     typlen = get_typlen(typid);
2146         int32           maxwidth;
2147
2148         /*
2149          * Easy if it's a fixed-width type
2150          */
2151         if (typlen > 0)
2152                 return typlen;
2153
2154         /*
2155          * type_maximum_size knows the encoding of typmod for some datatypes;
2156          * don't duplicate that knowledge here.
2157          */
2158         maxwidth = type_maximum_size(typid, typmod);
2159         if (maxwidth > 0)
2160         {
2161                 /*
2162                  * For BPCHAR, the max width is also the only width.  Otherwise we
2163                  * need to guess about the typical data width given the max. A sliding
2164                  * scale for percentage of max width seems reasonable.
2165                  */
2166                 if (typid == BPCHAROID)
2167                         return maxwidth;
2168                 if (maxwidth <= 32)
2169                         return maxwidth;        /* assume full width */
2170                 if (maxwidth < 1000)
2171                         return 32 + (maxwidth - 32) / 2;        /* assume 50% */
2172
2173                 /*
2174                  * Beyond 1000, assume we're looking at something like
2175                  * "varchar(10000)" where the limit isn't actually reached often, and
2176                  * use a fixed estimate.
2177                  */
2178                 return 32 + (1000 - 32) / 2;
2179         }
2180
2181         /*
2182          * Ooops, we have no idea ... wild guess time.
2183          */
2184         return 32;
2185 }
2186
2187 /*
2188  * get_typtype
2189  *
2190  *              Given the type OID, find if it is a basic type, a complex type, etc.
2191  *              It returns the null char if the cache lookup fails...
2192  */
2193 char
2194 get_typtype(Oid typid)
2195 {
2196         HeapTuple       tp;
2197
2198         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2199         if (HeapTupleIsValid(tp))
2200         {
2201                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2202                 char            result;
2203
2204                 result = typtup->typtype;
2205                 ReleaseSysCache(tp);
2206                 return result;
2207         }
2208         else
2209                 return '\0';
2210 }
2211
2212 /*
2213  * type_is_rowtype
2214  *
2215  *              Convenience function to determine whether a type OID represents
2216  *              a "rowtype" type --- either RECORD or a named composite type.
2217  */
2218 bool
2219 type_is_rowtype(Oid typid)
2220 {
2221         return (typid == RECORDOID || get_typtype(typid) == TYPTYPE_COMPOSITE);
2222 }
2223
2224 /*
2225  * type_is_enum
2226  *        Returns true if the given type is an enum type.
2227  */
2228 bool
2229 type_is_enum(Oid typid)
2230 {
2231         return (get_typtype(typid) == TYPTYPE_ENUM);
2232 }
2233
2234 /*
2235  * get_type_category_preferred
2236  *
2237  *              Given the type OID, fetch its category and preferred-type status.
2238  *              Throws error on failure.
2239  */
2240 void
2241 get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
2242 {
2243         HeapTuple       tp;
2244         Form_pg_type typtup;
2245
2246         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2247         if (!HeapTupleIsValid(tp))
2248                 elog(ERROR, "cache lookup failed for type %u", typid);
2249         typtup = (Form_pg_type) GETSTRUCT(tp);
2250         *typcategory = typtup->typcategory;
2251         *typispreferred = typtup->typispreferred;
2252         ReleaseSysCache(tp);
2253 }
2254
2255 /*
2256  * get_typ_typrelid
2257  *
2258  *              Given the type OID, get the typrelid (InvalidOid if not a complex
2259  *              type).
2260  */
2261 Oid
2262 get_typ_typrelid(Oid typid)
2263 {
2264         HeapTuple       tp;
2265
2266         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2267         if (HeapTupleIsValid(tp))
2268         {
2269                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2270                 Oid                     result;
2271
2272                 result = typtup->typrelid;
2273                 ReleaseSysCache(tp);
2274                 return result;
2275         }
2276         else
2277                 return InvalidOid;
2278 }
2279
2280 /*
2281  * get_element_type
2282  *
2283  *              Given the type OID, get the typelem (InvalidOid if not an array type).
2284  *
2285  * NB: this only considers varlena arrays to be true arrays; InvalidOid is
2286  * returned if the input is a fixed-length array type.
2287  */
2288 Oid
2289 get_element_type(Oid typid)
2290 {
2291         HeapTuple       tp;
2292
2293         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2294         if (HeapTupleIsValid(tp))
2295         {
2296                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2297                 Oid                     result;
2298
2299                 if (typtup->typlen == -1)
2300                         result = typtup->typelem;
2301                 else
2302                         result = InvalidOid;
2303                 ReleaseSysCache(tp);
2304                 return result;
2305         }
2306         else
2307                 return InvalidOid;
2308 }
2309
2310 /*
2311  * get_array_type
2312  *
2313  *              Given the type OID, get the corresponding "true" array type.
2314  *              Returns InvalidOid if no array type can be found.
2315  */
2316 Oid
2317 get_array_type(Oid typid)
2318 {
2319         HeapTuple       tp;
2320         Oid                     result = InvalidOid;
2321
2322         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2323         if (HeapTupleIsValid(tp))
2324         {
2325                 result = ((Form_pg_type) GETSTRUCT(tp))->typarray;
2326                 ReleaseSysCache(tp);
2327         }
2328         return result;
2329 }
2330
2331 /*
2332  * get_base_element_type
2333  *              Given the type OID, get the typelem, looking "through" any domain
2334  *              to its underlying array type.
2335  *
2336  * This is equivalent to get_element_type(getBaseType(typid)), but avoids
2337  * an extra cache lookup.  Note that it fails to provide any information
2338  * about the typmod of the array.
2339  */
2340 Oid
2341 get_base_element_type(Oid typid)
2342 {
2343         /*
2344          * We loop to find the bottom base type in a stack of domains.
2345          */
2346         for (;;)
2347         {
2348                 HeapTuple       tup;
2349                 Form_pg_type typTup;
2350
2351                 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2352                 if (!HeapTupleIsValid(tup))
2353                         break;
2354                 typTup = (Form_pg_type) GETSTRUCT(tup);
2355                 if (typTup->typtype != TYPTYPE_DOMAIN)
2356                 {
2357                         /* Not a domain, so stop descending */
2358                         Oid                     result;
2359
2360                         /* This test must match get_element_type */
2361                         if (typTup->typlen == -1)
2362                                 result = typTup->typelem;
2363                         else
2364                                 result = InvalidOid;
2365                         ReleaseSysCache(tup);
2366                         return result;
2367                 }
2368
2369                 typid = typTup->typbasetype;
2370                 ReleaseSysCache(tup);
2371         }
2372
2373         /* Like get_element_type, silently return InvalidOid for bogus input */
2374         return InvalidOid;
2375 }
2376
2377 /*
2378  * getTypeInputInfo
2379  *
2380  *              Get info needed for converting values of a type to internal form
2381  */
2382 void
2383 getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
2384 {
2385         HeapTuple       typeTuple;
2386         Form_pg_type pt;
2387
2388         typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
2389         if (!HeapTupleIsValid(typeTuple))
2390                 elog(ERROR, "cache lookup failed for type %u", type);
2391         pt = (Form_pg_type) GETSTRUCT(typeTuple);
2392
2393         if (!pt->typisdefined)
2394                 ereport(ERROR,
2395                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2396                                  errmsg("type %s is only a shell",
2397                                                 format_type_be(type))));
2398         if (!OidIsValid(pt->typinput))
2399                 ereport(ERROR,
2400                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2401                                  errmsg("no input function available for type %s",
2402                                                 format_type_be(type))));
2403
2404         *typInput = pt->typinput;
2405         *typIOParam = getTypeIOParam(typeTuple);
2406
2407         ReleaseSysCache(typeTuple);
2408 }
2409
2410 /*
2411  * getTypeOutputInfo
2412  *
2413  *              Get info needed for printing values of a type
2414  */
2415 void
2416 getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
2417 {
2418         HeapTuple       typeTuple;
2419         Form_pg_type pt;
2420
2421         typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
2422         if (!HeapTupleIsValid(typeTuple))
2423                 elog(ERROR, "cache lookup failed for type %u", type);
2424         pt = (Form_pg_type) GETSTRUCT(typeTuple);
2425
2426         if (!pt->typisdefined)
2427                 ereport(ERROR,
2428                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2429                                  errmsg("type %s is only a shell",
2430                                                 format_type_be(type))));
2431         if (!OidIsValid(pt->typoutput))
2432                 ereport(ERROR,
2433                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2434                                  errmsg("no output function available for type %s",
2435                                                 format_type_be(type))));
2436
2437         *typOutput = pt->typoutput;
2438         *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
2439
2440         ReleaseSysCache(typeTuple);
2441 }
2442
2443 /*
2444  * getTypeBinaryInputInfo
2445  *
2446  *              Get info needed for binary input of values of a type
2447  */
2448 void
2449 getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
2450 {
2451         HeapTuple       typeTuple;
2452         Form_pg_type pt;
2453
2454         typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
2455         if (!HeapTupleIsValid(typeTuple))
2456                 elog(ERROR, "cache lookup failed for type %u", type);
2457         pt = (Form_pg_type) GETSTRUCT(typeTuple);
2458
2459         if (!pt->typisdefined)
2460                 ereport(ERROR,
2461                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2462                                  errmsg("type %s is only a shell",
2463                                                 format_type_be(type))));
2464         if (!OidIsValid(pt->typreceive))
2465                 ereport(ERROR,
2466                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2467                                  errmsg("no binary input function available for type %s",
2468                                                 format_type_be(type))));
2469
2470         *typReceive = pt->typreceive;
2471         *typIOParam = getTypeIOParam(typeTuple);
2472
2473         ReleaseSysCache(typeTuple);
2474 }
2475
2476 /*
2477  * getTypeBinaryOutputInfo
2478  *
2479  *              Get info needed for binary output of values of a type
2480  */
2481 void
2482 getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
2483 {
2484         HeapTuple       typeTuple;
2485         Form_pg_type pt;
2486
2487         typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
2488         if (!HeapTupleIsValid(typeTuple))
2489                 elog(ERROR, "cache lookup failed for type %u", type);
2490         pt = (Form_pg_type) GETSTRUCT(typeTuple);
2491
2492         if (!pt->typisdefined)
2493                 ereport(ERROR,
2494                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2495                                  errmsg("type %s is only a shell",
2496                                                 format_type_be(type))));
2497         if (!OidIsValid(pt->typsend))
2498                 ereport(ERROR,
2499                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2500                                  errmsg("no binary output function available for type %s",
2501                                                 format_type_be(type))));
2502
2503         *typSend = pt->typsend;
2504         *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
2505
2506         ReleaseSysCache(typeTuple);
2507 }
2508
2509 /*
2510  * get_typmodin
2511  *
2512  *              Given the type OID, return the type's typmodin procedure, if any.
2513  */
2514 Oid
2515 get_typmodin(Oid typid)
2516 {
2517         HeapTuple       tp;
2518
2519         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2520         if (HeapTupleIsValid(tp))
2521         {
2522                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2523                 Oid                     result;
2524
2525                 result = typtup->typmodin;
2526                 ReleaseSysCache(tp);
2527                 return result;
2528         }
2529         else
2530                 return InvalidOid;
2531 }
2532
2533 #ifdef NOT_USED
2534 /*
2535  * get_typmodout
2536  *
2537  *              Given the type OID, return the type's typmodout procedure, if any.
2538  */
2539 Oid
2540 get_typmodout(Oid typid)
2541 {
2542         HeapTuple       tp;
2543
2544         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2545         if (HeapTupleIsValid(tp))
2546         {
2547                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2548                 Oid                     result;
2549
2550                 result = typtup->typmodout;
2551                 ReleaseSysCache(tp);
2552                 return result;
2553         }
2554         else
2555                 return InvalidOid;
2556 }
2557 #endif   /* NOT_USED */
2558
2559 /*
2560  * get_typcollation
2561  *
2562  *              Given the type OID, return the type's typcollation attribute.
2563  */
2564 Oid
2565 get_typcollation(Oid typid)
2566 {
2567         HeapTuple       tp;
2568
2569         tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2570         if (HeapTupleIsValid(tp))
2571         {
2572                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2573                 Oid                     result;
2574
2575                 result = typtup->typcollation;
2576                 ReleaseSysCache(tp);
2577                 return result;
2578         }
2579         else
2580                 return InvalidOid;
2581 }
2582
2583
2584 /*
2585  * type_is_collatable
2586  *
2587  *              Return whether the type cares about collations
2588  */
2589 bool
2590 type_is_collatable(Oid typid)
2591 {
2592         return OidIsValid(get_typcollation(typid));
2593 }
2594
2595
2596 /*                              ---------- STATISTICS CACHE ----------                                   */
2597
2598 /*
2599  * get_attavgwidth
2600  *
2601  *        Given the table and attribute number of a column, get the average
2602  *        width of entries in the column.  Return zero if no data available.
2603  *
2604  * Currently this is only consulted for individual tables, not for inheritance
2605  * trees, so we don't need an "inh" parameter.
2606  *
2607  * Calling a hook at this point looks somewhat strange, but is required
2608  * because the optimizer calls this function without any other way for
2609  * plug-ins to control the result.
2610  */
2611 int32
2612 get_attavgwidth(Oid relid, AttrNumber attnum)
2613 {
2614         HeapTuple       tp;
2615         int32           stawidth;
2616
2617         if (get_attavgwidth_hook)
2618         {
2619                 stawidth = (*get_attavgwidth_hook) (relid, attnum);
2620                 if (stawidth > 0)
2621                         return stawidth;
2622         }
2623         tp = SearchSysCache3(STATRELATTINH,
2624                                                  ObjectIdGetDatum(relid),
2625                                                  Int16GetDatum(attnum),
2626                                                  BoolGetDatum(false));
2627         if (HeapTupleIsValid(tp))
2628         {
2629                 stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
2630                 ReleaseSysCache(tp);
2631                 if (stawidth > 0)
2632                         return stawidth;
2633         }
2634         return 0;
2635 }
2636
2637 /*
2638  * get_attstatsslot
2639  *
2640  *              Extract the contents of a "slot" of a pg_statistic tuple.
2641  *              Returns TRUE if requested slot type was found, else FALSE.
2642  *
2643  * Unlike other routines in this file, this takes a pointer to an
2644  * already-looked-up tuple in the pg_statistic cache.  We do this since
2645  * most callers will want to extract more than one value from the cache
2646  * entry, and we don't want to repeat the cache lookup unnecessarily.
2647  * Also, this API allows this routine to be used with statistics tuples
2648  * that have been provided by a stats hook and didn't really come from
2649  * pg_statistic.
2650  *
2651  * statstuple: pg_statistics tuple to be examined.
2652  * atttype: type OID of attribute (can be InvalidOid if values == NULL).
2653  * atttypmod: typmod of attribute (can be 0 if values == NULL).
2654  * reqkind: STAKIND code for desired statistics slot kind.
2655  * reqop: STAOP value wanted, or InvalidOid if don't care.
2656  * actualop: if not NULL, *actualop receives the actual STAOP value.
2657  * values, nvalues: if not NULL, the slot's stavalues are extracted.
2658  * numbers, nnumbers: if not NULL, the slot's stanumbers are extracted.
2659  *
2660  * If assigned, values and numbers are set to point to palloc'd arrays.
2661  * If the attribute type is pass-by-reference, the values referenced by
2662  * the values array are themselves palloc'd.  The palloc'd stuff can be
2663  * freed by calling free_attstatsslot.
2664  *
2665  * Note: at present, atttype/atttypmod aren't actually used here at all.
2666  * But the caller must have the correct (or at least binary-compatible)
2667  * type ID to pass to free_attstatsslot later.
2668  */
2669 bool
2670 get_attstatsslot(HeapTuple statstuple,
2671                                  Oid atttype, int32 atttypmod,
2672                                  int reqkind, Oid reqop,
2673                                  Oid *actualop,
2674                                  Datum **values, int *nvalues,
2675                                  float4 **numbers, int *nnumbers)
2676 {
2677         Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
2678         int                     i,
2679                                 j;
2680         Datum           val;
2681         bool            isnull;
2682         ArrayType  *statarray;
2683         Oid                     arrayelemtype;
2684         int                     narrayelem;
2685         HeapTuple       typeTuple;
2686         Form_pg_type typeForm;
2687
2688         for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
2689         {
2690                 if ((&stats->stakind1)[i] == reqkind &&
2691                         (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
2692                         break;
2693         }
2694         if (i >= STATISTIC_NUM_SLOTS)
2695                 return false;                   /* not there */
2696
2697         if (actualop)
2698                 *actualop = (&stats->staop1)[i];
2699
2700         if (values)
2701         {
2702                 val = SysCacheGetAttr(STATRELATTINH, statstuple,
2703                                                           Anum_pg_statistic_stavalues1 + i,
2704                                                           &isnull);
2705                 if (isnull)
2706                         elog(ERROR, "stavalues is null");
2707                 statarray = DatumGetArrayTypeP(val);
2708
2709                 /*
2710                  * Need to get info about the array element type.  We look at the
2711                  * actual element type embedded in the array, which might be only
2712                  * binary-compatible with the passed-in atttype.  The info we
2713                  * extract here should be the same either way, but deconstruct_array
2714                  * is picky about having an exact type OID match.
2715                  */
2716                 arrayelemtype = ARR_ELEMTYPE(statarray);
2717                 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrayelemtype));
2718                 if (!HeapTupleIsValid(typeTuple))
2719                         elog(ERROR, "cache lookup failed for type %u", arrayelemtype);
2720                 typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
2721
2722                 /* Deconstruct array into Datum elements; NULLs not expected */
2723                 deconstruct_array(statarray,
2724                                                   arrayelemtype,
2725                                                   typeForm->typlen,
2726                                                   typeForm->typbyval,
2727                                                   typeForm->typalign,
2728                                                   values, NULL, nvalues);
2729
2730                 /*
2731                  * If the element type is pass-by-reference, we now have a bunch of
2732                  * Datums that are pointers into the syscache value.  Copy them to
2733                  * avoid problems if syscache decides to drop the entry.
2734                  */
2735                 if (!typeForm->typbyval)
2736                 {
2737                         for (j = 0; j < *nvalues; j++)
2738                         {
2739                                 (*values)[j] = datumCopy((*values)[j],
2740                                                                                  typeForm->typbyval,
2741                                                                                  typeForm->typlen);
2742                         }
2743                 }
2744
2745                 ReleaseSysCache(typeTuple);
2746
2747                 /*
2748                  * Free statarray if it's a detoasted copy.
2749                  */
2750                 if ((Pointer) statarray != DatumGetPointer(val))
2751                         pfree(statarray);
2752         }
2753
2754         if (numbers)
2755         {
2756                 val = SysCacheGetAttr(STATRELATTINH, statstuple,
2757                                                           Anum_pg_statistic_stanumbers1 + i,
2758                                                           &isnull);
2759                 if (isnull)
2760                         elog(ERROR, "stanumbers is null");
2761                 statarray = DatumGetArrayTypeP(val);
2762
2763                 /*
2764                  * We expect the array to be a 1-D float4 array; verify that. We don't
2765                  * need to use deconstruct_array() since the array data is just going
2766                  * to look like a C array of float4 values.
2767                  */
2768                 narrayelem = ARR_DIMS(statarray)[0];
2769                 if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
2770                         ARR_HASNULL(statarray) ||
2771                         ARR_ELEMTYPE(statarray) != FLOAT4OID)
2772                         elog(ERROR, "stanumbers is not a 1-D float4 array");
2773                 *numbers = (float4 *) palloc(narrayelem * sizeof(float4));
2774                 memcpy(*numbers, ARR_DATA_PTR(statarray), narrayelem * sizeof(float4));
2775                 *nnumbers = narrayelem;
2776
2777                 /*
2778                  * Free statarray if it's a detoasted copy.
2779                  */
2780                 if ((Pointer) statarray != DatumGetPointer(val))
2781                         pfree(statarray);
2782         }
2783
2784         return true;
2785 }
2786
2787 /*
2788  * free_attstatsslot
2789  *              Free data allocated by get_attstatsslot
2790  *
2791  * atttype need be valid only if values != NULL.
2792  */
2793 void
2794 free_attstatsslot(Oid atttype,
2795                                   Datum *values, int nvalues,
2796                                   float4 *numbers, int nnumbers)
2797 {
2798         if (values)
2799         {
2800                 if (!get_typbyval(atttype))
2801                 {
2802                         int                     i;
2803
2804                         for (i = 0; i < nvalues; i++)
2805                                 pfree(DatumGetPointer(values[i]));
2806                 }
2807                 pfree(values);
2808         }
2809         if (numbers)
2810                 pfree(numbers);
2811 }
2812
2813 /*                              ---------- PG_NAMESPACE CACHE ----------                                 */
2814
2815 /*
2816  * get_namespace_name
2817  *              Returns the name of a given namespace
2818  *
2819  * Returns a palloc'd copy of the string, or NULL if no such namespace.
2820  */
2821 char *
2822 get_namespace_name(Oid nspid)
2823 {
2824         HeapTuple       tp;
2825
2826         tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
2827         if (HeapTupleIsValid(tp))
2828         {
2829                 Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
2830                 char       *result;
2831
2832                 result = pstrdup(NameStr(nsptup->nspname));
2833                 ReleaseSysCache(tp);
2834                 return result;
2835         }
2836         else
2837                 return NULL;
2838 }