1 /*-------------------------------------------------------------------------
2 *
3 * lsyscache.c
4 * Convenience routines for common queries in the system catalog cache.
5 *
6 * Portions Copyright (c) 1996-2017, 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() */
50 get_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 */
62 bool
op_in_opfamily(Oid opno,Oid opfamily)63 op_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 */
79 int
get_op_opfamily_strategy(Oid opno,Oid opfamily)80 get_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 */
104 Oid
get_op_opfamily_sortfamily(Oid opno,Oid opfamily)105 get_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 */
132 void
get_op_opfamily_properties(Oid opno,Oid opfamily,bool ordering_op,int * strategy,Oid * lefttype,Oid * righttype)133 get_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 */
162 Oid
get_opfamily_member(Oid opfamily,Oid lefttype,Oid righttype,int16 strategy)163 get_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 */
203 bool
get_ordering_op_properties(Oid opno,Oid * opfamily,Oid * opcintype,int16 * strategy)204 get_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 */
263 Oid
get_equality_op_for_ordering_op(Oid opno,bool * reverse)264 get_equality_op_for_ordering_op(Oid opno, bool *reverse)
265 {
266 Oid result = InvalidOid;
267 Oid opfamily;
268 Oid opcintype;
269 int16 strategy;
270
271 /* Find the operator in pg_amop */
272 if (get_ordering_op_properties(opno,
273 &opfamily, &opcintype, &strategy))
274 {
275 /* Found a suitable opfamily, get matching equality operator */
276 result = get_opfamily_member(opfamily,
277 opcintype,
278 opcintype,
279 BTEqualStrategyNumber);
280 if (reverse)
281 *reverse = (strategy == BTGreaterStrategyNumber);
282 }
283
284 return result;
285 }
286
287 /*
288 * get_ordering_op_for_equality_op
289 * Get the OID of a datatype-specific btree ordering operator
290 * associated with an equality operator. (If there are multiple
291 * possibilities, assume any one will do.)
292 *
293 * This function is used when we have to sort data before unique-ifying,
294 * and don't much care which sorting op is used as long as it's compatible
295 * with the intended equality operator. Since we need a sorting operator,
296 * it should be single-data-type even if the given operator is cross-type.
297 * The caller specifies whether to find an op for the LHS or RHS data type.
298 *
299 * Returns InvalidOid if no matching ordering operator can be found.
300 */
301 Oid
get_ordering_op_for_equality_op(Oid opno,bool use_lhs_type)302 get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
303 {
304 Oid result = InvalidOid;
305 CatCList *catlist;
306 int i;
307
308 /*
309 * Search pg_amop to see if the target operator is registered as the "="
310 * operator of any btree opfamily.
311 */
312 catlist = 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 */
362 List *
get_mergejoin_opfamilies(Oid opno)363 get_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 */
406 bool
get_compatible_hash_operators(Oid opno,Oid * lhs_opno,Oid * rhs_opno)407 get_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 hash support function(s) compatible with the given
494 * 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 */
506 bool
get_op_hash_functions(Oid opno,RegProcedure * lhs_procno,RegProcedure * rhs_procno)507 get_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 HASHPROC);
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 HASHPROC);
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 */
597 List *
get_op_btree_interpretation(Oid opno)598 get_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 */
694 bool
equality_ops_are_compatible(Oid opno1,Oid opno2)695 equality_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 */
743 Oid
get_opfamily_proc(Oid opfamily,Oid lefttype,Oid righttype,int16 procnum)744 get_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,
769 * return the "attname" field from the attribute relation.
770 *
771 * Note: returns a palloc'd copy of the string, or NULL if no such attribute.
772 */
773 char *
get_attname(Oid relid,AttrNumber attnum)774 get_attname(Oid relid, AttrNumber attnum)
775 {
776 HeapTuple tp;
777
778 tp = SearchSysCache2(ATTNUM,
779 ObjectIdGetDatum(relid),
780 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 else
791 return NULL;
792 }
793
794 /*
795 * get_relid_attribute_name
796 *
797 * Same as above routine get_attname(), except that error
798 * is handled by elog() instead of returning NULL.
799 */
800 char *
get_relid_attribute_name(Oid relid,AttrNumber attnum)801 get_relid_attribute_name(Oid relid, AttrNumber attnum)
802 {
803 char *attname;
804
805 attname = get_attname(relid, attnum);
806 if (attname == NULL)
807 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
808 attnum, relid);
809 return attname;
810 }
811
812 /*
813 * get_attnum
814 *
815 * Given the relation id and the attribute name,
816 * return the "attnum" field from the attribute relation.
817 *
818 * Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
819 */
820 AttrNumber
get_attnum(Oid relid,const char * attname)821 get_attnum(Oid relid, const char *attname)
822 {
823 HeapTuple tp;
824
825 tp = SearchSysCacheAttName(relid, attname);
826 if (HeapTupleIsValid(tp))
827 {
828 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
829 AttrNumber result;
830
831 result = att_tup->attnum;
832 ReleaseSysCache(tp);
833 return result;
834 }
835 else
836 return InvalidAttrNumber;
837 }
838
839 /*
840 * get_attidentity
841 *
842 * Given the relation id and the attribute name,
843 * return the "attidentity" field from the attribute relation.
844 *
845 * Returns '\0' if not found.
846 *
847 * Since no identity is represented by '\0', this can also be used as a
848 * Boolean test.
849 */
850 char
get_attidentity(Oid relid,AttrNumber attnum)851 get_attidentity(Oid relid, AttrNumber attnum)
852 {
853 HeapTuple tp;
854
855 tp = SearchSysCache2(ATTNUM,
856 ObjectIdGetDatum(relid),
857 Int16GetDatum(attnum));
858 if (HeapTupleIsValid(tp))
859 {
860 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
861 char result;
862
863 result = att_tup->attidentity;
864 ReleaseSysCache(tp);
865 return result;
866 }
867 else
868 return '\0';
869 }
870
871 /*
872 * get_atttype
873 *
874 * Given the relation OID and the attribute number with the relation,
875 * return the attribute type OID.
876 */
877 Oid
get_atttype(Oid relid,AttrNumber attnum)878 get_atttype(Oid relid, AttrNumber attnum)
879 {
880 HeapTuple tp;
881
882 tp = SearchSysCache2(ATTNUM,
883 ObjectIdGetDatum(relid),
884 Int16GetDatum(attnum));
885 if (HeapTupleIsValid(tp))
886 {
887 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
888 Oid result;
889
890 result = att_tup->atttypid;
891 ReleaseSysCache(tp);
892 return result;
893 }
894 else
895 return InvalidOid;
896 }
897
898 /*
899 * get_atttypmod
900 *
901 * Given the relation id and the attribute number,
902 * return the "atttypmod" field from the attribute relation.
903 */
904 int32
get_atttypmod(Oid relid,AttrNumber attnum)905 get_atttypmod(Oid relid, AttrNumber attnum)
906 {
907 HeapTuple tp;
908
909 tp = SearchSysCache2(ATTNUM,
910 ObjectIdGetDatum(relid),
911 Int16GetDatum(attnum));
912 if (HeapTupleIsValid(tp))
913 {
914 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
915 int32 result;
916
917 result = att_tup->atttypmod;
918 ReleaseSysCache(tp);
919 return result;
920 }
921 else
922 return -1;
923 }
924
925 /*
926 * get_atttypetypmodcoll
927 *
928 * A three-fer: given the relation id and the attribute number,
929 * fetch atttypid, atttypmod, and attcollation in a single cache lookup.
930 *
931 * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
932 * raises an error if it can't obtain the information.
933 */
934 void
get_atttypetypmodcoll(Oid relid,AttrNumber attnum,Oid * typid,int32 * typmod,Oid * collid)935 get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
936 Oid *typid, int32 *typmod, Oid *collid)
937 {
938 HeapTuple tp;
939 Form_pg_attribute att_tup;
940
941 tp = SearchSysCache2(ATTNUM,
942 ObjectIdGetDatum(relid),
943 Int16GetDatum(attnum));
944 if (!HeapTupleIsValid(tp))
945 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
946 attnum, relid);
947 att_tup = (Form_pg_attribute) GETSTRUCT(tp);
948
949 *typid = att_tup->atttypid;
950 *typmod = att_tup->atttypmod;
951 *collid = att_tup->attcollation;
952 ReleaseSysCache(tp);
953 }
954
955 /* ---------- COLLATION CACHE ---------- */
956
957 /*
958 * get_collation_name
959 * Returns the name of a given pg_collation entry.
960 *
961 * Returns a palloc'd copy of the string, or NULL if no such constraint.
962 *
963 * NOTE: since collation name is not unique, be wary of code that uses this
964 * for anything except preparing error messages.
965 */
966 char *
get_collation_name(Oid colloid)967 get_collation_name(Oid colloid)
968 {
969 HeapTuple tp;
970
971 tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
972 if (HeapTupleIsValid(tp))
973 {
974 Form_pg_collation colltup = (Form_pg_collation) GETSTRUCT(tp);
975 char *result;
976
977 result = pstrdup(NameStr(colltup->collname));
978 ReleaseSysCache(tp);
979 return result;
980 }
981 else
982 return NULL;
983 }
984
985 /* ---------- CONSTRAINT CACHE ---------- */
986
987 /*
988 * get_constraint_name
989 * Returns the name of a given pg_constraint entry.
990 *
991 * Returns a palloc'd copy of the string, or NULL if no such constraint.
992 *
993 * NOTE: since constraint name is not unique, be wary of code that uses this
994 * for anything except preparing error messages.
995 */
996 char *
get_constraint_name(Oid conoid)997 get_constraint_name(Oid conoid)
998 {
999 HeapTuple tp;
1000
1001 tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
1002 if (HeapTupleIsValid(tp))
1003 {
1004 Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
1005 char *result;
1006
1007 result = pstrdup(NameStr(contup->conname));
1008 ReleaseSysCache(tp);
1009 return result;
1010 }
1011 else
1012 return NULL;
1013 }
1014
1015 /* ---------- LANGUAGE CACHE ---------- */
1016
1017 char *
get_language_name(Oid langoid,bool missing_ok)1018 get_language_name(Oid langoid, bool missing_ok)
1019 {
1020 HeapTuple tp;
1021
1022 tp = SearchSysCache1(LANGOID, ObjectIdGetDatum(langoid));
1023 if (HeapTupleIsValid(tp))
1024 {
1025 Form_pg_language lantup = (Form_pg_language) GETSTRUCT(tp);
1026 char *result;
1027
1028 result = pstrdup(NameStr(lantup->lanname));
1029 ReleaseSysCache(tp);
1030 return result;
1031 }
1032
1033 if (!missing_ok)
1034 elog(ERROR, "cache lookup failed for language %u",
1035 langoid);
1036 return NULL;
1037 }
1038
1039 /* ---------- OPCLASS CACHE ---------- */
1040
1041 /*
1042 * get_opclass_family
1043 *
1044 * Returns the OID of the operator family the opclass belongs to.
1045 */
1046 Oid
get_opclass_family(Oid opclass)1047 get_opclass_family(Oid opclass)
1048 {
1049 HeapTuple tp;
1050 Form_pg_opclass cla_tup;
1051 Oid result;
1052
1053 tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
1054 if (!HeapTupleIsValid(tp))
1055 elog(ERROR, "cache lookup failed for opclass %u", opclass);
1056 cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1057
1058 result = cla_tup->opcfamily;
1059 ReleaseSysCache(tp);
1060 return result;
1061 }
1062
1063 /*
1064 * get_opclass_input_type
1065 *
1066 * Returns the OID of the datatype the opclass indexes.
1067 */
1068 Oid
get_opclass_input_type(Oid opclass)1069 get_opclass_input_type(Oid opclass)
1070 {
1071 HeapTuple tp;
1072 Form_pg_opclass cla_tup;
1073 Oid result;
1074
1075 tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
1076 if (!HeapTupleIsValid(tp))
1077 elog(ERROR, "cache lookup failed for opclass %u", opclass);
1078 cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1079
1080 result = cla_tup->opcintype;
1081 ReleaseSysCache(tp);
1082 return result;
1083 }
1084
1085 /* ---------- OPERATOR CACHE ---------- */
1086
1087 /*
1088 * get_opcode
1089 *
1090 * Returns the regproc id of the routine used to implement an
1091 * operator given the operator oid.
1092 */
1093 RegProcedure
get_opcode(Oid opno)1094 get_opcode(Oid opno)
1095 {
1096 HeapTuple tp;
1097
1098 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1099 if (HeapTupleIsValid(tp))
1100 {
1101 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1102 RegProcedure result;
1103
1104 result = optup->oprcode;
1105 ReleaseSysCache(tp);
1106 return result;
1107 }
1108 else
1109 return (RegProcedure) InvalidOid;
1110 }
1111
1112 /*
1113 * get_opname
1114 * returns the name of the operator with the given opno
1115 *
1116 * Note: returns a palloc'd copy of the string, or NULL if no such operator.
1117 */
1118 char *
get_opname(Oid opno)1119 get_opname(Oid opno)
1120 {
1121 HeapTuple tp;
1122
1123 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1124 if (HeapTupleIsValid(tp))
1125 {
1126 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1127 char *result;
1128
1129 result = pstrdup(NameStr(optup->oprname));
1130 ReleaseSysCache(tp);
1131 return result;
1132 }
1133 else
1134 return NULL;
1135 }
1136
1137 /*
1138 * get_op_rettype
1139 * Given operator oid, return the operator's result type.
1140 */
1141 Oid
get_op_rettype(Oid opno)1142 get_op_rettype(Oid opno)
1143 {
1144 HeapTuple tp;
1145
1146 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1147 if (HeapTupleIsValid(tp))
1148 {
1149 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1150 Oid result;
1151
1152 result = optup->oprresult;
1153 ReleaseSysCache(tp);
1154 return result;
1155 }
1156 else
1157 return InvalidOid;
1158 }
1159
1160 /*
1161 * op_input_types
1162 *
1163 * Returns the left and right input datatypes for an operator
1164 * (InvalidOid if not relevant).
1165 */
1166 void
op_input_types(Oid opno,Oid * lefttype,Oid * righttype)1167 op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
1168 {
1169 HeapTuple tp;
1170 Form_pg_operator optup;
1171
1172 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1173 if (!HeapTupleIsValid(tp)) /* shouldn't happen */
1174 elog(ERROR, "cache lookup failed for operator %u", opno);
1175 optup = (Form_pg_operator) GETSTRUCT(tp);
1176 *lefttype = optup->oprleft;
1177 *righttype = optup->oprright;
1178 ReleaseSysCache(tp);
1179 }
1180
1181 /*
1182 * op_mergejoinable
1183 *
1184 * Returns true if the operator is potentially mergejoinable. (The planner
1185 * will fail to find any mergejoin plans unless there are suitable btree
1186 * opfamily entries for this operator and associated sortops. The pg_operator
1187 * flag is just a hint to tell the planner whether to bother looking.)
1188 *
1189 * In some cases (currently only array_eq and record_eq), mergejoinability
1190 * depends on the specific input data type the operator is invoked for, so
1191 * that must be passed as well. We currently assume that only one input's type
1192 * is needed to check this --- by convention, pass the left input's data type.
1193 */
1194 bool
op_mergejoinable(Oid opno,Oid inputtype)1195 op_mergejoinable(Oid opno, Oid inputtype)
1196 {
1197 bool result = false;
1198 HeapTuple tp;
1199 TypeCacheEntry *typentry;
1200
1201 /*
1202 * For array_eq or record_eq, we can sort if the element or field types
1203 * are all sortable. We could implement all the checks for that here, but
1204 * the typcache already does that and caches the results too, so let's
1205 * rely on the typcache.
1206 */
1207 if (opno == ARRAY_EQ_OP)
1208 {
1209 typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
1210 if (typentry->cmp_proc == F_BTARRAYCMP)
1211 result = true;
1212 }
1213 else if (opno == RECORD_EQ_OP)
1214 {
1215 typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
1216 if (typentry->cmp_proc == F_BTRECORDCMP)
1217 result = true;
1218 }
1219 else
1220 {
1221 /* For all other operators, rely on pg_operator.oprcanmerge */
1222 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1223 if (HeapTupleIsValid(tp))
1224 {
1225 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1226
1227 result = optup->oprcanmerge;
1228 ReleaseSysCache(tp);
1229 }
1230 }
1231 return result;
1232 }
1233
1234 /*
1235 * op_hashjoinable
1236 *
1237 * Returns true if the operator is hashjoinable. (There must be a suitable
1238 * hash opfamily entry for this operator if it is so marked.)
1239 *
1240 * In some cases (currently only array_eq), hashjoinability depends on the
1241 * specific input data type the operator is invoked for, so that must be
1242 * passed as well. We currently assume that only one input's type is needed
1243 * to check this --- by convention, pass the left input's data type.
1244 */
1245 bool
op_hashjoinable(Oid opno,Oid inputtype)1246 op_hashjoinable(Oid opno, Oid inputtype)
1247 {
1248 bool result = false;
1249 HeapTuple tp;
1250 TypeCacheEntry *typentry;
1251
1252 /* As in op_mergejoinable, let the typcache handle the hard cases */
1253 /* Eventually we'll need a similar case for record_eq ... */
1254 if (opno == ARRAY_EQ_OP)
1255 {
1256 typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
1257 if (typentry->hash_proc == F_HASH_ARRAY)
1258 result = true;
1259 }
1260 else
1261 {
1262 /* For all other operators, rely on pg_operator.oprcanhash */
1263 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1264 if (HeapTupleIsValid(tp))
1265 {
1266 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1267
1268 result = optup->oprcanhash;
1269 ReleaseSysCache(tp);
1270 }
1271 }
1272 return result;
1273 }
1274
1275 /*
1276 * op_strict
1277 *
1278 * Get the proisstrict flag for the operator's underlying function.
1279 */
1280 bool
op_strict(Oid opno)1281 op_strict(Oid opno)
1282 {
1283 RegProcedure funcid = get_opcode(opno);
1284
1285 if (funcid == (RegProcedure) InvalidOid)
1286 elog(ERROR, "operator %u does not exist", opno);
1287
1288 return func_strict((Oid) funcid);
1289 }
1290
1291 /*
1292 * op_volatile
1293 *
1294 * Get the provolatile flag for the operator's underlying function.
1295 */
1296 char
op_volatile(Oid opno)1297 op_volatile(Oid opno)
1298 {
1299 RegProcedure funcid = get_opcode(opno);
1300
1301 if (funcid == (RegProcedure) InvalidOid)
1302 elog(ERROR, "operator %u does not exist", opno);
1303
1304 return func_volatile((Oid) funcid);
1305 }
1306
1307 /*
1308 * get_commutator
1309 *
1310 * Returns the corresponding commutator of an operator.
1311 */
1312 Oid
get_commutator(Oid opno)1313 get_commutator(Oid opno)
1314 {
1315 HeapTuple tp;
1316
1317 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1318 if (HeapTupleIsValid(tp))
1319 {
1320 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1321 Oid result;
1322
1323 result = optup->oprcom;
1324 ReleaseSysCache(tp);
1325 return result;
1326 }
1327 else
1328 return InvalidOid;
1329 }
1330
1331 /*
1332 * get_negator
1333 *
1334 * Returns the corresponding negator of an operator.
1335 */
1336 Oid
get_negator(Oid opno)1337 get_negator(Oid opno)
1338 {
1339 HeapTuple tp;
1340
1341 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1342 if (HeapTupleIsValid(tp))
1343 {
1344 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1345 Oid result;
1346
1347 result = optup->oprnegate;
1348 ReleaseSysCache(tp);
1349 return result;
1350 }
1351 else
1352 return InvalidOid;
1353 }
1354
1355 /*
1356 * get_oprrest
1357 *
1358 * Returns procedure id for computing selectivity of an operator.
1359 */
1360 RegProcedure
get_oprrest(Oid opno)1361 get_oprrest(Oid opno)
1362 {
1363 HeapTuple tp;
1364
1365 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1366 if (HeapTupleIsValid(tp))
1367 {
1368 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1369 RegProcedure result;
1370
1371 result = optup->oprrest;
1372 ReleaseSysCache(tp);
1373 return result;
1374 }
1375 else
1376 return (RegProcedure) InvalidOid;
1377 }
1378
1379 /*
1380 * get_oprjoin
1381 *
1382 * Returns procedure id for computing selectivity of a join.
1383 */
1384 RegProcedure
get_oprjoin(Oid opno)1385 get_oprjoin(Oid opno)
1386 {
1387 HeapTuple tp;
1388
1389 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1390 if (HeapTupleIsValid(tp))
1391 {
1392 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1393 RegProcedure result;
1394
1395 result = optup->oprjoin;
1396 ReleaseSysCache(tp);
1397 return result;
1398 }
1399 else
1400 return (RegProcedure) InvalidOid;
1401 }
1402
1403 /* ---------- FUNCTION CACHE ---------- */
1404
1405 /*
1406 * get_func_name
1407 * returns the name of the function with the given funcid
1408 *
1409 * Note: returns a palloc'd copy of the string, or NULL if no such function.
1410 */
1411 char *
get_func_name(Oid funcid)1412 get_func_name(Oid funcid)
1413 {
1414 HeapTuple tp;
1415
1416 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1417 if (HeapTupleIsValid(tp))
1418 {
1419 Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
1420 char *result;
1421
1422 result = pstrdup(NameStr(functup->proname));
1423 ReleaseSysCache(tp);
1424 return result;
1425 }
1426 else
1427 return NULL;
1428 }
1429
1430 /*
1431 * get_func_namespace
1432 *
1433 * Returns the pg_namespace OID associated with a given function.
1434 */
1435 Oid
get_func_namespace(Oid funcid)1436 get_func_namespace(Oid funcid)
1437 {
1438 HeapTuple tp;
1439
1440 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1441 if (HeapTupleIsValid(tp))
1442 {
1443 Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
1444 Oid result;
1445
1446 result = functup->pronamespace;
1447 ReleaseSysCache(tp);
1448 return result;
1449 }
1450 else
1451 return InvalidOid;
1452 }
1453
1454 /*
1455 * get_func_rettype
1456 * Given procedure id, return the function's result type.
1457 */
1458 Oid
get_func_rettype(Oid funcid)1459 get_func_rettype(Oid funcid)
1460 {
1461 HeapTuple tp;
1462 Oid result;
1463
1464 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1465 if (!HeapTupleIsValid(tp))
1466 elog(ERROR, "cache lookup failed for function %u", funcid);
1467
1468 result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
1469 ReleaseSysCache(tp);
1470 return result;
1471 }
1472
1473 /*
1474 * get_func_nargs
1475 * Given procedure id, return the number of arguments.
1476 */
1477 int
get_func_nargs(Oid funcid)1478 get_func_nargs(Oid funcid)
1479 {
1480 HeapTuple tp;
1481 int result;
1482
1483 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1484 if (!HeapTupleIsValid(tp))
1485 elog(ERROR, "cache lookup failed for function %u", funcid);
1486
1487 result = ((Form_pg_proc) GETSTRUCT(tp))->pronargs;
1488 ReleaseSysCache(tp);
1489 return result;
1490 }
1491
1492 /*
1493 * get_func_signature
1494 * Given procedure id, return the function's argument and result types.
1495 * (The return value is the result type.)
1496 *
1497 * The arguments are returned as a palloc'd array.
1498 */
1499 Oid
get_func_signature(Oid funcid,Oid ** argtypes,int * nargs)1500 get_func_signature(Oid funcid, Oid **argtypes, int *nargs)
1501 {
1502 HeapTuple tp;
1503 Form_pg_proc procstruct;
1504 Oid result;
1505
1506 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1507 if (!HeapTupleIsValid(tp))
1508 elog(ERROR, "cache lookup failed for function %u", funcid);
1509
1510 procstruct = (Form_pg_proc) GETSTRUCT(tp);
1511
1512 result = procstruct->prorettype;
1513 *nargs = (int) procstruct->pronargs;
1514 Assert(*nargs == procstruct->proargtypes.dim1);
1515 *argtypes = (Oid *) palloc(*nargs * sizeof(Oid));
1516 memcpy(*argtypes, procstruct->proargtypes.values, *nargs * sizeof(Oid));
1517
1518 ReleaseSysCache(tp);
1519 return result;
1520 }
1521
1522 /*
1523 * get_func_variadictype
1524 * Given procedure id, return the function's provariadic field.
1525 */
1526 Oid
get_func_variadictype(Oid funcid)1527 get_func_variadictype(Oid funcid)
1528 {
1529 HeapTuple tp;
1530 Oid result;
1531
1532 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1533 if (!HeapTupleIsValid(tp))
1534 elog(ERROR, "cache lookup failed for function %u", funcid);
1535
1536 result = ((Form_pg_proc) GETSTRUCT(tp))->provariadic;
1537 ReleaseSysCache(tp);
1538 return result;
1539 }
1540
1541 /*
1542 * get_func_retset
1543 * Given procedure id, return the function's proretset flag.
1544 */
1545 bool
get_func_retset(Oid funcid)1546 get_func_retset(Oid funcid)
1547 {
1548 HeapTuple tp;
1549 bool result;
1550
1551 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1552 if (!HeapTupleIsValid(tp))
1553 elog(ERROR, "cache lookup failed for function %u", funcid);
1554
1555 result = ((Form_pg_proc) GETSTRUCT(tp))->proretset;
1556 ReleaseSysCache(tp);
1557 return result;
1558 }
1559
1560 /*
1561 * func_strict
1562 * Given procedure id, return the function's proisstrict flag.
1563 */
1564 bool
func_strict(Oid funcid)1565 func_strict(Oid funcid)
1566 {
1567 HeapTuple tp;
1568 bool result;
1569
1570 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1571 if (!HeapTupleIsValid(tp))
1572 elog(ERROR, "cache lookup failed for function %u", funcid);
1573
1574 result = ((Form_pg_proc) GETSTRUCT(tp))->proisstrict;
1575 ReleaseSysCache(tp);
1576 return result;
1577 }
1578
1579 /*
1580 * func_volatile
1581 * Given procedure id, return the function's provolatile flag.
1582 */
1583 char
func_volatile(Oid funcid)1584 func_volatile(Oid funcid)
1585 {
1586 HeapTuple tp;
1587 char result;
1588
1589 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1590 if (!HeapTupleIsValid(tp))
1591 elog(ERROR, "cache lookup failed for function %u", funcid);
1592
1593 result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
1594 ReleaseSysCache(tp);
1595 return result;
1596 }
1597
1598 /*
1599 * func_parallel
1600 * Given procedure id, return the function's proparallel flag.
1601 */
1602 char
func_parallel(Oid funcid)1603 func_parallel(Oid funcid)
1604 {
1605 HeapTuple tp;
1606 char result;
1607
1608 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1609 if (!HeapTupleIsValid(tp))
1610 elog(ERROR, "cache lookup failed for function %u", funcid);
1611
1612 result = ((Form_pg_proc) GETSTRUCT(tp))->proparallel;
1613 ReleaseSysCache(tp);
1614 return result;
1615 }
1616
1617 /*
1618 * get_func_leakproof
1619 * Given procedure id, return the function's leakproof field.
1620 */
1621 bool
get_func_leakproof(Oid funcid)1622 get_func_leakproof(Oid funcid)
1623 {
1624 HeapTuple tp;
1625 bool result;
1626
1627 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1628 if (!HeapTupleIsValid(tp))
1629 elog(ERROR, "cache lookup failed for function %u", funcid);
1630
1631 result = ((Form_pg_proc) GETSTRUCT(tp))->proleakproof;
1632 ReleaseSysCache(tp);
1633 return result;
1634 }
1635
1636 /*
1637 * get_func_cost
1638 * Given procedure id, return the function's procost field.
1639 */
1640 float4
get_func_cost(Oid funcid)1641 get_func_cost(Oid funcid)
1642 {
1643 HeapTuple tp;
1644 float4 result;
1645
1646 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1647 if (!HeapTupleIsValid(tp))
1648 elog(ERROR, "cache lookup failed for function %u", funcid);
1649
1650 result = ((Form_pg_proc) GETSTRUCT(tp))->procost;
1651 ReleaseSysCache(tp);
1652 return result;
1653 }
1654
1655 /*
1656 * get_func_rows
1657 * Given procedure id, return the function's prorows field.
1658 */
1659 float4
get_func_rows(Oid funcid)1660 get_func_rows(Oid funcid)
1661 {
1662 HeapTuple tp;
1663 float4 result;
1664
1665 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1666 if (!HeapTupleIsValid(tp))
1667 elog(ERROR, "cache lookup failed for function %u", funcid);
1668
1669 result = ((Form_pg_proc) GETSTRUCT(tp))->prorows;
1670 ReleaseSysCache(tp);
1671 return result;
1672 }
1673
1674 /* ---------- RELATION CACHE ---------- */
1675
1676 /*
1677 * get_relname_relid
1678 * Given name and namespace of a relation, look up the OID.
1679 *
1680 * Returns InvalidOid if there is no such relation.
1681 */
1682 Oid
get_relname_relid(const char * relname,Oid relnamespace)1683 get_relname_relid(const char *relname, Oid relnamespace)
1684 {
1685 return GetSysCacheOid2(RELNAMENSP,
1686 PointerGetDatum(relname),
1687 ObjectIdGetDatum(relnamespace));
1688 }
1689
1690 #ifdef NOT_USED
1691 /*
1692 * get_relnatts
1693 *
1694 * Returns the number of attributes for a given relation.
1695 */
1696 int
get_relnatts(Oid relid)1697 get_relnatts(Oid relid)
1698 {
1699 HeapTuple tp;
1700
1701 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1702 if (HeapTupleIsValid(tp))
1703 {
1704 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1705 int result;
1706
1707 result = reltup->relnatts;
1708 ReleaseSysCache(tp);
1709 return result;
1710 }
1711 else
1712 return InvalidAttrNumber;
1713 }
1714 #endif
1715
1716 /*
1717 * get_rel_name
1718 * Returns the name of a given relation.
1719 *
1720 * Returns a palloc'd copy of the string, or NULL if no such relation.
1721 *
1722 * NOTE: since relation name is not unique, be wary of code that uses this
1723 * for anything except preparing error messages.
1724 */
1725 char *
get_rel_name(Oid relid)1726 get_rel_name(Oid relid)
1727 {
1728 HeapTuple tp;
1729
1730 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1731 if (HeapTupleIsValid(tp))
1732 {
1733 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1734 char *result;
1735
1736 result = pstrdup(NameStr(reltup->relname));
1737 ReleaseSysCache(tp);
1738 return result;
1739 }
1740 else
1741 return NULL;
1742 }
1743
1744 /*
1745 * get_rel_namespace
1746 *
1747 * Returns the pg_namespace OID associated with a given relation.
1748 */
1749 Oid
get_rel_namespace(Oid relid)1750 get_rel_namespace(Oid relid)
1751 {
1752 HeapTuple tp;
1753
1754 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1755 if (HeapTupleIsValid(tp))
1756 {
1757 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1758 Oid result;
1759
1760 result = reltup->relnamespace;
1761 ReleaseSysCache(tp);
1762 return result;
1763 }
1764 else
1765 return InvalidOid;
1766 }
1767
1768 /*
1769 * get_rel_type_id
1770 *
1771 * Returns the pg_type OID associated with a given relation.
1772 *
1773 * Note: not all pg_class entries have associated pg_type OIDs; so be
1774 * careful to check for InvalidOid result.
1775 */
1776 Oid
get_rel_type_id(Oid relid)1777 get_rel_type_id(Oid relid)
1778 {
1779 HeapTuple tp;
1780
1781 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1782 if (HeapTupleIsValid(tp))
1783 {
1784 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1785 Oid result;
1786
1787 result = reltup->reltype;
1788 ReleaseSysCache(tp);
1789 return result;
1790 }
1791 else
1792 return InvalidOid;
1793 }
1794
1795 /*
1796 * get_rel_relkind
1797 *
1798 * Returns the relkind associated with a given relation.
1799 */
1800 char
get_rel_relkind(Oid relid)1801 get_rel_relkind(Oid relid)
1802 {
1803 HeapTuple tp;
1804
1805 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1806 if (HeapTupleIsValid(tp))
1807 {
1808 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1809 char result;
1810
1811 result = reltup->relkind;
1812 ReleaseSysCache(tp);
1813 return result;
1814 }
1815 else
1816 return '\0';
1817 }
1818
1819 /*
1820 * get_rel_relispartition
1821 *
1822 * Returns the relispartition flag associated with a given relation.
1823 */
1824 bool
get_rel_relispartition(Oid relid)1825 get_rel_relispartition(Oid relid)
1826 {
1827 HeapTuple tp;
1828
1829 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1830 if (HeapTupleIsValid(tp))
1831 {
1832 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1833 bool result;
1834
1835 result = reltup->relispartition;
1836 ReleaseSysCache(tp);
1837 return result;
1838 }
1839 else
1840 return false;
1841 }
1842
1843 /*
1844 * get_rel_tablespace
1845 *
1846 * Returns the pg_tablespace OID associated with a given relation.
1847 *
1848 * Note: InvalidOid might mean either that we couldn't find the relation,
1849 * or that it is in the database's default tablespace.
1850 */
1851 Oid
get_rel_tablespace(Oid relid)1852 get_rel_tablespace(Oid relid)
1853 {
1854 HeapTuple tp;
1855
1856 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1857 if (HeapTupleIsValid(tp))
1858 {
1859 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1860 Oid result;
1861
1862 result = reltup->reltablespace;
1863 ReleaseSysCache(tp);
1864 return result;
1865 }
1866 else
1867 return InvalidOid;
1868 }
1869
1870 /*
1871 * get_rel_persistence
1872 *
1873 * Returns the relpersistence associated with a given relation.
1874 */
1875 char
get_rel_persistence(Oid relid)1876 get_rel_persistence(Oid relid)
1877 {
1878 HeapTuple tp;
1879 Form_pg_class reltup;
1880 char result;
1881
1882 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1883 if (!HeapTupleIsValid(tp))
1884 elog(ERROR, "cache lookup failed for relation %u", relid);
1885 reltup = (Form_pg_class) GETSTRUCT(tp);
1886 result = reltup->relpersistence;
1887 ReleaseSysCache(tp);
1888
1889 return result;
1890 }
1891
1892
1893 /* ---------- TRANSFORM CACHE ---------- */
1894
1895 Oid
get_transform_fromsql(Oid typid,Oid langid,List * trftypes)1896 get_transform_fromsql(Oid typid, Oid langid, List *trftypes)
1897 {
1898 HeapTuple tup;
1899
1900 if (!list_member_oid(trftypes, typid))
1901 return InvalidOid;
1902
1903 tup = SearchSysCache2(TRFTYPELANG, typid, langid);
1904 if (HeapTupleIsValid(tup))
1905 {
1906 Oid funcid;
1907
1908 funcid = ((Form_pg_transform) GETSTRUCT(tup))->trffromsql;
1909 ReleaseSysCache(tup);
1910 return funcid;
1911 }
1912 else
1913 return InvalidOid;
1914 }
1915
1916 Oid
get_transform_tosql(Oid typid,Oid langid,List * trftypes)1917 get_transform_tosql(Oid typid, Oid langid, List *trftypes)
1918 {
1919 HeapTuple tup;
1920
1921 if (!list_member_oid(trftypes, typid))
1922 return InvalidOid;
1923
1924 tup = SearchSysCache2(TRFTYPELANG, typid, langid);
1925 if (HeapTupleIsValid(tup))
1926 {
1927 Oid funcid;
1928
1929 funcid = ((Form_pg_transform) GETSTRUCT(tup))->trftosql;
1930 ReleaseSysCache(tup);
1931 return funcid;
1932 }
1933 else
1934 return InvalidOid;
1935 }
1936
1937
1938 /* ---------- TYPE CACHE ---------- */
1939
1940 /*
1941 * get_typisdefined
1942 *
1943 * Given the type OID, determine whether the type is defined
1944 * (if not, it's only a shell).
1945 */
1946 bool
get_typisdefined(Oid typid)1947 get_typisdefined(Oid typid)
1948 {
1949 HeapTuple tp;
1950
1951 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1952 if (HeapTupleIsValid(tp))
1953 {
1954 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1955 bool result;
1956
1957 result = typtup->typisdefined;
1958 ReleaseSysCache(tp);
1959 return result;
1960 }
1961 else
1962 return false;
1963 }
1964
1965 /*
1966 * get_typlen
1967 *
1968 * Given the type OID, return the length of the type.
1969 */
1970 int16
get_typlen(Oid typid)1971 get_typlen(Oid typid)
1972 {
1973 HeapTuple tp;
1974
1975 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1976 if (HeapTupleIsValid(tp))
1977 {
1978 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1979 int16 result;
1980
1981 result = typtup->typlen;
1982 ReleaseSysCache(tp);
1983 return result;
1984 }
1985 else
1986 return 0;
1987 }
1988
1989 /*
1990 * get_typbyval
1991 *
1992 * Given the type OID, determine whether the type is returned by value or
1993 * not. Returns true if by value, false if by reference.
1994 */
1995 bool
get_typbyval(Oid typid)1996 get_typbyval(Oid typid)
1997 {
1998 HeapTuple tp;
1999
2000 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2001 if (HeapTupleIsValid(tp))
2002 {
2003 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2004 bool result;
2005
2006 result = typtup->typbyval;
2007 ReleaseSysCache(tp);
2008 return result;
2009 }
2010 else
2011 return false;
2012 }
2013
2014 /*
2015 * get_typlenbyval
2016 *
2017 * A two-fer: given the type OID, return both typlen and typbyval.
2018 *
2019 * Since both pieces of info are needed to know how to copy a Datum,
2020 * many places need both. Might as well get them with one cache lookup
2021 * instead of two. Also, this routine raises an error instead of
2022 * returning a bogus value when given a bad type OID.
2023 */
2024 void
get_typlenbyval(Oid typid,int16 * typlen,bool * typbyval)2025 get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
2026 {
2027 HeapTuple tp;
2028 Form_pg_type typtup;
2029
2030 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2031 if (!HeapTupleIsValid(tp))
2032 elog(ERROR, "cache lookup failed for type %u", typid);
2033 typtup = (Form_pg_type) GETSTRUCT(tp);
2034 *typlen = typtup->typlen;
2035 *typbyval = typtup->typbyval;
2036 ReleaseSysCache(tp);
2037 }
2038
2039 /*
2040 * get_typlenbyvalalign
2041 *
2042 * A three-fer: given the type OID, return typlen, typbyval, typalign.
2043 */
2044 void
get_typlenbyvalalign(Oid typid,int16 * typlen,bool * typbyval,char * typalign)2045 get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
2046 char *typalign)
2047 {
2048 HeapTuple tp;
2049 Form_pg_type typtup;
2050
2051 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2052 if (!HeapTupleIsValid(tp))
2053 elog(ERROR, "cache lookup failed for type %u", typid);
2054 typtup = (Form_pg_type) GETSTRUCT(tp);
2055 *typlen = typtup->typlen;
2056 *typbyval = typtup->typbyval;
2057 *typalign = typtup->typalign;
2058 ReleaseSysCache(tp);
2059 }
2060
2061 /*
2062 * getTypeIOParam
2063 * Given a pg_type row, select the type OID to pass to I/O functions
2064 *
2065 * Formerly, all I/O functions were passed pg_type.typelem as their second
2066 * parameter, but we now have a more complex rule about what to pass.
2067 * This knowledge is intended to be centralized here --- direct references
2068 * to typelem elsewhere in the code are wrong, if they are associated with
2069 * I/O calls and not with actual subscripting operations! (But see
2070 * bootstrap.c's boot_get_type_io_data() if you need to change this.)
2071 *
2072 * As of PostgreSQL 8.1, output functions receive only the value itself
2073 * and not any auxiliary parameters, so the name of this routine is now
2074 * a bit of a misnomer ... it should be getTypeInputParam.
2075 */
2076 Oid
getTypeIOParam(HeapTuple typeTuple)2077 getTypeIOParam(HeapTuple typeTuple)
2078 {
2079 Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
2080
2081 /*
2082 * Array types get their typelem as parameter; everybody else gets their
2083 * own type OID as parameter.
2084 */
2085 if (OidIsValid(typeStruct->typelem))
2086 return typeStruct->typelem;
2087 else
2088 return HeapTupleGetOid(typeTuple);
2089 }
2090
2091 /*
2092 * get_type_io_data
2093 *
2094 * A six-fer: given the type OID, return typlen, typbyval, typalign,
2095 * typdelim, typioparam, and IO function OID. The IO function
2096 * returned is controlled by IOFuncSelector
2097 */
2098 void
get_type_io_data(Oid typid,IOFuncSelector which_func,int16 * typlen,bool * typbyval,char * typalign,char * typdelim,Oid * typioparam,Oid * func)2099 get_type_io_data(Oid typid,
2100 IOFuncSelector which_func,
2101 int16 *typlen,
2102 bool *typbyval,
2103 char *typalign,
2104 char *typdelim,
2105 Oid *typioparam,
2106 Oid *func)
2107 {
2108 HeapTuple typeTuple;
2109 Form_pg_type typeStruct;
2110
2111 /*
2112 * In bootstrap mode, pass it off to bootstrap.c. This hack allows us to
2113 * use array_in and array_out during bootstrap.
2114 */
2115 if (IsBootstrapProcessingMode())
2116 {
2117 Oid typinput;
2118 Oid typoutput;
2119
2120 boot_get_type_io_data(typid,
2121 typlen,
2122 typbyval,
2123 typalign,
2124 typdelim,
2125 typioparam,
2126 &typinput,
2127 &typoutput);
2128 switch (which_func)
2129 {
2130 case IOFunc_input:
2131 *func = typinput;
2132 break;
2133 case IOFunc_output:
2134 *func = typoutput;
2135 break;
2136 default:
2137 elog(ERROR, "binary I/O not supported during bootstrap");
2138 break;
2139 }
2140 return;
2141 }
2142
2143 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2144 if (!HeapTupleIsValid(typeTuple))
2145 elog(ERROR, "cache lookup failed for type %u", typid);
2146 typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
2147
2148 *typlen = typeStruct->typlen;
2149 *typbyval = typeStruct->typbyval;
2150 *typalign = typeStruct->typalign;
2151 *typdelim = typeStruct->typdelim;
2152 *typioparam = getTypeIOParam(typeTuple);
2153 switch (which_func)
2154 {
2155 case IOFunc_input:
2156 *func = typeStruct->typinput;
2157 break;
2158 case IOFunc_output:
2159 *func = typeStruct->typoutput;
2160 break;
2161 case IOFunc_receive:
2162 *func = typeStruct->typreceive;
2163 break;
2164 case IOFunc_send:
2165 *func = typeStruct->typsend;
2166 break;
2167 }
2168 ReleaseSysCache(typeTuple);
2169 }
2170
2171 #ifdef NOT_USED
2172 char
get_typalign(Oid typid)2173 get_typalign(Oid typid)
2174 {
2175 HeapTuple tp;
2176
2177 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2178 if (HeapTupleIsValid(tp))
2179 {
2180 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2181 char result;
2182
2183 result = typtup->typalign;
2184 ReleaseSysCache(tp);
2185 return result;
2186 }
2187 else
2188 return 'i';
2189 }
2190 #endif
2191
2192 char
get_typstorage(Oid typid)2193 get_typstorage(Oid typid)
2194 {
2195 HeapTuple tp;
2196
2197 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2198 if (HeapTupleIsValid(tp))
2199 {
2200 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2201 char result;
2202
2203 result = typtup->typstorage;
2204 ReleaseSysCache(tp);
2205 return result;
2206 }
2207 else
2208 return 'p';
2209 }
2210
2211 /*
2212 * get_typdefault
2213 * Given a type OID, return the type's default value, if any.
2214 *
2215 * The result is a palloc'd expression node tree, or NULL if there
2216 * is no defined default for the datatype.
2217 *
2218 * NB: caller should be prepared to coerce result to correct datatype;
2219 * the returned expression tree might produce something of the wrong type.
2220 */
2221 Node *
get_typdefault(Oid typid)2222 get_typdefault(Oid typid)
2223 {
2224 HeapTuple typeTuple;
2225 Form_pg_type type;
2226 Datum datum;
2227 bool isNull;
2228 Node *expr;
2229
2230 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2231 if (!HeapTupleIsValid(typeTuple))
2232 elog(ERROR, "cache lookup failed for type %u", typid);
2233 type = (Form_pg_type) GETSTRUCT(typeTuple);
2234
2235 /*
2236 * typdefault and typdefaultbin are potentially null, so don't try to
2237 * access 'em as struct fields. Must do it the hard way with
2238 * SysCacheGetAttr.
2239 */
2240 datum = SysCacheGetAttr(TYPEOID,
2241 typeTuple,
2242 Anum_pg_type_typdefaultbin,
2243 &isNull);
2244
2245 if (!isNull)
2246 {
2247 /* We have an expression default */
2248 expr = stringToNode(TextDatumGetCString(datum));
2249 }
2250 else
2251 {
2252 /* Perhaps we have a plain literal default */
2253 datum = SysCacheGetAttr(TYPEOID,
2254 typeTuple,
2255 Anum_pg_type_typdefault,
2256 &isNull);
2257
2258 if (!isNull)
2259 {
2260 char *strDefaultVal;
2261
2262 /* Convert text datum to C string */
2263 strDefaultVal = TextDatumGetCString(datum);
2264 /* Convert C string to a value of the given type */
2265 datum = OidInputFunctionCall(type->typinput, strDefaultVal,
2266 getTypeIOParam(typeTuple), -1);
2267 /* Build a Const node containing the value */
2268 expr = (Node *) makeConst(typid,
2269 -1,
2270 type->typcollation,
2271 type->typlen,
2272 datum,
2273 false,
2274 type->typbyval);
2275 pfree(strDefaultVal);
2276 }
2277 else
2278 {
2279 /* No default */
2280 expr = NULL;
2281 }
2282 }
2283
2284 ReleaseSysCache(typeTuple);
2285
2286 return expr;
2287 }
2288
2289 /*
2290 * getBaseType
2291 * If the given type is a domain, return its base type;
2292 * otherwise return the type's own OID.
2293 */
2294 Oid
getBaseType(Oid typid)2295 getBaseType(Oid typid)
2296 {
2297 int32 typmod = -1;
2298
2299 return getBaseTypeAndTypmod(typid, &typmod);
2300 }
2301
2302 /*
2303 * getBaseTypeAndTypmod
2304 * If the given type is a domain, return its base type and typmod;
2305 * otherwise return the type's own OID, and leave *typmod unchanged.
2306 *
2307 * Note that the "applied typmod" should be -1 for every domain level
2308 * above the bottommost; therefore, if the passed-in typid is indeed
2309 * a domain, *typmod should be -1.
2310 */
2311 Oid
getBaseTypeAndTypmod(Oid typid,int32 * typmod)2312 getBaseTypeAndTypmod(Oid typid, int32 *typmod)
2313 {
2314 /*
2315 * We loop to find the bottom base type in a stack of domains.
2316 */
2317 for (;;)
2318 {
2319 HeapTuple tup;
2320 Form_pg_type typTup;
2321
2322 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2323 if (!HeapTupleIsValid(tup))
2324 elog(ERROR, "cache lookup failed for type %u", typid);
2325 typTup = (Form_pg_type) GETSTRUCT(tup);
2326 if (typTup->typtype != TYPTYPE_DOMAIN)
2327 {
2328 /* Not a domain, so done */
2329 ReleaseSysCache(tup);
2330 break;
2331 }
2332
2333 Assert(*typmod == -1);
2334 typid = typTup->typbasetype;
2335 *typmod = typTup->typtypmod;
2336
2337 ReleaseSysCache(tup);
2338 }
2339
2340 return typid;
2341 }
2342
2343 /*
2344 * get_typavgwidth
2345 *
2346 * Given a type OID and a typmod value (pass -1 if typmod is unknown),
2347 * estimate the average width of values of the type. This is used by
2348 * the planner, which doesn't require absolutely correct results;
2349 * it's OK (and expected) to guess if we don't know for sure.
2350 */
2351 int32
get_typavgwidth(Oid typid,int32 typmod)2352 get_typavgwidth(Oid typid, int32 typmod)
2353 {
2354 int typlen = get_typlen(typid);
2355 int32 maxwidth;
2356
2357 /*
2358 * Easy if it's a fixed-width type
2359 */
2360 if (typlen > 0)
2361 return typlen;
2362
2363 /*
2364 * type_maximum_size knows the encoding of typmod for some datatypes;
2365 * don't duplicate that knowledge here.
2366 */
2367 maxwidth = type_maximum_size(typid, typmod);
2368 if (maxwidth > 0)
2369 {
2370 /*
2371 * For BPCHAR, the max width is also the only width. Otherwise we
2372 * need to guess about the typical data width given the max. A sliding
2373 * scale for percentage of max width seems reasonable.
2374 */
2375 if (typid == BPCHAROID)
2376 return maxwidth;
2377 if (maxwidth <= 32)
2378 return maxwidth; /* assume full width */
2379 if (maxwidth < 1000)
2380 return 32 + (maxwidth - 32) / 2; /* assume 50% */
2381
2382 /*
2383 * Beyond 1000, assume we're looking at something like
2384 * "varchar(10000)" where the limit isn't actually reached often, and
2385 * use a fixed estimate.
2386 */
2387 return 32 + (1000 - 32) / 2;
2388 }
2389
2390 /*
2391 * Oops, we have no idea ... wild guess time.
2392 */
2393 return 32;
2394 }
2395
2396 /*
2397 * get_typtype
2398 *
2399 * Given the type OID, find if it is a basic type, a complex type, etc.
2400 * It returns the null char if the cache lookup fails...
2401 */
2402 char
get_typtype(Oid typid)2403 get_typtype(Oid typid)
2404 {
2405 HeapTuple tp;
2406
2407 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2408 if (HeapTupleIsValid(tp))
2409 {
2410 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2411 char result;
2412
2413 result = typtup->typtype;
2414 ReleaseSysCache(tp);
2415 return result;
2416 }
2417 else
2418 return '\0';
2419 }
2420
2421 /*
2422 * type_is_rowtype
2423 *
2424 * Convenience function to determine whether a type OID represents
2425 * a "rowtype" type --- either RECORD or a named composite type.
2426 */
2427 bool
type_is_rowtype(Oid typid)2428 type_is_rowtype(Oid typid)
2429 {
2430 return (typid == RECORDOID || get_typtype(typid) == TYPTYPE_COMPOSITE);
2431 }
2432
2433 /*
2434 * type_is_enum
2435 * Returns true if the given type is an enum type.
2436 */
2437 bool
type_is_enum(Oid typid)2438 type_is_enum(Oid typid)
2439 {
2440 return (get_typtype(typid) == TYPTYPE_ENUM);
2441 }
2442
2443 /*
2444 * type_is_range
2445 * Returns true if the given type is a range type.
2446 */
2447 bool
type_is_range(Oid typid)2448 type_is_range(Oid typid)
2449 {
2450 return (get_typtype(typid) == TYPTYPE_RANGE);
2451 }
2452
2453 /*
2454 * get_type_category_preferred
2455 *
2456 * Given the type OID, fetch its category and preferred-type status.
2457 * Throws error on failure.
2458 */
2459 void
get_type_category_preferred(Oid typid,char * typcategory,bool * typispreferred)2460 get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
2461 {
2462 HeapTuple tp;
2463 Form_pg_type typtup;
2464
2465 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2466 if (!HeapTupleIsValid(tp))
2467 elog(ERROR, "cache lookup failed for type %u", typid);
2468 typtup = (Form_pg_type) GETSTRUCT(tp);
2469 *typcategory = typtup->typcategory;
2470 *typispreferred = typtup->typispreferred;
2471 ReleaseSysCache(tp);
2472 }
2473
2474 /*
2475 * get_typ_typrelid
2476 *
2477 * Given the type OID, get the typrelid (InvalidOid if not a complex
2478 * type).
2479 */
2480 Oid
get_typ_typrelid(Oid typid)2481 get_typ_typrelid(Oid typid)
2482 {
2483 HeapTuple tp;
2484
2485 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2486 if (HeapTupleIsValid(tp))
2487 {
2488 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2489 Oid result;
2490
2491 result = typtup->typrelid;
2492 ReleaseSysCache(tp);
2493 return result;
2494 }
2495 else
2496 return InvalidOid;
2497 }
2498
2499 /*
2500 * get_element_type
2501 *
2502 * Given the type OID, get the typelem (InvalidOid if not an array type).
2503 *
2504 * NB: this only considers varlena arrays to be true arrays; InvalidOid is
2505 * returned if the input is a fixed-length array type.
2506 */
2507 Oid
get_element_type(Oid typid)2508 get_element_type(Oid typid)
2509 {
2510 HeapTuple tp;
2511
2512 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2513 if (HeapTupleIsValid(tp))
2514 {
2515 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2516 Oid result;
2517
2518 if (typtup->typlen == -1)
2519 result = typtup->typelem;
2520 else
2521 result = InvalidOid;
2522 ReleaseSysCache(tp);
2523 return result;
2524 }
2525 else
2526 return InvalidOid;
2527 }
2528
2529 /*
2530 * get_array_type
2531 *
2532 * Given the type OID, get the corresponding "true" array type.
2533 * Returns InvalidOid if no array type can be found.
2534 */
2535 Oid
get_array_type(Oid typid)2536 get_array_type(Oid typid)
2537 {
2538 HeapTuple tp;
2539 Oid result = InvalidOid;
2540
2541 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2542 if (HeapTupleIsValid(tp))
2543 {
2544 result = ((Form_pg_type) GETSTRUCT(tp))->typarray;
2545 ReleaseSysCache(tp);
2546 }
2547 return result;
2548 }
2549
2550 /*
2551 * get_promoted_array_type
2552 *
2553 * The "promoted" type is what you'd get from an ARRAY(SELECT ...)
2554 * construct, that is, either the corresponding "true" array type
2555 * if the input is a scalar type that has such an array type,
2556 * or the same type if the input is already a "true" array type.
2557 * Returns InvalidOid if neither rule is satisfied.
2558 */
2559 Oid
get_promoted_array_type(Oid typid)2560 get_promoted_array_type(Oid typid)
2561 {
2562 Oid array_type = get_array_type(typid);
2563
2564 if (OidIsValid(array_type))
2565 return array_type;
2566 if (OidIsValid(get_element_type(typid)))
2567 return typid;
2568 return InvalidOid;
2569 }
2570
2571 /*
2572 * get_base_element_type
2573 * Given the type OID, get the typelem, looking "through" any domain
2574 * to its underlying array type.
2575 *
2576 * This is equivalent to get_element_type(getBaseType(typid)), but avoids
2577 * an extra cache lookup. Note that it fails to provide any information
2578 * about the typmod of the array.
2579 */
2580 Oid
get_base_element_type(Oid typid)2581 get_base_element_type(Oid typid)
2582 {
2583 /*
2584 * We loop to find the bottom base type in a stack of domains.
2585 */
2586 for (;;)
2587 {
2588 HeapTuple tup;
2589 Form_pg_type typTup;
2590
2591 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2592 if (!HeapTupleIsValid(tup))
2593 break;
2594 typTup = (Form_pg_type) GETSTRUCT(tup);
2595 if (typTup->typtype != TYPTYPE_DOMAIN)
2596 {
2597 /* Not a domain, so stop descending */
2598 Oid result;
2599
2600 /* This test must match get_element_type */
2601 if (typTup->typlen == -1)
2602 result = typTup->typelem;
2603 else
2604 result = InvalidOid;
2605 ReleaseSysCache(tup);
2606 return result;
2607 }
2608
2609 typid = typTup->typbasetype;
2610 ReleaseSysCache(tup);
2611 }
2612
2613 /* Like get_element_type, silently return InvalidOid for bogus input */
2614 return InvalidOid;
2615 }
2616
2617 /*
2618 * getTypeInputInfo
2619 *
2620 * Get info needed for converting values of a type to internal form
2621 */
2622 void
getTypeInputInfo(Oid type,Oid * typInput,Oid * typIOParam)2623 getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
2624 {
2625 HeapTuple typeTuple;
2626 Form_pg_type pt;
2627
2628 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
2629 if (!HeapTupleIsValid(typeTuple))
2630 elog(ERROR, "cache lookup failed for type %u", type);
2631 pt = (Form_pg_type) GETSTRUCT(typeTuple);
2632
2633 if (!pt->typisdefined)
2634 ereport(ERROR,
2635 (errcode(ERRCODE_UNDEFINED_OBJECT),
2636 errmsg("type %s is only a shell",
2637 format_type_be(type))));
2638 if (!OidIsValid(pt->typinput))
2639 ereport(ERROR,
2640 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2641 errmsg("no input function available for type %s",
2642 format_type_be(type))));
2643
2644 *typInput = pt->typinput;
2645 *typIOParam = getTypeIOParam(typeTuple);
2646
2647 ReleaseSysCache(typeTuple);
2648 }
2649
2650 /*
2651 * getTypeOutputInfo
2652 *
2653 * Get info needed for printing values of a type
2654 */
2655 void
getTypeOutputInfo(Oid type,Oid * typOutput,bool * typIsVarlena)2656 getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
2657 {
2658 HeapTuple typeTuple;
2659 Form_pg_type pt;
2660
2661 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
2662 if (!HeapTupleIsValid(typeTuple))
2663 elog(ERROR, "cache lookup failed for type %u", type);
2664 pt = (Form_pg_type) GETSTRUCT(typeTuple);
2665
2666 if (!pt->typisdefined)
2667 ereport(ERROR,
2668 (errcode(ERRCODE_UNDEFINED_OBJECT),
2669 errmsg("type %s is only a shell",
2670 format_type_be(type))));
2671 if (!OidIsValid(pt->typoutput))
2672 ereport(ERROR,
2673 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2674 errmsg("no output function available for type %s",
2675 format_type_be(type))));
2676
2677 *typOutput = pt->typoutput;
2678 *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
2679
2680 ReleaseSysCache(typeTuple);
2681 }
2682
2683 /*
2684 * getTypeBinaryInputInfo
2685 *
2686 * Get info needed for binary input of values of a type
2687 */
2688 void
getTypeBinaryInputInfo(Oid type,Oid * typReceive,Oid * typIOParam)2689 getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
2690 {
2691 HeapTuple typeTuple;
2692 Form_pg_type pt;
2693
2694 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
2695 if (!HeapTupleIsValid(typeTuple))
2696 elog(ERROR, "cache lookup failed for type %u", type);
2697 pt = (Form_pg_type) GETSTRUCT(typeTuple);
2698
2699 if (!pt->typisdefined)
2700 ereport(ERROR,
2701 (errcode(ERRCODE_UNDEFINED_OBJECT),
2702 errmsg("type %s is only a shell",
2703 format_type_be(type))));
2704 if (!OidIsValid(pt->typreceive))
2705 ereport(ERROR,
2706 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2707 errmsg("no binary input function available for type %s",
2708 format_type_be(type))));
2709
2710 *typReceive = pt->typreceive;
2711 *typIOParam = getTypeIOParam(typeTuple);
2712
2713 ReleaseSysCache(typeTuple);
2714 }
2715
2716 /*
2717 * getTypeBinaryOutputInfo
2718 *
2719 * Get info needed for binary output of values of a type
2720 */
2721 void
getTypeBinaryOutputInfo(Oid type,Oid * typSend,bool * typIsVarlena)2722 getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
2723 {
2724 HeapTuple typeTuple;
2725 Form_pg_type pt;
2726
2727 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
2728 if (!HeapTupleIsValid(typeTuple))
2729 elog(ERROR, "cache lookup failed for type %u", type);
2730 pt = (Form_pg_type) GETSTRUCT(typeTuple);
2731
2732 if (!pt->typisdefined)
2733 ereport(ERROR,
2734 (errcode(ERRCODE_UNDEFINED_OBJECT),
2735 errmsg("type %s is only a shell",
2736 format_type_be(type))));
2737 if (!OidIsValid(pt->typsend))
2738 ereport(ERROR,
2739 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2740 errmsg("no binary output function available for type %s",
2741 format_type_be(type))));
2742
2743 *typSend = pt->typsend;
2744 *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
2745
2746 ReleaseSysCache(typeTuple);
2747 }
2748
2749 /*
2750 * get_typmodin
2751 *
2752 * Given the type OID, return the type's typmodin procedure, if any.
2753 */
2754 Oid
get_typmodin(Oid typid)2755 get_typmodin(Oid typid)
2756 {
2757 HeapTuple tp;
2758
2759 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2760 if (HeapTupleIsValid(tp))
2761 {
2762 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2763 Oid result;
2764
2765 result = typtup->typmodin;
2766 ReleaseSysCache(tp);
2767 return result;
2768 }
2769 else
2770 return InvalidOid;
2771 }
2772
2773 #ifdef NOT_USED
2774 /*
2775 * get_typmodout
2776 *
2777 * Given the type OID, return the type's typmodout procedure, if any.
2778 */
2779 Oid
get_typmodout(Oid typid)2780 get_typmodout(Oid typid)
2781 {
2782 HeapTuple tp;
2783
2784 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2785 if (HeapTupleIsValid(tp))
2786 {
2787 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2788 Oid result;
2789
2790 result = typtup->typmodout;
2791 ReleaseSysCache(tp);
2792 return result;
2793 }
2794 else
2795 return InvalidOid;
2796 }
2797 #endif /* NOT_USED */
2798
2799 /*
2800 * get_typcollation
2801 *
2802 * Given the type OID, return the type's typcollation attribute.
2803 */
2804 Oid
get_typcollation(Oid typid)2805 get_typcollation(Oid typid)
2806 {
2807 HeapTuple tp;
2808
2809 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2810 if (HeapTupleIsValid(tp))
2811 {
2812 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2813 Oid result;
2814
2815 result = typtup->typcollation;
2816 ReleaseSysCache(tp);
2817 return result;
2818 }
2819 else
2820 return InvalidOid;
2821 }
2822
2823
2824 /*
2825 * type_is_collatable
2826 *
2827 * Return whether the type cares about collations
2828 */
2829 bool
type_is_collatable(Oid typid)2830 type_is_collatable(Oid typid)
2831 {
2832 return OidIsValid(get_typcollation(typid));
2833 }
2834
2835
2836 /* ---------- STATISTICS CACHE ---------- */
2837
2838 /*
2839 * get_attavgwidth
2840 *
2841 * Given the table and attribute number of a column, get the average
2842 * width of entries in the column. Return zero if no data available.
2843 *
2844 * Currently this is only consulted for individual tables, not for inheritance
2845 * trees, so we don't need an "inh" parameter.
2846 *
2847 * Calling a hook at this point looks somewhat strange, but is required
2848 * because the optimizer calls this function without any other way for
2849 * plug-ins to control the result.
2850 */
2851 int32
get_attavgwidth(Oid relid,AttrNumber attnum)2852 get_attavgwidth(Oid relid, AttrNumber attnum)
2853 {
2854 HeapTuple tp;
2855 int32 stawidth;
2856
2857 if (get_attavgwidth_hook)
2858 {
2859 stawidth = (*get_attavgwidth_hook) (relid, attnum);
2860 if (stawidth > 0)
2861 return stawidth;
2862 }
2863 tp = SearchSysCache3(STATRELATTINH,
2864 ObjectIdGetDatum(relid),
2865 Int16GetDatum(attnum),
2866 BoolGetDatum(false));
2867 if (HeapTupleIsValid(tp))
2868 {
2869 stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
2870 ReleaseSysCache(tp);
2871 if (stawidth > 0)
2872 return stawidth;
2873 }
2874 return 0;
2875 }
2876
2877 /*
2878 * get_attstatsslot
2879 *
2880 * Extract the contents of a "slot" of a pg_statistic tuple.
2881 * Returns TRUE if requested slot type was found, else FALSE.
2882 *
2883 * Unlike other routines in this file, this takes a pointer to an
2884 * already-looked-up tuple in the pg_statistic cache. We do this since
2885 * most callers will want to extract more than one value from the cache
2886 * entry, and we don't want to repeat the cache lookup unnecessarily.
2887 * Also, this API allows this routine to be used with statistics tuples
2888 * that have been provided by a stats hook and didn't really come from
2889 * pg_statistic.
2890 *
2891 * sslot: pointer to output area (typically, a local variable in the caller).
2892 * statstuple: pg_statistic tuple to be examined.
2893 * reqkind: STAKIND code for desired statistics slot kind.
2894 * reqop: STAOP value wanted, or InvalidOid if don't care.
2895 * flags: bitmask of ATTSTATSSLOT_VALUES and/or ATTSTATSSLOT_NUMBERS.
2896 *
2897 * If a matching slot is found, TRUE is returned, and *sslot is filled thus:
2898 * staop: receives the actual STAOP value.
2899 * valuetype: receives actual datatype of the elements of stavalues.
2900 * values: receives pointer to an array of the slot's stavalues.
2901 * nvalues: receives number of stavalues.
2902 * numbers: receives pointer to an array of the slot's stanumbers (as float4).
2903 * nnumbers: receives number of stanumbers.
2904 *
2905 * valuetype/values/nvalues are InvalidOid/NULL/0 if ATTSTATSSLOT_VALUES
2906 * wasn't specified. Likewise, numbers/nnumbers are NULL/0 if
2907 * ATTSTATSSLOT_NUMBERS wasn't specified.
2908 *
2909 * If no matching slot is found, FALSE is returned, and *sslot is zeroed.
2910 *
2911 * The data referred to by the fields of sslot is locally palloc'd and
2912 * is independent of the original pg_statistic tuple. When the caller
2913 * is done with it, call free_attstatsslot to release the palloc'd data.
2914 *
2915 * If it's desirable to call free_attstatsslot when get_attstatsslot might
2916 * not have been called, memset'ing sslot to zeroes will allow that.
2917 */
2918 bool
get_attstatsslot(AttStatsSlot * sslot,HeapTuple statstuple,int reqkind,Oid reqop,int flags)2919 get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple,
2920 int reqkind, Oid reqop, int flags)
2921 {
2922 Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
2923 int i;
2924 Datum val;
2925 bool isnull;
2926 ArrayType *statarray;
2927 Oid arrayelemtype;
2928 int narrayelem;
2929 HeapTuple typeTuple;
2930 Form_pg_type typeForm;
2931
2932 /* initialize *sslot properly */
2933 memset(sslot, 0, sizeof(AttStatsSlot));
2934
2935 for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
2936 {
2937 if ((&stats->stakind1)[i] == reqkind &&
2938 (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
2939 break;
2940 }
2941 if (i >= STATISTIC_NUM_SLOTS)
2942 return false; /* not there */
2943
2944 sslot->staop = (&stats->staop1)[i];
2945
2946 if (flags & ATTSTATSSLOT_VALUES)
2947 {
2948 val = SysCacheGetAttr(STATRELATTINH, statstuple,
2949 Anum_pg_statistic_stavalues1 + i,
2950 &isnull);
2951 if (isnull)
2952 elog(ERROR, "stavalues is null");
2953
2954 /*
2955 * Detoast the array if needed, and in any case make a copy that's
2956 * under control of this AttStatsSlot.
2957 */
2958 statarray = DatumGetArrayTypePCopy(val);
2959
2960 /*
2961 * Extract the actual array element type, and pass it back in case the
2962 * caller needs it.
2963 */
2964 sslot->valuetype = arrayelemtype = ARR_ELEMTYPE(statarray);
2965
2966 /* Need info about element type */
2967 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrayelemtype));
2968 if (!HeapTupleIsValid(typeTuple))
2969 elog(ERROR, "cache lookup failed for type %u", arrayelemtype);
2970 typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
2971
2972 /* Deconstruct array into Datum elements; NULLs not expected */
2973 deconstruct_array(statarray,
2974 arrayelemtype,
2975 typeForm->typlen,
2976 typeForm->typbyval,
2977 typeForm->typalign,
2978 &sslot->values, NULL, &sslot->nvalues);
2979
2980 /*
2981 * If the element type is pass-by-reference, we now have a bunch of
2982 * Datums that are pointers into the statarray, so we need to keep
2983 * that until free_attstatsslot. Otherwise, all the useful info is in
2984 * sslot->values[], so we can free the array object immediately.
2985 */
2986 if (!typeForm->typbyval)
2987 sslot->values_arr = statarray;
2988 else
2989 pfree(statarray);
2990
2991 ReleaseSysCache(typeTuple);
2992 }
2993
2994 if (flags & ATTSTATSSLOT_NUMBERS)
2995 {
2996 val = SysCacheGetAttr(STATRELATTINH, statstuple,
2997 Anum_pg_statistic_stanumbers1 + i,
2998 &isnull);
2999 if (isnull)
3000 elog(ERROR, "stanumbers is null");
3001
3002 /*
3003 * Detoast the array if needed, and in any case make a copy that's
3004 * under control of this AttStatsSlot.
3005 */
3006 statarray = DatumGetArrayTypePCopy(val);
3007
3008 /*
3009 * We expect the array to be a 1-D float4 array; verify that. We don't
3010 * need to use deconstruct_array() since the array data is just going
3011 * to look like a C array of float4 values.
3012 */
3013 narrayelem = ARR_DIMS(statarray)[0];
3014 if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
3015 ARR_HASNULL(statarray) ||
3016 ARR_ELEMTYPE(statarray) != FLOAT4OID)
3017 elog(ERROR, "stanumbers is not a 1-D float4 array");
3018
3019 /* Give caller a pointer directly into the statarray */
3020 sslot->numbers = (float4 *) ARR_DATA_PTR(statarray);
3021 sslot->nnumbers = narrayelem;
3022
3023 /* We'll free the statarray in free_attstatsslot */
3024 sslot->numbers_arr = statarray;
3025 }
3026
3027 return true;
3028 }
3029
3030 /*
3031 * free_attstatsslot
3032 * Free data allocated by get_attstatsslot
3033 */
3034 void
free_attstatsslot(AttStatsSlot * sslot)3035 free_attstatsslot(AttStatsSlot *sslot)
3036 {
3037 /* The values[] array was separately palloc'd by deconstruct_array */
3038 if (sslot->values)
3039 pfree(sslot->values);
3040 /* The numbers[] array points into numbers_arr, do not pfree it */
3041 /* Free the detoasted array objects, if any */
3042 if (sslot->values_arr)
3043 pfree(sslot->values_arr);
3044 if (sslot->numbers_arr)
3045 pfree(sslot->numbers_arr);
3046 }
3047
3048 /* ---------- PG_NAMESPACE CACHE ---------- */
3049
3050 /*
3051 * get_namespace_name
3052 * Returns the name of a given namespace
3053 *
3054 * Returns a palloc'd copy of the string, or NULL if no such namespace.
3055 */
3056 char *
get_namespace_name(Oid nspid)3057 get_namespace_name(Oid nspid)
3058 {
3059 HeapTuple tp;
3060
3061 tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
3062 if (HeapTupleIsValid(tp))
3063 {
3064 Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
3065 char *result;
3066
3067 result = pstrdup(NameStr(nsptup->nspname));
3068 ReleaseSysCache(tp);
3069 return result;
3070 }
3071 else
3072 return NULL;
3073 }
3074
3075 /*
3076 * get_namespace_name_or_temp
3077 * As above, but if it is this backend's temporary namespace, return
3078 * "pg_temp" instead.
3079 */
3080 char *
get_namespace_name_or_temp(Oid nspid)3081 get_namespace_name_or_temp(Oid nspid)
3082 {
3083 if (isTempNamespace(nspid))
3084 return "pg_temp";
3085 else
3086 return get_namespace_name(nspid);
3087 }
3088
3089 /* ---------- PG_RANGE CACHE ---------- */
3090
3091 /*
3092 * get_range_subtype
3093 * Returns the subtype of a given range type
3094 *
3095 * Returns InvalidOid if the type is not a range type.
3096 */
3097 Oid
get_range_subtype(Oid rangeOid)3098 get_range_subtype(Oid rangeOid)
3099 {
3100 HeapTuple tp;
3101
3102 tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
3103 if (HeapTupleIsValid(tp))
3104 {
3105 Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
3106 Oid result;
3107
3108 result = rngtup->rngsubtype;
3109 ReleaseSysCache(tp);
3110 return result;
3111 }
3112 else
3113 return InvalidOid;
3114 }
3115
3116 /*
3117 * get_range_collation
3118 * Returns the collation of a given range type
3119 *
3120 * Returns InvalidOid if the type is not a range type,
3121 * or if its subtype is not collatable.
3122 */
3123 Oid
get_range_collation(Oid rangeOid)3124 get_range_collation(Oid rangeOid)
3125 {
3126 HeapTuple tp;
3127
3128 tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
3129 if (HeapTupleIsValid(tp))
3130 {
3131 Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
3132 Oid result;
3133
3134 result = rngtup->rngcollation;
3135 ReleaseSysCache(tp);
3136 return result;
3137 }
3138 else
3139 return InvalidOid;
3140 }
3141
3142 /* ---------- PG_INDEX CACHE ---------- */
3143
3144 /*
3145 * get_index_isreplident
3146 *
3147 * Given the index OID, return pg_index.indisreplident.
3148 */
3149 bool
get_index_isreplident(Oid index_oid)3150 get_index_isreplident(Oid index_oid)
3151 {
3152 HeapTuple tuple;
3153 Form_pg_index rd_index;
3154 bool result;
3155
3156 tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
3157 if (!HeapTupleIsValid(tuple))
3158 return false;
3159
3160 rd_index = (Form_pg_index) GETSTRUCT(tuple);
3161 result = rd_index->indisreplident;
3162 ReleaseSysCache(tuple);
3163
3164 return result;
3165 }
3166
3167 /*
3168 * get_index_isclustered
3169 *
3170 * Given the index OID, return pg_index.indisclustered.
3171 */
3172 bool
get_index_isclustered(Oid index_oid)3173 get_index_isclustered(Oid index_oid)
3174 {
3175 bool isclustered;
3176 HeapTuple tuple;
3177 Form_pg_index rd_index;
3178
3179 tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
3180 if (!HeapTupleIsValid(tuple))
3181 elog(ERROR, "cache lookup failed for index %u", index_oid);
3182
3183 rd_index = (Form_pg_index) GETSTRUCT(tuple);
3184 isclustered = rd_index->indisclustered;
3185 ReleaseSysCache(tuple);
3186
3187 return isclustered;
3188 }
3189