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