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