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