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