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