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