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