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