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