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