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