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