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