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