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