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