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