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