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