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