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