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