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