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