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