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