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