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