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