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