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