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