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
7073 tgl@sss.pgh.pa.us 70 :CBC 446901 : op_in_opfamily(Oid opno, Oid opfamily)
71 : : {
5641 72 : 446901 : 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
7073 87 : 530025 : get_op_opfamily_strategy(Oid opno, Oid opfamily)
88 : : {
89 : : HeapTuple tp;
90 : : Form_pg_amop amop_tup;
91 : : int result;
92 : :
5641 93 : 530025 : tp = SearchSysCache3(AMOPOPID,
94 : : ObjectIdGetDatum(opno),
95 : : CharGetDatum(AMOP_SEARCH),
96 : : ObjectIdGetDatum(opfamily));
7694 97 [ - + ]: 530025 : if (!HeapTupleIsValid(tp))
7694 tgl@sss.pgh.pa.us 98 :UBC 0 : return 0;
7694 tgl@sss.pgh.pa.us 99 :CBC 530025 : amop_tup = (Form_pg_amop) GETSTRUCT(tp);
100 : 530025 : result = amop_tup->amopstrategy;
101 : 530025 : ReleaseSysCache(tp);
102 : 530025 : 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
5633 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))
5633 tgl@sss.pgh.pa.us 123 :UBC 0 : return InvalidOid;
5633 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 : 277271 : 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 : :
5641 148 [ + + ]: 277271 : tp = SearchSysCache3(AMOPOPID,
149 : : ObjectIdGetDatum(opno),
150 : : CharGetDatum(ordering_op ? AMOP_ORDER : AMOP_SEARCH),
151 : : ObjectIdGetDatum(opfamily));
9023 152 [ - + ]: 277271 : if (!HeapTupleIsValid(tp))
7073 tgl@sss.pgh.pa.us 153 [ # # ]:UBC 0 : elog(ERROR, "operator %u is not a member of opfamily %u",
154 : : opno, opfamily);
9023 tgl@sss.pgh.pa.us 155 :CBC 277271 : amop_tup = (Form_pg_amop) GETSTRUCT(tp);
8213 156 : 277271 : *strategy = amop_tup->amopstrategy;
7073 157 : 277271 : *lefttype = amop_tup->amoplefttype;
158 : 277271 : *righttype = amop_tup->amoprighttype;
9023 159 : 277271 : ReleaseSysCache(tp);
10892 scrappy@hub.org 160 : 277271 : }
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
7073 tgl@sss.pgh.pa.us 170 : 3053639 : 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 : :
5924 rhaas@postgresql.org 177 : 3053639 : tp = SearchSysCache4(AMOPSTRATEGY,
178 : : ObjectIdGetDatum(opfamily),
179 : : ObjectIdGetDatum(lefttype),
180 : : ObjectIdGetDatum(righttype),
181 : : Int16GetDatum(strategy));
8380 tgl@sss.pgh.pa.us 182 [ + + ]: 3053639 : if (!HeapTupleIsValid(tp))
183 : 548 : return InvalidOid;
184 : 3053091 : amop_tup = (Form_pg_amop) GETSTRUCT(tp);
185 : 3053091 : result = amop_tup->amopopr;
186 : 3053091 : ReleaseSysCache(tp);
187 : 3053091 : 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
413 peter@eisentraut.org 199 : 2225923 : get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype,
200 : : CompareType cmptype)
201 : : {
202 : : Oid opmethod;
203 : : StrategyNumber strategy;
204 : :
205 : 2225923 : opmethod = get_opfamily_method(opfamily);
206 : 2225923 : strategy = IndexAmTranslateCompareType(cmptype, opmethod, opfamily, true);
207 [ - + ]: 2225923 : if (!strategy)
413 peter@eisentraut.org 208 :UBC 0 : return InvalidOid;
413 peter@eisentraut.org 209 :CBC 2225923 : 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
394 223 : 10615676 : get_opmethod_canorder(Oid amoid)
224 : : {
225 [ + + + ]: 10615676 : switch (amoid)
226 : : {
227 : 2502094 : case BTREE_AM_OID:
228 : 2502094 : return true;
229 : 8113044 : 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 : 8113044 : return false;
235 : 538 : default:
126 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
7044 tgl@sss.pgh.pa.us 261 :CBC 382460 : get_ordering_op_properties(Oid opno,
262 : : Oid *opfamily, Oid *opcintype, CompareType *cmptype)
263 : : {
7056 264 : 382460 : bool result = false;
265 : : CatCList *catlist;
266 : : int i;
267 : :
268 : : /* ensure outputs are initialized on failure */
7044 269 : 382460 : *opfamily = InvalidOid;
270 : 382460 : *opcintype = InvalidOid;
394 peter@eisentraut.org 271 : 382460 : *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 : : */
5924 rhaas@postgresql.org 277 : 382460 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
278 : :
7056 tgl@sss.pgh.pa.us 279 [ + - ]: 382472 : for (i = 0; i < catlist->n_members; i++)
280 : : {
281 : 382472 : HeapTuple tuple = &catlist->members[i]->tuple;
282 : 382472 : Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
283 : : CompareType am_cmptype;
284 : :
285 : : /* must be ordering index */
394 peter@eisentraut.org 286 [ + + ]: 382472 : if (!get_opmethod_canorder(aform->amopmethod))
7056 tgl@sss.pgh.pa.us 287 : 12 : continue;
288 : :
394 peter@eisentraut.org 289 : 382460 : am_cmptype = IndexAmTranslateStrategy(aform->amopstrategy,
290 : : aform->amopmethod,
291 : : aform->amopfamily,
292 : : true);
293 : :
294 [ + + + - ]: 382460 : if (am_cmptype == COMPARE_LT || am_cmptype == COMPARE_GT)
295 : : {
296 : : /* Found it ... should have consistent input types */
7044 tgl@sss.pgh.pa.us 297 [ + - ]: 382460 : if (aform->amoplefttype == aform->amoprighttype)
298 : : {
299 : : /* Found a suitable opfamily, return info */
300 : 382460 : *opfamily = aform->amopfamily;
301 : 382460 : *opcintype = aform->amoplefttype;
394 peter@eisentraut.org 302 : 382460 : *cmptype = am_cmptype;
7044 tgl@sss.pgh.pa.us 303 : 382460 : result = true;
304 : 382460 : break;
305 : : }
306 : : }
307 : : }
308 : :
7056 309 : 382460 : ReleaseSysCacheList(catlist);
310 : :
311 : 382460 : 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
6485 326 : 6672 : get_equality_op_for_ordering_op(Oid opno, bool *reverse)
327 : : {
7055 328 : 6672 : Oid result = InvalidOid;
329 : : Oid opfamily;
330 : : Oid opcintype;
331 : : CompareType cmptype;
332 : :
333 : : /* Find the operator in pg_amop */
7044 334 [ + - ]: 6672 : if (get_ordering_op_properties(opno,
335 : : &opfamily, &opcintype, &cmptype))
336 : : {
337 : : /* Found a suitable opfamily, get matching equality operator */
394 peter@eisentraut.org 338 : 6672 : result = get_opfamily_member_for_cmptype(opfamily,
339 : : opcintype,
340 : : opcintype,
341 : : COMPARE_EQ);
6485 tgl@sss.pgh.pa.us 342 [ + + ]: 6672 : if (reverse)
394 peter@eisentraut.org 343 : 810 : *reverse = (cmptype == COMPARE_GT);
344 : : }
345 : :
7055 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 : : */
5924 rhaas@postgresql.org 374 : 5455 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
375 : :
7055 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 */
394 peter@eisentraut.org 383 [ + + ]: 5499 : if (!get_opmethod_canorder(aform->amopmethod))
7055 tgl@sss.pgh.pa.us 384 : 44 : continue;
385 : :
394 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 : :
7055 tgl@sss.pgh.pa.us 395 [ - + ]: 5455 : typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
394 peter@eisentraut.org 396 : 5455 : result = get_opfamily_member_for_cmptype(aform->amopfamily,
397 : : typid, typid,
398 : : COMPARE_LT);
7055 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 *
7045 430 : 2035050 : get_mergejoin_opfamilies(Oid opno)
431 : : {
432 : 2035050 : 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 : : */
5924 rhaas@postgresql.org 440 : 2035050 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
441 : :
7045 tgl@sss.pgh.pa.us 442 [ + + ]: 12252400 : for (i = 0; i < catlist->n_members; i++)
443 : : {
444 : 10217350 : HeapTuple tuple = &catlist->members[i]->tuple;
445 : 10217350 : Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
446 : :
447 : : /* must be ordering index equality */
394 peter@eisentraut.org 448 [ + + + - ]: 12328636 : if (get_opmethod_canorder(aform->amopmethod) &&
449 : 2111286 : IndexAmTranslateStrategy(aform->amopstrategy,
450 : : aform->amopmethod,
451 : : aform->amopfamily,
452 : : true) == COMPARE_EQ)
7045 tgl@sss.pgh.pa.us 453 : 2111286 : result = lappend_oid(result, aform->amopfamily);
454 : : }
455 : :
456 : 2035050 : ReleaseSysCacheList(catlist);
457 : :
458 : 2035050 : 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
7035 477 : 4610 : get_compatible_hash_operators(Oid opno,
478 : : Oid *lhs_opno, Oid *rhs_opno)
479 : : {
480 : 4610 : bool result = false;
481 : : CatCList *catlist;
482 : : int i;
483 : :
484 : : /* Ensure output args are initialized on failure */
485 [ - + ]: 4610 : if (lhs_opno)
7035 tgl@sss.pgh.pa.us 486 :UBC 0 : *lhs_opno = InvalidOid;
7035 tgl@sss.pgh.pa.us 487 [ + - ]:CBC 4610 : if (rhs_opno)
488 : 4610 : *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 : : */
5924 rhaas@postgresql.org 495 : 4610 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
496 : :
7055 tgl@sss.pgh.pa.us 497 [ + - ]: 9176 : for (i = 0; i < catlist->n_members; i++)
498 : : {
499 : 9176 : HeapTuple tuple = &catlist->members[i]->tuple;
500 : 9176 : Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
501 : :
502 [ + + ]: 9176 : if (aform->amopmethod == HASH_AM_OID &&
503 [ + - ]: 4610 : aform->amopstrategy == HTEqualStrategyNumber)
504 : : {
505 : : /* No extra lookup needed if given operator is single-type */
506 [ + + ]: 4610 : if (aform->amoplefttype == aform->amoprighttype)
507 : : {
7035 508 [ - + ]: 4573 : if (lhs_opno)
7035 tgl@sss.pgh.pa.us 509 :UBC 0 : *lhs_opno = opno;
7035 tgl@sss.pgh.pa.us 510 [ + - ]:CBC 4573 : if (rhs_opno)
511 : 4573 : *rhs_opno = opno;
512 : 4573 : result = true;
7055 513 : 4573 : 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 : : */
7035 521 [ - + ]: 37 : if (lhs_opno)
522 : : {
7035 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 : : }
7035 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 */
7035 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 */
7035 tgl@sss.pgh.pa.us 550 :CBC 37 : result = true;
7055 551 : 37 : break;
552 : : }
553 : : }
554 : : }
555 : :
556 : 4610 : ReleaseSysCacheList(catlist);
557 : :
558 : 4610 : 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
7035 577 : 65422 : get_op_hash_functions(Oid opno,
578 : : RegProcedure *lhs_procno, RegProcedure *rhs_procno)
579 : : {
580 : 65422 : bool result = false;
581 : : CatCList *catlist;
582 : : int i;
583 : :
584 : : /* Ensure output args are initialized on failure */
585 [ + - ]: 65422 : if (lhs_procno)
586 : 65422 : *lhs_procno = InvalidOid;
587 [ + - ]: 65422 : if (rhs_procno)
588 : 65422 : *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 : : */
5924 rhaas@postgresql.org 595 : 65422 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
596 : :
8353 tgl@sss.pgh.pa.us 597 [ + + ]: 130988 : for (i = 0; i < catlist->n_members; i++)
598 : : {
8297 599 : 130570 : HeapTuple tuple = &catlist->members[i]->tuple;
600 : 130570 : Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
601 : :
7073 602 [ + + ]: 130570 : if (aform->amopmethod == HASH_AM_OID &&
603 [ + - ]: 65004 : 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 : : */
7035 610 [ + - ]: 65004 : if (lhs_procno)
611 : : {
612 : 65004 : *lhs_procno = get_opfamily_proc(aform->amopfamily,
613 : : aform->amoplefttype,
614 : : aform->amoplefttype,
615 : : HASHSTANDARD_PROC);
616 [ - + ]: 65004 : if (!OidIsValid(*lhs_procno))
7035 tgl@sss.pgh.pa.us 617 :UBC 0 : continue;
618 : : /* Matching LHS found, done if caller doesn't want RHS */
7035 tgl@sss.pgh.pa.us 619 [ - + ]:CBC 65004 : if (!rhs_procno)
620 : : {
7035 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 */
7035 tgl@sss.pgh.pa.us 625 [ + + ]:CBC 65004 : if (aform->amoplefttype == aform->amoprighttype)
626 : : {
627 : 63525 : *rhs_procno = *lhs_procno;
628 : 63525 : result = true;
629 : 63525 : break;
630 : : }
631 : : }
632 [ + - ]: 1479 : if (rhs_procno)
633 : : {
634 : 1479 : *rhs_procno = get_opfamily_proc(aform->amopfamily,
635 : : aform->amoprighttype,
636 : : aform->amoprighttype,
637 : : HASHSTANDARD_PROC);
638 [ - + ]: 1479 : if (!OidIsValid(*rhs_procno))
639 : : {
640 : : /* Forget any LHS function from this opfamily */
7035 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 */
7035 tgl@sss.pgh.pa.us 646 :CBC 1479 : result = true;
647 : 1479 : break;
648 : : }
649 : : }
650 : : }
651 : :
8353 652 : 65422 : ReleaseSysCacheList(catlist);
653 : :
7073 654 : 65422 : 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 *
394 peter@eisentraut.org 668 : 3660 : get_op_index_interpretation(Oid opno)
669 : : {
5417 tgl@sss.pgh.pa.us 670 : 3660 : 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 : : */
5924 rhaas@postgresql.org 678 : 3660 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
679 : :
7433 tgl@sss.pgh.pa.us 680 [ + + ]: 14015 : for (i = 0; i < catlist->n_members; i++)
681 : : {
682 : 10355 : HeapTuple op_tuple = &catlist->members[i]->tuple;
683 : 10355 : Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
684 : : CompareType cmptype;
685 : :
686 : : /* must be ordering index */
394 peter@eisentraut.org 687 [ + + ]: 10355 : if (!get_opmethod_canorder(op_form->amopmethod))
7433 tgl@sss.pgh.pa.us 688 : 7462 : continue;
689 : :
690 : : /* Get the operator's comparison type */
394 peter@eisentraut.org 691 : 2893 : cmptype = IndexAmTranslateStrategy(op_form->amopstrategy,
692 : : op_form->amopmethod,
693 : : op_form->amopfamily,
694 : : true);
695 : :
696 : : /* should not happen */
697 [ - + ]: 2893 : if (cmptype == COMPARE_INVALID)
394 peter@eisentraut.org 698 :UBC 0 : continue;
699 : :
146 michael@paquier.xyz 700 :GNC 2893 : thisresult = palloc_object(OpIndexInterpretation);
5417 tgl@sss.pgh.pa.us 701 :CBC 2893 : thisresult->opfamily_id = op_form->amopfamily;
394 peter@eisentraut.org 702 : 2893 : thisresult->cmptype = cmptype;
5417 tgl@sss.pgh.pa.us 703 : 2893 : thisresult->oplefttype = op_form->amoplefttype;
704 : 2893 : thisresult->oprighttype = op_form->amoprighttype;
705 : 2893 : result = lappend(result, thisresult);
706 : : }
707 : :
708 : 3660 : 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 [ + + ]: 3660 : if (result == NIL)
715 : : {
716 : 948 : Oid op_negator = get_negator(opno);
717 : :
718 [ + + ]: 948 : if (OidIsValid(op_negator))
719 : : {
720 : 932 : catlist = SearchSysCacheList1(AMOPOPID,
721 : : ObjectIdGetDatum(op_negator));
722 : :
723 [ + + ]: 3726 : 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);
126 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 */
394 peter@eisentraut.org 731 [ + + ]:CBC 2794 : if (!amroutine->amcanorder)
5417 tgl@sss.pgh.pa.us 732 : 2130 : continue;
733 : :
734 : : /* Get the operator's comparison type */
394 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)
5417 tgl@sss.pgh.pa.us 742 :UBC 0 : continue;
743 : :
744 : : /* OK, report it as COMPARE_NE */
146 michael@paquier.xyz 745 :GNC 664 : thisresult = palloc_object(OpIndexInterpretation);
5417 tgl@sss.pgh.pa.us 746 :CBC 664 : thisresult->opfamily_id = op_form->amopfamily;
394 peter@eisentraut.org 747 : 664 : thisresult->cmptype = COMPARE_NE;
5417 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 : 932 : ReleaseSysCacheList(catlist);
754 : : }
755 : : }
756 : :
757 : 3660 : 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
6485 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 : : */
5924 rhaas@postgresql.org 786 : 5 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno1));
787 : :
6485 tgl@sss.pgh.pa.us 788 : 5 : result = false;
7055 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 : : */
126 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 : :
7055 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
2160 825 : 148843 : 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 [ + + ]: 148843 : if (opno1 == opno2)
833 : 69057 : return true;
834 : :
835 : : /*
836 : : * We search through all the pg_amop entries for opno1.
837 : : */
838 : 79786 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno1));
839 : :
840 : 79786 : result = false;
841 [ + + ]: 80056 : for (i = 0; i < catlist->n_members; i++)
842 : : {
843 : 79966 : HeapTuple op_tuple = &catlist->members[i]->tuple;
844 : 79966 : 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 : : */
126 tgl@sss.pgh.pa.us 850 [ + + ]:GNC 79966 : if (op_in_opfamily(opno2, op_form->amopfamily) &&
851 [ + + ]: 79706 : GetIndexAmRoutineByAmId(op_form->amopmethod, false)->amconsistentordering)
852 : : {
853 : 79696 : result = true;
854 : 79696 : break;
855 : : }
856 : : }
857 : :
2160 tgl@sss.pgh.pa.us 858 :CBC 79786 : ReleaseSysCacheList(catlist);
859 : :
860 : 79786 : 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
0 rguo@postgresql.org 886 : 361732 : collations_agree_on_equality(Oid coll1, Oid coll2)
887 : : {
888 [ + + - + ]: 361732 : if (!OidIsValid(coll1) || !OidIsValid(coll2))
889 : 357140 : return true;
890 : :
891 [ + + ]: 4592 : if (coll1 == coll2)
892 : 4312 : return true;
893 : :
894 [ + + ]: 280 : if (!get_collation_isdeterministic(coll1) ||
895 [ + + ]: 220 : !get_collation_isdeterministic(coll2))
896 : 220 : 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
54 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 ||
54 rguo@postgresql.org 930 [ # # ]:UNC 0 : aform->amopmethod == HASH_AM_OID)
931 : : {
54 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
7073 tgl@sss.pgh.pa.us 953 :CBC 510442 : 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 : :
5924 rhaas@postgresql.org 959 : 510442 : tp = SearchSysCache4(AMPROCNUM,
960 : : ObjectIdGetDatum(opfamily),
961 : : ObjectIdGetDatum(lefttype),
962 : : ObjectIdGetDatum(righttype),
963 : : Int16GetDatum(procnum));
8297 tgl@sss.pgh.pa.us 964 [ + + ]: 510442 : if (!HeapTupleIsValid(tp))
965 : 21150 : return InvalidOid;
966 : 489292 : amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
967 : 489292 : result = amproc_tup->amproc;
968 : 489292 : ReleaseSysCache(tp);
969 : 489292 : 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 *
3004 alvherre@alvh.no-ip. 984 : 57558 : get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
985 : : {
986 : : HeapTuple tp;
987 : :
5924 rhaas@postgresql.org 988 : 57558 : tp = SearchSysCache2(ATTNUM,
989 : : ObjectIdGetDatum(relid), Int16GetDatum(attnum));
9838 tgl@sss.pgh.pa.us 990 [ + + ]: 57558 : if (HeapTupleIsValid(tp))
991 : : {
992 : 57542 : Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
993 : : char *result;
994 : :
9301 995 : 57542 : result = pstrdup(NameStr(att_tup->attname));
996 : 57542 : ReleaseSysCache(tp);
997 : 57542 : return result;
998 : : }
999 : :
3004 alvherre@alvh.no-ip. 1000 [ - + ]: 16 : if (!missing_ok)
8303 tgl@sss.pgh.pa.us 1001 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1002 : : attnum, relid);
3004 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
8677 tgl@sss.pgh.pa.us 1015 : 24075 : get_attnum(Oid relid, const char *attname)
1016 : : {
1017 : : HeapTuple tp;
1018 : :
1019 : 24075 : tp = SearchSysCacheAttName(relid, attname);
9838 1020 [ + + ]: 24075 : if (HeapTupleIsValid(tp))
1021 : : {
1022 : 23977 : Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
1023 : : AttrNumber result;
1024 : :
9301 1025 : 23977 : result = att_tup->attnum;
1026 : 23977 : ReleaseSysCache(tp);
1027 : 23977 : return result;
1028 : : }
1029 : : else
10332 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
2593 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));
2587 1054 [ - + ]: 1541 : if (!HeapTupleIsValid(tp))
2593 peter@eisentraut.org 1055 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1056 : : attnum, relid);
2587 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
10892 scrappy@hub.org 1070 : 2599 : get_atttype(Oid relid, AttrNumber attnum)
1071 : : {
1072 : : HeapTuple tp;
1073 : :
5924 rhaas@postgresql.org 1074 : 2599 : tp = SearchSysCache2(ATTNUM,
1075 : : ObjectIdGetDatum(relid),
1076 : : Int16GetDatum(attnum));
9838 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 : :
9301 1082 : 2599 : result = att_tup->atttypid;
1083 : 2599 : ReleaseSysCache(tp);
1084 : 2599 : return result;
1085 : : }
1086 : : else
9838 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
5519 tgl@sss.pgh.pa.us 1100 :CBC 16095 : get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
1101 : : Oid *typid, int32 *typmod, Oid *collid)
1102 : : {
1103 : : HeapTuple tp;
1104 : : Form_pg_attribute att_tup;
1105 : :
5924 rhaas@postgresql.org 1106 : 16095 : tp = SearchSysCache2(ATTNUM,
1107 : : ObjectIdGetDatum(relid),
1108 : : Int16GetDatum(attnum));
9127 tgl@sss.pgh.pa.us 1109 [ - + ]: 16095 : if (!HeapTupleIsValid(tp))
8317 tgl@sss.pgh.pa.us 1110 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1111 : : attnum, relid);
9127 tgl@sss.pgh.pa.us 1112 :CBC 16095 : att_tup = (Form_pg_attribute) GETSTRUCT(tp);
1113 : :
1114 : 16095 : *typid = att_tup->atttypid;
1115 : 16095 : *typmod = att_tup->atttypmod;
5519 1116 : 16095 : *collid = att_tup->attcollation;
9127 1117 : 16095 : ReleaseSysCache(tp);
1118 : 16095 : }
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
2227 akorotkov@postgresql 1127 : 590125 : get_attoptions(Oid relid, int16 attnum)
1128 : : {
1129 : : HeapTuple tuple;
1130 : : Datum attopts;
1131 : : Datum result;
1132 : : bool isnull;
1133 : :
1134 : 590125 : tuple = SearchSysCache2(ATTNUM,
1135 : : ObjectIdGetDatum(relid),
1136 : : Int16GetDatum(attnum));
1137 : :
1138 [ - + ]: 590125 : if (!HeapTupleIsValid(tuple))
2227 akorotkov@postgresql 1139 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1140 : : attnum, relid);
1141 : :
2227 akorotkov@postgresql 1142 :CBC 590125 : attopts = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
1143 : : &isnull);
1144 : :
1145 [ + + ]: 590125 : if (isnull)
1146 : 589902 : result = (Datum) 0;
1147 : : else
2182 tgl@sss.pgh.pa.us 1148 : 223 : result = datumCopy(attopts, false, -1); /* text[] */
1149 : :
2227 akorotkov@postgresql 1150 : 590125 : ReleaseSysCache(tuple);
1151 : :
1152 : 590125 : 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
2247 alvherre@alvh.no-ip. 1164 : 51 : get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok)
1165 : : {
1166 : : Oid oid;
1167 : :
1168 : 51 : oid = GetSysCacheOid2(CASTSOURCETARGET, Anum_pg_cast_oid,
1169 : : ObjectIdGetDatum(sourcetypeid),
1170 : : ObjectIdGetDatum(targettypeid));
1171 [ + + + + ]: 51 : 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 : 47 : 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 *
5565 peter_e@gmx.net 1192 : 369 : get_collation_name(Oid colloid)
1193 : : {
1194 : : HeapTuple tp;
1195 : :
1196 : 369 : tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
1197 [ + - ]: 369 : if (HeapTupleIsValid(tp))
1198 : : {
1199 : 369 : Form_pg_collation colltup = (Form_pg_collation) GETSTRUCT(tp);
1200 : : char *result;
1201 : :
1202 : 369 : result = pstrdup(NameStr(colltup->collname));
1203 : 369 : ReleaseSysCache(tp);
1204 : 369 : return result;
1205 : : }
1206 : : else
5565 peter_e@gmx.net 1207 :UBC 0 : return NULL;
1208 : : }
1209 : :
1210 : : bool
2601 peter@eisentraut.org 1211 :CBC 2145 : get_collation_isdeterministic(Oid colloid)
1212 : : {
1213 : : HeapTuple tp;
1214 : : Form_pg_collation colltup;
1215 : : bool result;
1216 : :
1217 : 2145 : tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
1218 [ - + ]: 2145 : if (!HeapTupleIsValid(tp))
2601 peter@eisentraut.org 1219 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for collation %u", colloid);
2601 peter@eisentraut.org 1220 :CBC 2145 : colltup = (Form_pg_collation) GETSTRUCT(tp);
1221 : 2145 : result = colltup->collisdeterministic;
1222 : 2145 : ReleaseSysCache(tp);
1223 : 2145 : 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 *
7020 tgl@sss.pgh.pa.us 1238 : 603 : get_constraint_name(Oid conoid)
1239 : : {
1240 : : HeapTuple tp;
1241 : :
5924 rhaas@postgresql.org 1242 : 603 : tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
7020 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
7020 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
1973 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 : :
1516 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;
1973 peter@eisentraut.org 1286 : 761 : ReleaseSysCache(tp);
1287 : 761 : return result;
1288 : : }
1289 : : else
1973 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
750 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))
750 alvherre@alvh.no-ip. 1307 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for constraint %u", conoid);
1308 : :
750 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 *
250 alvherre@kurilemu.de 1323 :GNC 26078 : get_database_name(Oid dbid)
1324 : : {
1325 : : HeapTuple dbtuple;
1326 : : char *result;
1327 : :
1328 : 26078 : dbtuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(dbid));
1329 [ + + ]: 26078 : if (HeapTupleIsValid(dbtuple))
1330 : : {
1331 : 25919 : result = pstrdup(NameStr(((Form_pg_database) GETSTRUCT(dbtuple))->datname));
1332 : 25919 : ReleaseSysCache(dbtuple);
1333 : : }
1334 : : else
1335 : 159 : result = NULL;
1336 : :
1337 : 26078 : return result;
1338 : : }
1339 : :
1340 : :
1341 : : /* ---------- LANGUAGE CACHE ---------- */
1342 : :
1343 : : char *
4027 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)
4027 peter_e@gmx.net 1360 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for language %u",
1361 : : langoid);
4027 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
7073 tgl@sss.pgh.pa.us 1373 : 104998 : get_opclass_family(Oid opclass)
1374 : : {
1375 : : HeapTuple tp;
1376 : : Form_pg_opclass cla_tup;
1377 : : Oid result;
1378 : :
5924 rhaas@postgresql.org 1379 : 104998 : tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
7433 tgl@sss.pgh.pa.us 1380 [ - + ]: 104998 : if (!HeapTupleIsValid(tp))
7433 tgl@sss.pgh.pa.us 1381 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for opclass %u", opclass);
7433 tgl@sss.pgh.pa.us 1382 :CBC 104998 : cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1383 : :
7073 1384 : 104998 : result = cla_tup->opcfamily;
7433 1385 : 104998 : ReleaseSysCache(tp);
1386 : 104998 : 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 : 105202 : get_opclass_input_type(Oid opclass)
1396 : : {
1397 : : HeapTuple tp;
1398 : : Form_pg_opclass cla_tup;
1399 : : Oid result;
1400 : :
5924 rhaas@postgresql.org 1401 : 105202 : tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
7433 tgl@sss.pgh.pa.us 1402 [ - + ]: 105202 : if (!HeapTupleIsValid(tp))
7433 tgl@sss.pgh.pa.us 1403 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for opclass %u", opclass);
7433 tgl@sss.pgh.pa.us 1404 :CBC 105202 : cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1405 : :
1406 : 105202 : result = cla_tup->opcintype;
1407 : 105202 : ReleaseSysCache(tp);
8353 1408 : 105202 : 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
2785 akorotkov@postgresql 1418 : 4597 : get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
1419 : : {
1420 : : HeapTuple tp;
1421 : : Form_pg_opclass cla_tup;
1422 : :
1423 : 4597 : tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
1424 [ - + ]: 4597 : if (!HeapTupleIsValid(tp))
2785 akorotkov@postgresql 1425 :UBC 0 : return false;
1426 : :
2785 akorotkov@postgresql 1427 :CBC 4597 : cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1428 : :
1429 : 4597 : *opfamily = cla_tup->opcfamily;
1430 : 4597 : *opcintype = cla_tup->opcintype;
1431 : :
1432 : 4597 : ReleaseSysCache(tp);
1433 : :
1434 : 4597 : 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
1026 akapila@postgresql.o 1443 : 2573 : get_opclass_method(Oid opclass)
1444 : : {
1445 : : HeapTuple tp;
1446 : : Form_pg_opclass cla_tup;
1447 : : Oid result;
1448 : :
1449 : 2573 : tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
1450 [ - + ]: 2573 : if (!HeapTupleIsValid(tp))
1026 akapila@postgresql.o 1451 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for opclass %u", opclass);
1026 akapila@postgresql.o 1452 :CBC 2573 : cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1453 : :
1454 : 2573 : result = cla_tup->opcmethod;
1455 : 2573 : ReleaseSysCache(tp);
1456 : 2573 : 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
413 peter@eisentraut.org 1467 : 2334739 : get_opfamily_method(Oid opfid)
1468 : : {
1469 : : HeapTuple tp;
1470 : : Form_pg_opfamily opfform;
1471 : : Oid result;
1472 : :
1473 : 2334739 : tp = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
1474 [ - + ]: 2334739 : if (!HeapTupleIsValid(tp))
413 peter@eisentraut.org 1475 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for operator family %u", opfid);
413 peter@eisentraut.org 1476 :CBC 2334739 : opfform = (Form_pg_opfamily) GETSTRUCT(tp);
1477 : :
1478 : 2334739 : result = opfform->opfmethod;
1479 : 2334739 : ReleaseSysCache(tp);
1480 : 2334739 : return result;
1481 : : }
1482 : :
1483 : : char *
466 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 : : {
466 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 : :
466 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
10892 scrappy@hub.org 1516 : 1196135 : get_opcode(Oid opno)
1517 : : {
1518 : : HeapTuple tp;
1519 : :
5924 rhaas@postgresql.org 1520 : 1196135 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
9838 tgl@sss.pgh.pa.us 1521 [ + - ]: 1196135 : if (HeapTupleIsValid(tp))
1522 : : {
1523 : 1196135 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1524 : : RegProcedure result;
1525 : :
9301 1526 : 1196135 : result = optup->oprcode;
1527 : 1196135 : ReleaseSysCache(tp);
1528 : 1196135 : return result;
1529 : : }
1530 : : else
9396 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 *
10892 scrappy@hub.org 1541 :CBC 45 : get_opname(Oid opno)
1542 : : {
1543 : : HeapTuple tp;
1544 : :
5924 rhaas@postgresql.org 1545 : 45 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
9838 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 : :
9301 1551 : 45 : result = pstrdup(NameStr(optup->oprname));
1552 : 45 : ReleaseSysCache(tp);
1553 : 45 : return result;
1554 : : }
1555 : : else
9838 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
3757 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
3757 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
8189 tgl@sss.pgh.pa.us 1589 :CBC 339389 : op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
1590 : : {
1591 : : HeapTuple tp;
1592 : : Form_pg_operator optup;
1593 : :
5924 rhaas@postgresql.org 1594 : 339389 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
8189 tgl@sss.pgh.pa.us 1595 [ - + ]: 339389 : if (!HeapTupleIsValid(tp)) /* shouldn't happen */
8189 tgl@sss.pgh.pa.us 1596 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for operator %u", opno);
8189 tgl@sss.pgh.pa.us 1597 :CBC 339389 : optup = (Form_pg_operator) GETSTRUCT(tp);
1598 : 339389 : *lefttype = optup->oprleft;
1599 : 339389 : *righttype = optup->oprright;
1600 : 339389 : ReleaseSysCache(tp);
1601 : 339389 : }
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
5666 1617 : 458854 : op_mergejoinable(Oid opno, Oid inputtype)
1618 : : {
9301 1619 : 458854 : 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 : : */
5666 1629 [ + + ]: 458854 : if (opno == ARRAY_EQ_OP)
1630 : : {
5450 1631 : 390 : typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
1632 [ + - ]: 390 : if (typentry->cmp_proc == F_BTARRAYCMP)
1633 : 390 : result = true;
1634 : : }
1635 [ + + ]: 458464 : 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 */
5666 1644 : 458402 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1645 [ + - ]: 458402 : if (HeapTupleIsValid(tp))
1646 : : {
1647 : 458402 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1648 : :
1649 : 458402 : result = optup->oprcanmerge;
1650 : 458402 : ReleaseSysCache(tp);
1651 : : }
1652 : : }
9301 1653 : 458854 : 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
5666 1668 : 448251 : op_hashjoinable(Oid opno, Oid inputtype)
1669 : : {
8511 1670 : 448251 : bool result = false;
1671 : : HeapTuple tp;
1672 : : TypeCacheEntry *typentry;
1673 : :
1674 : : /* As in op_mergejoinable, let the typcache handle the hard cases */
5666 1675 [ + + ]: 448251 : if (opno == ARRAY_EQ_OP)
1676 : : {
5450 1677 : 261 : typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
1678 [ + - ]: 261 : if (typentry->hash_proc == F_HASH_ARRAY)
1679 : 261 : result = true;
1680 : : }
1993 peter@eisentraut.org 1681 [ + + ]: 447990 : 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 */
5666 tgl@sss.pgh.pa.us 1690 : 447925 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1691 [ + - ]: 447925 : if (HeapTupleIsValid(tp))
1692 : : {
1693 : 447925 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1694 : :
1695 : 447925 : result = optup->oprcanhash;
1696 : 447925 : ReleaseSysCache(tp);
1697 : : }
1698 : : }
9301 1699 : 448251 : return result;
1700 : : }
1701 : :
1702 : : /*
1703 : : * op_strict
1704 : : *
1705 : : * Get the proisstrict flag for the operator's underlying function.
1706 : : */
1707 : : bool
8556 1708 : 57286 : op_strict(Oid opno)
1709 : : {
1710 : 57286 : RegProcedure funcid = get_opcode(opno);
1711 : :
1712 [ - + ]: 57286 : if (funcid == (RegProcedure) InvalidOid)
8320 tgl@sss.pgh.pa.us 1713 [ # # ]:UBC 0 : elog(ERROR, "operator %u does not exist", opno);
1714 : :
8556 tgl@sss.pgh.pa.us 1715 :CBC 57286 : 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
8796 1724 : 16037 : op_volatile(Oid opno)
1725 : : {
9175 bruce@momjian.us 1726 : 16037 : RegProcedure funcid = get_opcode(opno);
1727 : :
9396 tgl@sss.pgh.pa.us 1728 [ - + ]: 16037 : if (funcid == (RegProcedure) InvalidOid)
8320 tgl@sss.pgh.pa.us 1729 [ # # ]:UBC 0 : elog(ERROR, "operator %u does not exist", opno);
1730 : :
8796 tgl@sss.pgh.pa.us 1731 :CBC 16037 : return func_volatile((Oid) funcid);
1732 : : }
1733 : :
1734 : : /*
1735 : : * get_commutator
1736 : : *
1737 : : * Returns the corresponding commutator of an operator.
1738 : : */
1739 : : Oid
10892 scrappy@hub.org 1740 : 630766 : get_commutator(Oid opno)
1741 : : {
1742 : : HeapTuple tp;
1743 : :
5924 rhaas@postgresql.org 1744 : 630766 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
9838 tgl@sss.pgh.pa.us 1745 [ + - ]: 630766 : if (HeapTupleIsValid(tp))
1746 : : {
1747 : 630766 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1748 : : Oid result;
1749 : :
9301 1750 : 630766 : result = optup->oprcom;
1751 : 630766 : ReleaseSysCache(tp);
1752 : 630766 : return result;
1753 : : }
1754 : : else
9838 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
10892 scrappy@hub.org 1764 :CBC 51443 : get_negator(Oid opno)
1765 : : {
1766 : : HeapTuple tp;
1767 : :
5924 rhaas@postgresql.org 1768 : 51443 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
9838 tgl@sss.pgh.pa.us 1769 [ + - ]: 51443 : if (HeapTupleIsValid(tp))
1770 : : {
1771 : 51443 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1772 : : Oid result;
1773 : :
9301 1774 : 51443 : result = optup->oprnegate;
1775 : 51443 : ReleaseSysCache(tp);
1776 : 51443 : return result;
1777 : : }
1778 : : else
9838 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
10892 scrappy@hub.org 1788 :CBC 977613 : get_oprrest(Oid opno)
1789 : : {
1790 : : HeapTuple tp;
1791 : :
5924 rhaas@postgresql.org 1792 : 977613 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
9838 tgl@sss.pgh.pa.us 1793 [ + - ]: 977613 : if (HeapTupleIsValid(tp))
1794 : : {
1795 : 977613 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1796 : : RegProcedure result;
1797 : :
9301 1798 : 977613 : result = optup->oprrest;
1799 : 977613 : ReleaseSysCache(tp);
1800 : 977613 : return result;
1801 : : }
1802 : : else
9396 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
10892 scrappy@hub.org 1812 :CBC 221110 : get_oprjoin(Oid opno)
1813 : : {
1814 : : HeapTuple tp;
1815 : :
5924 rhaas@postgresql.org 1816 : 221110 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
9838 tgl@sss.pgh.pa.us 1817 [ + - ]: 221110 : if (HeapTupleIsValid(tp))
1818 : : {
1819 : 221110 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1820 : : RegProcedure result;
1821 : :
9301 1822 : 221110 : result = optup->oprjoin;
1823 : 221110 : ReleaseSysCache(tp);
1824 : 221110 : return result;
1825 : : }
1826 : : else
9396 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 *
8774 tgl@sss.pgh.pa.us 1839 :CBC 597 : get_func_name(Oid funcid)
1840 : : {
1841 : : HeapTuple tp;
1842 : :
5924 rhaas@postgresql.org 1843 : 597 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
8774 tgl@sss.pgh.pa.us 1844 [ + - ]: 597 : if (HeapTupleIsValid(tp))
1845 : : {
1846 : 597 : Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
1847 : : char *result;
1848 : :
1849 : 597 : result = pstrdup(NameStr(functup->proname));
1850 : 597 : ReleaseSysCache(tp);
1851 : 597 : return result;
1852 : : }
1853 : : else
8774 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
6112 tgl@sss.pgh.pa.us 1863 :CBC 127 : get_func_namespace(Oid funcid)
1864 : : {
1865 : : HeapTuple tp;
1866 : :
5924 rhaas@postgresql.org 1867 : 127 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
6112 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
6112 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
9759 tgl@sss.pgh.pa.us 1886 :CBC 15955 : get_func_rettype(Oid funcid)
1887 : : {
1888 : : HeapTuple tp;
1889 : : Oid result;
1890 : :
5924 rhaas@postgresql.org 1891 : 15955 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
9301 tgl@sss.pgh.pa.us 1892 [ - + ]: 15955 : if (!HeapTupleIsValid(tp))
8320 tgl@sss.pgh.pa.us 1893 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1894 : :
9301 tgl@sss.pgh.pa.us 1895 :CBC 15955 : result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
1896 : 15955 : ReleaseSysCache(tp);
1897 : 15955 : return result;
1898 : : }
1899 : :
1900 : : /*
1901 : : * get_func_nargs
1902 : : * Given procedure id, return the number of arguments.
1903 : : */
1904 : : int
7707 tgl@sss.pgh.pa.us 1905 :UBC 0 : get_func_nargs(Oid funcid)
1906 : : {
1907 : : HeapTuple tp;
1908 : : int result;
1909 : :
5924 rhaas@postgresql.org 1910 : 0 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
7707 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
7707 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 : :
5924 rhaas@postgresql.org 1933 : 935 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
8344 tgl@sss.pgh.pa.us 1934 [ - + ]: 935 : if (!HeapTupleIsValid(tp))
8320 tgl@sss.pgh.pa.us 1935 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1936 : :
8344 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;
7707 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 : :
8344 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
4516 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))
4516 tgl@sss.pgh.pa.us 1961 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1962 : :
4516 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
8759 1973 : 434576 : get_func_retset(Oid funcid)
1974 : : {
1975 : : HeapTuple tp;
1976 : : bool result;
1977 : :
5924 rhaas@postgresql.org 1978 : 434576 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
8759 tgl@sss.pgh.pa.us 1979 [ - + ]: 434576 : if (!HeapTupleIsValid(tp))
8320 tgl@sss.pgh.pa.us 1980 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1981 : :
8759 tgl@sss.pgh.pa.us 1982 :CBC 434576 : result = ((Form_pg_proc) GETSTRUCT(tp))->proretset;
1983 : 434576 : ReleaseSysCache(tp);
1984 : 434576 : return result;
1985 : : }
1986 : :
1987 : : /*
1988 : : * func_strict
1989 : : * Given procedure id, return the function's proisstrict flag.
1990 : : */
1991 : : bool
8556 1992 : 178980 : func_strict(Oid funcid)
1993 : : {
1994 : : HeapTuple tp;
1995 : : bool result;
1996 : :
5924 rhaas@postgresql.org 1997 : 178980 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
8556 tgl@sss.pgh.pa.us 1998 [ - + ]: 178980 : if (!HeapTupleIsValid(tp))
8320 tgl@sss.pgh.pa.us 1999 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
2000 : :
8556 tgl@sss.pgh.pa.us 2001 :CBC 178980 : result = ((Form_pg_proc) GETSTRUCT(tp))->proisstrict;
2002 : 178980 : ReleaseSysCache(tp);
2003 : 178980 : return result;
2004 : : }
2005 : :
2006 : : /*
2007 : : * func_volatile
2008 : : * Given procedure id, return the function's provolatile flag.
2009 : : */
2010 : : char
8796 2011 : 864194 : func_volatile(Oid funcid)
2012 : : {
2013 : : HeapTuple tp;
2014 : : char result;
2015 : :
5924 rhaas@postgresql.org 2016 : 864194 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
9301 tgl@sss.pgh.pa.us 2017 [ - + ]: 864194 : if (!HeapTupleIsValid(tp))
8320 tgl@sss.pgh.pa.us 2018 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
2019 : :
8796 tgl@sss.pgh.pa.us 2020 :CBC 864194 : result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
9301 2021 : 864194 : ReleaseSysCache(tp);
2022 : 864194 : return result;
2023 : : }
2024 : :
2025 : : /*
2026 : : * func_parallel
2027 : : * Given procedure id, return the function's proparallel flag.
2028 : : */
2029 : : char
3884 rhaas@postgresql.org 2030 : 1182348 : func_parallel(Oid funcid)
2031 : : {
2032 : : HeapTuple tp;
2033 : : char result;
2034 : :
2035 : 1182348 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2036 [ - + ]: 1182348 : if (!HeapTupleIsValid(tp))
3884 rhaas@postgresql.org 2037 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
2038 : :
3884 rhaas@postgresql.org 2039 :CBC 1182348 : result = ((Form_pg_proc) GETSTRUCT(tp))->proparallel;
2040 : 1182348 : ReleaseSysCache(tp);
2041 : 1182348 : return result;
2042 : : }
2043 : :
2044 : : /*
2045 : : * get_func_prokind
2046 : : * Given procedure id, return the routine kind.
2047 : : */
2048 : : char
2986 peter_e@gmx.net 2049 : 22658 : get_func_prokind(Oid funcid)
2050 : : {
2051 : : HeapTuple tp;
2052 : : char result;
2053 : :
3078 2054 : 22658 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2055 [ - + ]: 22658 : if (!HeapTupleIsValid(tp))
3078 peter_e@gmx.net 2056 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
2057 : :
2986 peter_e@gmx.net 2058 :CBC 22658 : result = ((Form_pg_proc) GETSTRUCT(tp))->prokind;
3078 2059 : 22658 : ReleaseSysCache(tp);
2060 : 22658 : return result;
2061 : : }
2062 : :
2063 : : /*
2064 : : * get_func_leakproof
2065 : : * Given procedure id, return the function's leakproof field.
2066 : : */
2067 : : bool
5195 rhaas@postgresql.org 2068 : 10353 : get_func_leakproof(Oid funcid)
2069 : : {
2070 : : HeapTuple tp;
2071 : : bool result;
2072 : :
2073 : 10353 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2074 [ - + ]: 10353 : if (!HeapTupleIsValid(tp))
5195 rhaas@postgresql.org 2075 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
2076 : :
5195 rhaas@postgresql.org 2077 :CBC 10353 : result = ((Form_pg_proc) GETSTRUCT(tp))->proleakproof;
2078 : 10353 : ReleaseSysCache(tp);
2079 : 10353 : 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
2642 tgl@sss.pgh.pa.us 2089 : 68703 : get_func_support(Oid funcid)
2090 : : {
2091 : : HeapTuple tp;
2092 : :
5924 rhaas@postgresql.org 2093 : 68703 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2642 tgl@sss.pgh.pa.us 2094 [ + - ]: 68703 : if (HeapTupleIsValid(tp))
2095 : : {
2096 : 68703 : Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
2097 : : RegProcedure result;
2098 : :
2099 : 68703 : result = functup->prosupport;
2100 : 68703 : ReleaseSysCache(tp);
2101 : 68703 : return result;
2102 : : }
2103 : : else
2642 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
8806 tgl@sss.pgh.pa.us 2116 :CBC 1052818 : get_relname_relid(const char *relname, Oid relnamespace)
2117 : : {
2723 andres@anarazel.de 2118 : 1052818 : 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 *
10892 scrappy@hub.org 2159 : 187073 : get_rel_name(Oid relid)
2160 : : {
2161 : : HeapTuple tp;
2162 : :
5924 rhaas@postgresql.org 2163 : 187073 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
9838 tgl@sss.pgh.pa.us 2164 [ + + ]: 187073 : if (HeapTupleIsValid(tp))
2165 : : {
2166 : 187065 : Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
2167 : : char *result;
2168 : :
9301 2169 : 187065 : result = pstrdup(NameStr(reltup->relname));
2170 : 187065 : ReleaseSysCache(tp);
2171 : 187065 : return result;
2172 : : }
2173 : : else
10332 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
8771 tgl@sss.pgh.pa.us 2183 : 283605 : get_rel_namespace(Oid relid)
2184 : : {
2185 : : HeapTuple tp;
2186 : :
5924 rhaas@postgresql.org 2187 : 283605 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
8771 tgl@sss.pgh.pa.us 2188 [ + - ]: 283605 : if (HeapTupleIsValid(tp))
2189 : : {
2190 : 283605 : Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
2191 : : Oid result;
2192 : :
2193 : 283605 : result = reltup->relnamespace;
2194 : 283605 : ReleaseSysCache(tp);
2195 : 283605 : return result;
2196 : : }
2197 : : else
8771 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
8810 tgl@sss.pgh.pa.us 2210 :CBC 5752 : get_rel_type_id(Oid relid)
2211 : : {
2212 : : HeapTuple tp;
2213 : :
5924 rhaas@postgresql.org 2214 : 5752 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
8810 tgl@sss.pgh.pa.us 2215 [ + - ]: 5752 : if (HeapTupleIsValid(tp))
2216 : : {
2217 : 5752 : Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
2218 : : Oid result;
2219 : :
2220 : 5752 : result = reltup->reltype;
2221 : 5752 : ReleaseSysCache(tp);
2222 : 5752 : return result;
2223 : : }
2224 : : else
8810 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
8629 tgl@sss.pgh.pa.us 2234 :CBC 183180 : get_rel_relkind(Oid relid)
2235 : : {
2236 : : HeapTuple tp;
2237 : :
5924 rhaas@postgresql.org 2238 : 183180 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
8629 tgl@sss.pgh.pa.us 2239 [ + - ]: 183180 : if (HeapTupleIsValid(tp))
2240 : : {
2241 : 183180 : Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
2242 : : char result;
2243 : :
2244 : 183180 : result = reltup->relkind;
2245 : 183180 : ReleaseSysCache(tp);
2246 : 183180 : return result;
2247 : : }
2248 : : else
8629 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
2777 tgl@sss.pgh.pa.us 2258 :CBC 11676 : get_rel_relispartition(Oid relid)
2259 : : {
2260 : : HeapTuple tp;
2261 : :
2262 : 11676 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2263 [ + - ]: 11676 : if (HeapTupleIsValid(tp))
2264 : : {
2265 : 11676 : Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
2266 : : bool result;
2267 : :
2268 : 11676 : result = reltup->relispartition;
2269 : 11676 : ReleaseSysCache(tp);
2270 : 11676 : return result;
2271 : : }
2272 : : else
2777 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
6779 tgl@sss.pgh.pa.us 2285 :CBC 6761 : get_rel_tablespace(Oid relid)
2286 : : {
2287 : : HeapTuple tp;
2288 : :
5924 rhaas@postgresql.org 2289 : 6761 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
6779 tgl@sss.pgh.pa.us 2290 [ + - ]: 6761 : if (HeapTupleIsValid(tp))
2291 : : {
2292 : 6761 : Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
2293 : : Oid result;
2294 : :
2295 : 6761 : result = reltup->reltablespace;
2296 : 6761 : ReleaseSysCache(tp);
2297 : 6761 : return result;
2298 : : }
2299 : : else
6779 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
3828 rhaas@postgresql.org 2309 :CBC 309628 : get_rel_persistence(Oid relid)
2310 : : {
2311 : : HeapTuple tp;
2312 : : Form_pg_class reltup;
2313 : : char result;
2314 : :
2315 : 309628 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2316 [ - + ]: 309628 : if (!HeapTupleIsValid(tp))
3828 rhaas@postgresql.org 2317 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
3828 rhaas@postgresql.org 2318 :CBC 309628 : reltup = (Form_pg_class) GETSTRUCT(tp);
2319 : 309628 : result = reltup->relpersistence;
2320 : 309628 : ReleaseSysCache(tp);
2321 : :
2322 : 309628 : return result;
2323 : : }
2324 : :
2325 : : /*
2326 : : * get_rel_relam
2327 : : *
2328 : : * Returns the relam associated with a given relation.
2329 : : */
2330 : : Oid
771 alvherre@alvh.no-ip. 2331 : 6356 : get_rel_relam(Oid relid)
2332 : : {
2333 : : HeapTuple tp;
2334 : : Form_pg_class reltup;
2335 : : Oid result;
2336 : :
2337 : 6356 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2338 [ - + ]: 6356 : if (!HeapTupleIsValid(tp))
771 alvherre@alvh.no-ip. 2339 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
771 alvherre@alvh.no-ip. 2340 :CBC 6356 : reltup = (Form_pg_class) GETSTRUCT(tp);
2341 : 6356 : result = reltup->relam;
2342 : 6356 : ReleaseSysCache(tp);
2343 : :
2344 : 6356 : return result;
2345 : : }
2346 : :
2347 : :
2348 : : /* ---------- TRANSFORM CACHE ---------- */
2349 : :
2350 : : Oid
4027 peter_e@gmx.net 2351 : 1053 : get_transform_fromsql(Oid typid, Oid langid, List *trftypes)
2352 : : {
2353 : : HeapTuple tup;
2354 : :
2355 [ + + ]: 1053 : if (!list_member_oid(trftypes, typid))
2356 : 972 : return InvalidOid;
2357 : :
1020 michael@paquier.xyz 2358 : 81 : tup = SearchSysCache2(TRFTYPELANG, ObjectIdGetDatum(typid),
2359 : : ObjectIdGetDatum(langid));
4027 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
4027 peter_e@gmx.net 2369 :UBC 0 : return InvalidOid;
2370 : : }
2371 : :
2372 : : Oid
4027 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 : :
1020 michael@paquier.xyz 2380 : 91 : tup = SearchSysCache2(TRFTYPELANG, ObjectIdGetDatum(typid),
2381 : : ObjectIdGetDatum(langid));
4027 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
4027 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
8803 tgl@sss.pgh.pa.us 2404 :CBC 187 : get_typisdefined(Oid typid)
2405 : : {
2406 : : HeapTuple tp;
2407 : :
5924 rhaas@postgresql.org 2408 : 187 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
8803 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
8803 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
10892 scrappy@hub.org 2428 :CBC 2076037 : get_typlen(Oid typid)
2429 : : {
2430 : : HeapTuple tp;
2431 : :
5924 rhaas@postgresql.org 2432 : 2076037 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
9838 tgl@sss.pgh.pa.us 2433 [ + - ]: 2076037 : if (HeapTupleIsValid(tp))
2434 : : {
2435 : 2076037 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2436 : : int16 result;
2437 : :
9301 2438 : 2076037 : result = typtup->typlen;
2439 : 2076037 : ReleaseSysCache(tp);
2440 : 2076037 : return result;
2441 : : }
2442 : : else
9838 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
10892 scrappy@hub.org 2453 :CBC 42665 : get_typbyval(Oid typid)
2454 : : {
2455 : : HeapTuple tp;
2456 : :
5924 rhaas@postgresql.org 2457 : 42665 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
9838 tgl@sss.pgh.pa.us 2458 [ + - ]: 42665 : if (HeapTupleIsValid(tp))
2459 : : {
2460 : 42665 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2461 : : bool result;
2462 : :
9301 2463 : 42665 : result = typtup->typbyval;
2464 : 42665 : ReleaseSysCache(tp);
2465 : 42665 : return result;
2466 : : }
2467 : : else
10332 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
9301 tgl@sss.pgh.pa.us 2482 :CBC 649251 : get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
2483 : : {
2484 : : HeapTuple tp;
2485 : : Form_pg_type typtup;
2486 : :
5924 rhaas@postgresql.org 2487 : 649251 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
9301 tgl@sss.pgh.pa.us 2488 [ - + ]: 649251 : if (!HeapTupleIsValid(tp))
9301 tgl@sss.pgh.pa.us 2489 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", typid);
9301 tgl@sss.pgh.pa.us 2490 :CBC 649251 : typtup = (Form_pg_type) GETSTRUCT(tp);
2491 : 649251 : *typlen = typtup->typlen;
2492 : 649251 : *typbyval = typtup->typbyval;
2493 : 649251 : ReleaseSysCache(tp);
2494 : 649251 : }
2495 : :
2496 : : /*
2497 : : * get_typlenbyvalalign
2498 : : *
2499 : : * A three-fer: given the type OID, return typlen, typbyval, typalign.
2500 : : */
2501 : : void
8653 2502 : 1097488 : get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
2503 : : char *typalign)
2504 : : {
2505 : : HeapTuple tp;
2506 : : Form_pg_type typtup;
2507 : :
5924 rhaas@postgresql.org 2508 : 1097488 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
8653 tgl@sss.pgh.pa.us 2509 [ - + ]: 1097488 : if (!HeapTupleIsValid(tp))
8653 tgl@sss.pgh.pa.us 2510 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", typid);
8653 tgl@sss.pgh.pa.us 2511 :CBC 1097488 : typtup = (Form_pg_type) GETSTRUCT(tp);
2512 : 1097488 : *typlen = typtup->typlen;
2513 : 1097488 : *typbyval = typtup->typbyval;
2514 : 1097488 : *typalign = typtup->typalign;
2515 : 1097488 : ReleaseSysCache(tp);
2516 : 1097488 : }
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
8003 2534 : 1137149 : getTypeIOParam(HeapTuple typeTuple)
2535 : : {
2536 : 1137149 : 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 : : */
5269 2542 [ + + ]: 1137149 : if (OidIsValid(typeStruct->typelem))
8003 2543 : 53568 : return typeStruct->typelem;
2544 : : else
2723 andres@anarazel.de 2545 : 1083581 : 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
8348 tgl@sss.pgh.pa.us 2556 : 87824 : 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 : : */
7203 2572 [ + + ]: 87824 : 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;
7203 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 : : }
7203 tgl@sss.pgh.pa.us 2599 :CBC 37107 : return;
2600 : : }
2601 : :
5924 rhaas@postgresql.org 2602 : 50717 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
8348 tgl@sss.pgh.pa.us 2603 [ - + ]: 50717 : if (!HeapTupleIsValid(typeTuple))
8348 tgl@sss.pgh.pa.us 2604 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", typid);
8348 tgl@sss.pgh.pa.us 2605 :CBC 50717 : typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
2606 : :
2607 : 50717 : *typlen = typeStruct->typlen;
2608 : 50717 : *typbyval = typeStruct->typbyval;
2609 : 50717 : *typalign = typeStruct->typalign;
2610 : 50717 : *typdelim = typeStruct->typdelim;
8003 2611 : 50717 : *typioparam = getTypeIOParam(typeTuple);
8348 2612 [ + + + + : 50717 : switch (which_func)
- ]
2613 : : {
2614 : 24606 : case IOFunc_input:
2615 : 24606 : *func = typeStruct->typinput;
2616 : 24606 : break;
2617 : 26063 : case IOFunc_output:
2618 : 26063 : *func = typeStruct->typoutput;
2619 : 26063 : 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 : 50717 : 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
9297 2652 : 61735 : get_typstorage(Oid typid)
2653 : : {
2654 : : HeapTuple tp;
2655 : :
5924 rhaas@postgresql.org 2656 : 61735 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
9297 tgl@sss.pgh.pa.us 2657 [ + - ]: 61735 : if (HeapTupleIsValid(tp))
2658 : : {
2659 : 61735 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2660 : : char result;
2661 : :
2662 : 61735 : result = typtup->typstorage;
2663 : 61735 : ReleaseSysCache(tp);
2664 : 61735 : return result;
2665 : : }
2666 : : else
2253 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 *
8812 tgl@sss.pgh.pa.us 2681 :CBC 21390 : get_typdefault(Oid typid)
2682 : : {
2683 : : HeapTuple typeTuple;
2684 : : Form_pg_type type;
2685 : : Datum datum;
2686 : : bool isNull;
2687 : : Node *expr;
2688 : :
5924 rhaas@postgresql.org 2689 : 21390 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
9766 tgl@sss.pgh.pa.us 2690 [ - + ]: 21390 : if (!HeapTupleIsValid(typeTuple))
8320 tgl@sss.pgh.pa.us 2691 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", typid);
9766 tgl@sss.pgh.pa.us 2692 :CBC 21390 : 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 : : */
8813 bruce@momjian.us 2699 : 21390 : datum = SysCacheGetAttr(TYPEOID,
2700 : : typeTuple,
2701 : : Anum_pg_type_typdefaultbin,
2702 : : &isNull);
2703 : :
8812 tgl@sss.pgh.pa.us 2704 [ + + ]: 21390 : if (!isNull)
2705 : : {
2706 : : /* We have an expression default */
6615 2707 : 157 : expr = stringToNode(TextDatumGetCString(datum));
2708 : : }
2709 : : else
2710 : : {
2711 : : /* Perhaps we have a plain literal default */
8812 2712 : 21233 : datum = SysCacheGetAttr(TYPEOID,
2713 : : typeTuple,
2714 : : Anum_pg_type_typdefault,
2715 : : &isNull);
2716 : :
2717 [ + + ]: 21233 : if (!isNull)
2718 : : {
2719 : : char *strDefaultVal;
2720 : :
2721 : : /* Convert text datum to C string */
6615 2722 : 8 : strDefaultVal = TextDatumGetCString(datum);
2723 : : /* Convert C string to a value of the given type */
7336 2724 : 8 : datum = OidInputFunctionCall(type->typinput, strDefaultVal,
2725 : : getTypeIOParam(typeTuple), -1);
2726 : : /* Build a Const node containing the value */
8812 2727 : 8 : expr = (Node *) makeConst(typid,
2728 : : -1,
2729 : : type->typcollation,
2730 : 8 : type->typlen,
2731 : : datum,
2732 : : false,
8562 2733 : 8 : type->typbyval);
8812 2734 : 8 : pfree(strDefaultVal);
2735 : : }
2736 : : else
2737 : : {
2738 : : /* No default */
2739 : 21225 : expr = NULL;
2740 : : }
2741 : : }
2742 : :
2743 : 21390 : ReleaseSysCache(typeTuple);
2744 : :
2745 : 21390 : 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 : 3688688 : getBaseType(Oid typid)
2755 : : {
7335 2756 : 3688688 : int32 typmod = -1;
2757 : :
2758 : 3688688 : 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 : 5065021 : getBaseTypeAndTypmod(Oid typid, int32 *typmod)
2772 : : {
2773 : : /*
2774 : : * We loop to find the bottom base type in a stack of domains.
2775 : : */
2776 : : for (;;)
8812 2777 : 194088 : {
2778 : : HeapTuple tup;
2779 : : Form_pg_type typTup;
2780 : :
5924 rhaas@postgresql.org 2781 : 5259109 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
8812 tgl@sss.pgh.pa.us 2782 [ - + ]: 5259109 : if (!HeapTupleIsValid(tup))
8320 tgl@sss.pgh.pa.us 2783 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", typid);
8812 tgl@sss.pgh.pa.us 2784 :CBC 5259109 : typTup = (Form_pg_type) GETSTRUCT(tup);
6973 2785 [ + + ]: 5259109 : if (typTup->typtype != TYPTYPE_DOMAIN)
2786 : : {
2787 : : /* Not a domain, so done */
8812 2788 : 5065021 : ReleaseSysCache(tup);
2789 : 5065021 : break;
2790 : : }
2791 : :
7335 2792 [ - + ]: 194088 : Assert(*typmod == -1);
8812 2793 : 194088 : typid = typTup->typbasetype;
7335 2794 : 194088 : *typmod = typTup->typtypmod;
2795 : :
8812 2796 : 194088 : ReleaseSysCache(tup);
2797 : : }
2798 : :
2799 : 5065021 : 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
9127 2811 : 1430309 : get_typavgwidth(Oid typid, int32 typmod)
2812 : : {
2813 : 1430309 : int typlen = get_typlen(typid);
2814 : : int32 maxwidth;
2815 : :
2816 : : /*
2817 : : * Easy if it's a fixed-width type
2818 : : */
2819 [ + + ]: 1430309 : if (typlen > 0)
2820 : 930060 : 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 : 500249 : maxwidth = type_maximum_size(typid, typmod);
2827 [ + + ]: 500249 : 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 [ + + ]: 37406 : if (typid == BPCHAROID)
2835 : 16300 : return maxwidth;
2836 [ + + ]: 21106 : if (maxwidth <= 32)
2837 : 12943 : return maxwidth; /* assume full width */
2838 [ + + ]: 8163 : if (maxwidth < 1000)
8958 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 : : */
9127 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 : 462843 : 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
10892 scrappy@hub.org 2862 : 615274 : get_typtype(Oid typid)
2863 : : {
2864 : : HeapTuple tp;
2865 : :
5924 rhaas@postgresql.org 2866 : 615274 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
9838 tgl@sss.pgh.pa.us 2867 [ + + ]: 615274 : if (HeapTupleIsValid(tp))
2868 : : {
2869 : 615198 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2870 : : char result;
2871 : :
9301 2872 : 615198 : result = typtup->typtype;
2873 : 615198 : ReleaseSysCache(tp);
2874 : 615198 : return result;
2875 : : }
2876 : : else
10332 bruce@momjian.us 2877 : 76 : 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
7159 tgl@sss.pgh.pa.us 2888 : 136258 : type_is_rowtype(Oid typid)
2889 : : {
3113 2890 [ + + ]: 136258 : if (typid == RECORDOID)
2891 : 70503 : return true; /* easy case */
2892 [ + + + ]: 65755 : switch (get_typtype(typid))
2893 : : {
2894 : 10584 : case TYPTYPE_COMPOSITE:
2895 : 10584 : return true;
2896 : 149 : case TYPTYPE_DOMAIN:
2897 [ + + ]: 149 : if (get_typtype(getBaseType(typid)) == TYPTYPE_COMPOSITE)
2898 : 48 : return true;
2899 : 101 : break;
2900 : 55022 : default:
2901 : 55022 : break;
2902 : : }
2903 : 55123 : return false;
2904 : : }
2905 : :
2906 : : /*
2907 : : * type_is_enum
2908 : : * Returns true if the given type is an enum type.
2909 : : */
2910 : : bool
6973 2911 : 65036 : type_is_enum(Oid typid)
2912 : : {
2913 : 65036 : 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
5297 heikki.linnakangas@i 2921 : 19169 : type_is_range(Oid typid)
2922 : : {
2923 : 19169 : 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
1962 akorotkov@postgresql 2931 : 38186 : type_is_multirange(Oid typid)
2932 : : {
2933 : 38186 : 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
6488 tgl@sss.pgh.pa.us 2943 : 261182 : get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
2944 : : {
2945 : : HeapTuple tp;
2946 : : Form_pg_type typtup;
2947 : :
5924 rhaas@postgresql.org 2948 : 261182 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
6488 tgl@sss.pgh.pa.us 2949 [ - + ]: 261182 : if (!HeapTupleIsValid(tp))
6488 tgl@sss.pgh.pa.us 2950 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", typid);
6488 tgl@sss.pgh.pa.us 2951 :CBC 261182 : typtup = (Form_pg_type) GETSTRUCT(tp);
2952 : 261182 : *typcategory = typtup->typcategory;
2953 : 261182 : *typispreferred = typtup->typispreferred;
2954 : 261182 : ReleaseSysCache(tp);
2955 : 261182 : }
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
8629 2964 : 20979 : get_typ_typrelid(Oid typid)
2965 : : {
2966 : : HeapTuple tp;
2967 : :
5924 rhaas@postgresql.org 2968 : 20979 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
8629 tgl@sss.pgh.pa.us 2969 [ + - ]: 20979 : if (HeapTupleIsValid(tp))
2970 : : {
2971 : 20979 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2972 : : Oid result;
2973 : :
2974 : 20979 : result = typtup->typrelid;
2975 : 20979 : ReleaseSysCache(tp);
2976 : 20979 : return result;
2977 : : }
2978 : : else
8629 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
8428 tgl@sss.pgh.pa.us 2992 :CBC 926232 : get_element_type(Oid typid)
2993 : : {
2994 : : HeapTuple tp;
2995 : :
5924 rhaas@postgresql.org 2996 : 926232 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
8428 tgl@sss.pgh.pa.us 2997 [ + - ]: 926232 : if (HeapTupleIsValid(tp))
2998 : : {
2999 : 926232 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
3000 : : Oid result;
3001 : :
1973 3002 [ + + + + ]: 926232 : if (IsTrueArrayType(typtup))
8428 3003 : 82158 : result = typtup->typelem;
3004 : : else
3005 : 844074 : result = InvalidOid;
3006 : 926232 : ReleaseSysCache(tp);
3007 : 926232 : return result;
3008 : : }
3009 : : else
8428 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
8428 tgl@sss.pgh.pa.us 3020 :CBC 113707 : get_array_type(Oid typid)
3021 : : {
3022 : : HeapTuple tp;
6746 bruce@momjian.us 3023 : 113707 : Oid result = InvalidOid;
3024 : :
5924 rhaas@postgresql.org 3025 : 113707 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
8428 tgl@sss.pgh.pa.us 3026 [ + - ]: 113707 : if (HeapTupleIsValid(tp))
3027 : : {
6934 3028 : 113707 : result = ((Form_pg_type) GETSTRUCT(tp))->typarray;
8428 3029 : 113707 : ReleaseSysCache(tp);
3030 : : }
6934 3031 : 113707 : 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
4179 3044 : 12372 : get_promoted_array_type(Oid typid)
3045 : : {
3046 : 12372 : Oid array_type = get_array_type(typid);
3047 : :
3048 [ + + ]: 12372 : if (OidIsValid(array_type))
3049 : 12346 : return array_type;
3050 [ + - ]: 26 : if (OidIsValid(get_element_type(typid)))
3051 : 26 : return typid;
4179 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
5675 tgl@sss.pgh.pa.us 3065 :CBC 163328 : 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 : 163372 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3076 [ + + ]: 163372 : if (!HeapTupleIsValid(tup))
3077 : 179 : break;
3078 : 163193 : typTup = (Form_pg_type) GETSTRUCT(tup);
3079 [ + + ]: 163193 : 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 */
1973 3085 [ + + + + ]: 163149 : if (IsTrueArrayType(typTup))
5675 3086 : 52324 : result = typTup->typelem;
3087 : : else
3088 : 110825 : result = InvalidOid;
3089 : 163149 : ReleaseSysCache(tup);
3090 : 163149 : 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
8003 3107 : 425763 : getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
3108 : : {
3109 : : HeapTuple typeTuple;
3110 : : Form_pg_type pt;
3111 : :
5924 rhaas@postgresql.org 3112 : 425763 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
8650 tgl@sss.pgh.pa.us 3113 [ - + ]: 425763 : if (!HeapTupleIsValid(typeTuple))
8320 tgl@sss.pgh.pa.us 3114 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", type);
8650 tgl@sss.pgh.pa.us 3115 :CBC 425763 : pt = (Form_pg_type) GETSTRUCT(typeTuple);
3116 : :
3117 [ - + ]: 425763 : if (!pt->typisdefined)
8320 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))));
8397 tgl@sss.pgh.pa.us 3122 [ - + ]:CBC 425763 : if (!OidIsValid(pt->typinput))
8320 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 : :
8650 tgl@sss.pgh.pa.us 3128 :CBC 425763 : *typInput = pt->typinput;
8003 3129 : 425763 : *typIOParam = getTypeIOParam(typeTuple);
3130 : :
8650 3131 : 425763 : ReleaseSysCache(typeTuple);
3132 : 425763 : }
3133 : :
3134 : : /*
3135 : : * getTypeOutputInfo
3136 : : *
3137 : : * Get info needed for printing values of a type
3138 : : */
3139 : : void
7674 3140 : 1068659 : getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
3141 : : {
3142 : : HeapTuple typeTuple;
3143 : : Form_pg_type pt;
3144 : :
5924 rhaas@postgresql.org 3145 : 1068659 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
8657 tgl@sss.pgh.pa.us 3146 [ - + ]: 1068659 : if (!HeapTupleIsValid(typeTuple))
8320 tgl@sss.pgh.pa.us 3147 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", type);
8657 tgl@sss.pgh.pa.us 3148 :CBC 1068659 : pt = (Form_pg_type) GETSTRUCT(typeTuple);
3149 : :
8397 3150 [ - + ]: 1068659 : if (!pt->typisdefined)
8320 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))));
8397 tgl@sss.pgh.pa.us 3155 [ - + ]:CBC 1068659 : if (!OidIsValid(pt->typoutput))
8320 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 : :
8657 tgl@sss.pgh.pa.us 3161 :CBC 1068659 : *typOutput = pt->typoutput;
3162 [ + + + + ]: 1068659 : *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
3163 : :
8397 3164 : 1068659 : ReleaseSysCache(typeTuple);
3165 : 1068659 : }
3166 : :
3167 : : /*
3168 : : * getTypeBinaryInputInfo
3169 : : *
3170 : : * Get info needed for binary input of values of a type
3171 : : */
3172 : : void
8003 3173 : 157613 : getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
3174 : : {
3175 : : HeapTuple typeTuple;
3176 : : Form_pg_type pt;
3177 : :
5924 rhaas@postgresql.org 3178 : 157613 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
8397 tgl@sss.pgh.pa.us 3179 [ - + ]: 157613 : if (!HeapTupleIsValid(typeTuple))
8320 tgl@sss.pgh.pa.us 3180 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", type);
8397 tgl@sss.pgh.pa.us 3181 :CBC 157613 : pt = (Form_pg_type) GETSTRUCT(typeTuple);
3182 : :
3183 [ - + ]: 157613 : if (!pt->typisdefined)
8320 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))));
8397 tgl@sss.pgh.pa.us 3188 [ + + ]:CBC 157613 : if (!OidIsValid(pt->typreceive))
8320 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 : :
8397 3194 : 157612 : *typReceive = pt->typreceive;
8003 3195 : 157612 : *typIOParam = getTypeIOParam(typeTuple);
3196 : :
8397 3197 : 157612 : ReleaseSysCache(typeTuple);
3198 : 157612 : }
3199 : :
3200 : : /*
3201 : : * getTypeBinaryOutputInfo
3202 : : *
3203 : : * Get info needed for binary output of values of a type
3204 : : */
3205 : : void
7674 3206 : 1426 : getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
3207 : : {
3208 : : HeapTuple typeTuple;
3209 : : Form_pg_type pt;
3210 : :
5924 rhaas@postgresql.org 3211 : 1426 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
8397 tgl@sss.pgh.pa.us 3212 [ - + ]: 1426 : if (!HeapTupleIsValid(typeTuple))
8320 tgl@sss.pgh.pa.us 3213 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", type);
8397 tgl@sss.pgh.pa.us 3214 :CBC 1426 : pt = (Form_pg_type) GETSTRUCT(typeTuple);
3215 : :
3216 [ - + ]: 1426 : if (!pt->typisdefined)
8320 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))));
8397 tgl@sss.pgh.pa.us 3221 [ + + ]:CBC 1426 : if (!OidIsValid(pt->typsend))
8320 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 : :
8397 3227 : 1425 : *typSend = pt->typsend;
3228 [ + + + + ]: 1425 : *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
3229 : :
8657 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
7066 tgl@sss.pgh.pa.us 3239 :UBC 0 : get_typmodin(Oid typid)
3240 : : {
3241 : : HeapTuple tp;
3242 : :
5924 rhaas@postgresql.org 3243 : 0 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
7066 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
5565 peter_e@gmx.net 3289 :CBC 1762061 : get_typcollation(Oid typid)
3290 : : {
3291 : : HeapTuple tp;
3292 : :
3293 : 1762061 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3294 [ + + ]: 1762061 : if (HeapTupleIsValid(tp))
3295 : : {
3296 : 1761753 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
3297 : : Oid result;
3298 : :
3299 : 1761753 : result = typtup->typcollation;
3300 : 1761753 : ReleaseSysCache(tp);
3301 : 1761753 : 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 : 328492 : type_is_collatable(Oid typid)
3315 : : {
3316 : 328492 : 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
1973 tgl@sss.pgh.pa.us 3330 : 29389 : get_typsubscript(Oid typid, Oid *typelemp)
3331 : : {
3332 : : HeapTuple tp;
3333 : :
3334 : 29389 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3335 [ + - ]: 29389 : if (HeapTupleIsValid(tp))
3336 : : {
3337 : 29389 : Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
3338 : 29389 : RegProcedure handler = typform->typsubscript;
3339 : :
3340 [ + + ]: 29389 : if (typelemp)
3341 : 9058 : *typelemp = typform->typelem;
3342 : 29389 : ReleaseSysCache(tp);
3343 : 29389 : return handler;
3344 : : }
3345 : : else
3346 : : {
1973 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 *
1973 tgl@sss.pgh.pa.us 3363 :CBC 29388 : getSubscriptingRoutines(Oid typid, Oid *typelemp)
3364 : : {
3365 : 29388 : RegProcedure typsubscript = get_typsubscript(typid, typelemp);
3366 : :
3367 [ + + ]: 29388 : if (!OidIsValid(typsubscript))
1971 3368 : 6 : return NULL;
3369 : :
1973 3370 : 29382 : return (const struct SubscriptRoutines *)
3371 : 29382 : 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
9127 3391 : 1213276 : get_attavgwidth(Oid relid, AttrNumber attnum)
3392 : : {
3393 : : HeapTuple tp;
3394 : : int32 stawidth;
3395 : :
6428 3396 [ - + ]: 1213276 : if (get_attavgwidth_hook)
3397 : : {
6428 tgl@sss.pgh.pa.us 3398 :UBC 0 : stawidth = (*get_attavgwidth_hook) (relid, attnum);
3399 [ # # ]: 0 : if (stawidth > 0)
3400 : 0 : return stawidth;
3401 : : }
5924 rhaas@postgresql.org 3402 :CBC 1213276 : tp = SearchSysCache3(STATRELATTINH,
3403 : : ObjectIdGetDatum(relid),
3404 : : Int16GetDatum(attnum),
3405 : : BoolGetDatum(false));
9127 tgl@sss.pgh.pa.us 3406 [ + + ]: 1213276 : if (HeapTupleIsValid(tp))
3407 : : {
6428 3408 : 562529 : stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
9127 3409 : 562529 : ReleaseSysCache(tp);
3410 [ + + ]: 562529 : if (stawidth > 0)
3411 : 549522 : return stawidth;
3412 : : }
3413 : 663754 : 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
3279 3467 : 1935403 : get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple,
3468 : : int reqkind, Oid reqop, int flags)
3469 : : {
9129 3470 : 1935403 : 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 */
3279 3480 : 1935403 : memset(sslot, 0, sizeof(AttStatsSlot));
3481 : :
9129 3482 [ + + ]: 5295339 : for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
3483 : : {
3484 [ + + + + ]: 4761098 : if ((&stats->stakind1)[i] == reqkind &&
3485 [ - + ]: 542306 : (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
3486 : : break;
3487 : : }
3488 [ + + ]: 1935403 : if (i >= STATISTIC_NUM_SLOTS)
3489 : 534241 : return false; /* not there */
3490 : :
3279 3491 : 1401162 : sslot->staop = (&stats->staop1)[i];
2699 3492 : 1401162 : sslot->stacoll = (&stats->stacoll1)[i];
3493 : :
3279 3494 [ + + ]: 1401162 : if (flags & ATTSTATSSLOT_VALUES)
3495 : : {
1137 dgustafsson@postgres 3496 : 624692 : val = SysCacheGetAttrNotNull(STATRELATTINH, statstuple,
3497 : 624692 : 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 : : */
3279 tgl@sss.pgh.pa.us 3503 : 624692 : 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 : 624692 : sslot->valuetype = arrayelemtype = ARR_ELEMTYPE(statarray);
3510 : :
3511 : : /* Need info about element type */
5779 3512 : 624692 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrayelemtype));
9129 3513 [ - + ]: 624692 : if (!HeapTupleIsValid(typeTuple))
5779 tgl@sss.pgh.pa.us 3514 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", arrayelemtype);
8444 tgl@sss.pgh.pa.us 3515 :CBC 624692 : typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
3516 : :
3517 : : /* Deconstruct array into Datum elements; NULLs not expected */
3518 : 624692 : deconstruct_array(statarray,
3519 : : arrayelemtype,
3520 : 624692 : typeForm->typlen,
3521 : 624692 : typeForm->typbyval,
3522 : 624692 : 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 [ + + ]: 624692 : if (!typeForm->typbyval)
3279 3532 : 38575 : sslot->values_arr = statarray;
3533 : : else
3534 : 586117 : pfree(statarray);
3535 : :
8444 3536 : 624692 : ReleaseSysCache(typeTuple);
3537 : : }
3538 : :
3279 3539 [ + + ]: 1401162 : if (flags & ATTSTATSSLOT_NUMBERS)
3540 : : {
1137 dgustafsson@postgres 3541 : 1015105 : val = SysCacheGetAttrNotNull(STATRELATTINH, statstuple,
3542 : 1015105 : 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 : : */
3279 tgl@sss.pgh.pa.us 3548 : 1015105 : 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 : : */
9129 3555 : 1015105 : narrayelem = ARR_DIMS(statarray)[0];
3556 [ + - + - ]: 1015105 : if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
7474 3557 [ + - ]: 1015105 : ARR_HASNULL(statarray) ||
8653 3558 [ - + ]: 1015105 : ARR_ELEMTYPE(statarray) != FLOAT4OID)
8320 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 */
3279 tgl@sss.pgh.pa.us 3562 [ - + ]:CBC 1015105 : sslot->numbers = (float4 *) ARR_DATA_PTR(statarray);
3563 : 1015105 : sslot->nnumbers = narrayelem;
3564 : :
3565 : : /* We'll free the statarray in free_attstatsslot */
3566 : 1015105 : sslot->numbers_arr = statarray;
3567 : : }
3568 : :
9129 3569 : 1401162 : return true;
3570 : : }
3571 : :
3572 : : /*
3573 : : * free_attstatsslot
3574 : : * Free data allocated by get_attstatsslot
3575 : : */
3576 : : void
3279 3577 : 1680556 : free_attstatsslot(AttStatsSlot *sslot)
3578 : : {
3579 : : /* The values[] array was separately palloc'd by deconstruct_array */
3580 [ + + ]: 1680556 : if (sslot->values)
3581 : 624692 : pfree(sslot->values);
3582 : : /* The numbers[] array points into numbers_arr, do not pfree it */
3583 : : /* Free the detoasted array objects, if any */
3584 [ + + ]: 1680556 : if (sslot->values_arr)
3585 : 38575 : pfree(sslot->values_arr);
3586 [ + + ]: 1680556 : if (sslot->numbers_arr)
3587 : 1015105 : pfree(sslot->numbers_arr);
9129 3588 : 1680556 : }
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 *
8799 3599 : 1119398 : get_namespace_name(Oid nspid)
3600 : : {
3601 : : HeapTuple tp;
3602 : :
5924 rhaas@postgresql.org 3603 : 1119398 : tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
8799 tgl@sss.pgh.pa.us 3604 [ + + ]: 1119398 : if (HeapTupleIsValid(tp))
3605 : : {
3606 : 1119383 : Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
3607 : : char *result;
3608 : :
3609 : 1119383 : result = pstrdup(NameStr(nsptup->nspname));
3610 : 1119383 : ReleaseSysCache(tp);
3611 : 1119383 : return result;
3612 : : }
3613 : : else
3614 : 15 : 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 *
4047 alvherre@alvh.no-ip. 3623 : 151014 : get_namespace_name_or_temp(Oid nspid)
3624 : : {
3625 [ + + ]: 151014 : if (isTempNamespace(nspid))
1743 tgl@sss.pgh.pa.us 3626 : 2548 : return pstrdup("pg_temp");
3627 : : else
4047 alvherre@alvh.no-ip. 3628 : 148466 : return get_namespace_name(nspid);
3629 : : }
3630 : :
3631 : : /* ---------- PG_RANGE CACHES ---------- */
3632 : :
3633 : : /*
3634 : : * get_range_subtype
3635 : : * Returns the subtype of a given range type
3636 : : *
3637 : : * Returns InvalidOid if the type is not a range type.
3638 : : */
3639 : : Oid
5297 heikki.linnakangas@i 3640 : 18049 : get_range_subtype(Oid rangeOid)
3641 : : {
3642 : : HeapTuple tp;
3643 : :
3644 : 18049 : tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
3645 [ + + ]: 18049 : if (HeapTupleIsValid(tp))
3646 : : {
5077 bruce@momjian.us 3647 : 14706 : Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
3648 : : Oid result;
3649 : :
5297 heikki.linnakangas@i 3650 : 14706 : result = rngtup->rngsubtype;
3651 : 14706 : ReleaseSysCache(tp);
3652 : 14706 : return result;
3653 : : }
3654 : : else
3655 : 3343 : return InvalidOid;
3656 : : }
3657 : :
3658 : : /*
3659 : : * get_range_collation
3660 : : * Returns the collation of a given range type
3661 : : *
3662 : : * Returns InvalidOid if the type is not a range type,
3663 : : * or if its subtype is not collatable.
3664 : : */
3665 : : Oid
2286 tgl@sss.pgh.pa.us 3666 : 1946 : get_range_collation(Oid rangeOid)
3667 : : {
3668 : : HeapTuple tp;
3669 : :
3670 : 1946 : tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
3671 [ + - ]: 1946 : if (HeapTupleIsValid(tp))
3672 : : {
3673 : 1946 : Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
3674 : : Oid result;
3675 : :
3676 : 1946 : result = rngtup->rngcollation;
3677 : 1946 : ReleaseSysCache(tp);
3678 : 1946 : return result;
3679 : : }
3680 : : else
2286 tgl@sss.pgh.pa.us 3681 :UBC 0 : return InvalidOid;
3682 : : }
3683 : :
3684 : : /*
3685 : : * get_range_constructor2
3686 : : * Gets the 2-arg constructor for the given rangetype.
3687 : : *
3688 : : * Raises an error if not found.
3689 : : */
3690 : : RegProcedure
34 peter@eisentraut.org 3691 :GNC 731 : get_range_constructor2(Oid rangeOid)
3692 : : {
3693 : : HeapTuple tp;
3694 : :
3695 : 731 : tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
3696 [ + - ]: 731 : if (HeapTupleIsValid(tp))
3697 : : {
3698 : 731 : Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
3699 : : RegProcedure result;
3700 : :
3701 : 731 : result = rngtup->rngconstruct2;
3702 : 731 : ReleaseSysCache(tp);
3703 : 731 : return result;
3704 : : }
3705 : : else
34 peter@eisentraut.org 3706 [ # # ]:UNC 0 : elog(ERROR, "cache lookup failed for range type %u", rangeOid);
3707 : : }
3708 : :
3709 : : /*
3710 : : * get_range_multirange
3711 : : * Returns the multirange type of a given range type
3712 : : *
3713 : : * Returns InvalidOid if the type is not a range type.
3714 : : */
3715 : : Oid
1962 akorotkov@postgresql 3716 :CBC 229 : get_range_multirange(Oid rangeOid)
3717 : : {
3718 : : HeapTuple tp;
3719 : :
3720 : 229 : tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
3721 [ + - ]: 229 : if (HeapTupleIsValid(tp))
3722 : : {
3723 : 229 : Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
3724 : : Oid result;
3725 : :
3726 : 229 : result = rngtup->rngmultitypid;
3727 : 229 : ReleaseSysCache(tp);
3728 : 229 : return result;
3729 : : }
3730 : : else
1962 akorotkov@postgresql 3731 :UBC 0 : return InvalidOid;
3732 : : }
3733 : :
3734 : : /*
3735 : : * get_multirange_range
3736 : : * Returns the range type of a given multirange
3737 : : *
3738 : : * Returns InvalidOid if the type is not a multirange.
3739 : : */
3740 : : Oid
1962 akorotkov@postgresql 3741 :CBC 13969 : get_multirange_range(Oid multirangeOid)
3742 : : {
3743 : : HeapTuple tp;
3744 : :
3745 : 13969 : tp = SearchSysCache1(RANGEMULTIRANGE, ObjectIdGetDatum(multirangeOid));
3746 [ + + ]: 13969 : if (HeapTupleIsValid(tp))
3747 : : {
3748 : 4682 : Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
3749 : : Oid result;
3750 : :
3751 : 4682 : result = rngtup->rngtypid;
3752 : 4682 : ReleaseSysCache(tp);
3753 : 4682 : return result;
3754 : : }
3755 : : else
3756 : 9287 : return InvalidOid;
3757 : : }
3758 : :
3759 : : /* ---------- PG_INDEX CACHE ---------- */
3760 : :
3761 : : /*
3762 : : * get_index_column_opclass
3763 : : *
3764 : : * Given the index OID and column number,
3765 : : * return opclass of the index column
3766 : : * or InvalidOid if the index was not found
3767 : : * or column is non-key one.
3768 : : */
3769 : : Oid
2785 3770 : 165 : get_index_column_opclass(Oid index_oid, int attno)
3771 : : {
3772 : : HeapTuple tuple;
3773 : : Form_pg_index rd_index;
3774 : : Datum datum;
3775 : : oidvector *indclass;
3776 : : Oid opclass;
3777 : :
3778 : : /* First we need to know the column's opclass. */
3779 : :
3780 : 165 : tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
3781 [ - + ]: 165 : if (!HeapTupleIsValid(tuple))
2785 akorotkov@postgresql 3782 :UBC 0 : return InvalidOid;
3783 : :
2785 akorotkov@postgresql 3784 :CBC 165 : rd_index = (Form_pg_index) GETSTRUCT(tuple);
3785 : :
3786 : : /* caller is supposed to guarantee this */
3787 [ + - - + ]: 165 : Assert(attno > 0 && attno <= rd_index->indnatts);
3788 : :
3789 : : /* Non-key attributes don't have an opclass */
2430 3790 [ - + ]: 165 : if (attno > rd_index->indnkeyatts)
3791 : : {
2430 akorotkov@postgresql 3792 :UBC 0 : ReleaseSysCache(tuple);
3793 : 0 : return InvalidOid;
3794 : : }
3795 : :
1137 dgustafsson@postgres 3796 :CBC 165 : datum = SysCacheGetAttrNotNull(INDEXRELID, tuple, Anum_pg_index_indclass);
2785 akorotkov@postgresql 3797 : 165 : indclass = ((oidvector *) DatumGetPointer(datum));
3798 : :
2430 3799 [ - + ]: 165 : Assert(attno <= indclass->dim1);
2785 3800 : 165 : opclass = indclass->values[attno - 1];
3801 : :
3802 : 165 : ReleaseSysCache(tuple);
3803 : :
3804 : 165 : return opclass;
3805 : : }
3806 : :
3807 : : /*
3808 : : * get_index_isreplident
3809 : : *
3810 : : * Given the index OID, return pg_index.indisreplident.
3811 : : */
3812 : : bool
2244 peter@eisentraut.org 3813 : 307 : get_index_isreplident(Oid index_oid)
3814 : : {
3815 : : HeapTuple tuple;
3816 : : Form_pg_index rd_index;
3817 : : bool result;
3818 : :
3819 : 307 : tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
3820 [ - + ]: 307 : if (!HeapTupleIsValid(tuple))
2244 peter@eisentraut.org 3821 :UBC 0 : return false;
3822 : :
2244 peter@eisentraut.org 3823 :CBC 307 : rd_index = (Form_pg_index) GETSTRUCT(tuple);
3824 : 307 : result = rd_index->indisreplident;
3825 : 307 : ReleaseSysCache(tuple);
3826 : :
3827 : 307 : return result;
3828 : : }
3829 : :
3830 : : /*
3831 : : * get_index_isvalid
3832 : : *
3833 : : * Given the index OID, return pg_index.indisvalid.
3834 : : */
3835 : : bool
2247 michael@paquier.xyz 3836 : 3904 : get_index_isvalid(Oid index_oid)
3837 : : {
3838 : : bool isvalid;
3839 : : HeapTuple tuple;
3840 : : Form_pg_index rd_index;
3841 : :
3842 : 3904 : tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
3843 [ - + ]: 3904 : if (!HeapTupleIsValid(tuple))
2247 michael@paquier.xyz 3844 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for index %u", index_oid);
3845 : :
2247 michael@paquier.xyz 3846 :CBC 3904 : rd_index = (Form_pg_index) GETSTRUCT(tuple);
3847 : 3904 : isvalid = rd_index->indisvalid;
3848 : 3904 : ReleaseSysCache(tuple);
3849 : :
3850 : 3904 : return isvalid;
3851 : : }
3852 : :
3853 : : /*
3854 : : * get_index_isclustered
3855 : : *
3856 : : * Given the index OID, return pg_index.indisclustered.
3857 : : */
3858 : : bool
2220 3859 : 511 : get_index_isclustered(Oid index_oid)
3860 : : {
3861 : : bool isclustered;
3862 : : HeapTuple tuple;
3863 : : Form_pg_index rd_index;
3864 : :
3865 : 511 : tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
3866 [ - + ]: 511 : if (!HeapTupleIsValid(tuple))
2220 michael@paquier.xyz 3867 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for index %u", index_oid);
3868 : :
2220 michael@paquier.xyz 3869 :CBC 511 : rd_index = (Form_pg_index) GETSTRUCT(tuple);
3870 : 511 : isclustered = rd_index->indisclustered;
3871 : 511 : ReleaseSysCache(tuple);
3872 : :
3873 : 511 : return isclustered;
3874 : : }
3875 : :
3876 : : /*
3877 : : * get_publication_oid - given a publication name, look up the OID
3878 : : *
3879 : : * If missing_ok is false, throw an error if name not found. If true, just
3880 : : * return InvalidOid.
3881 : : */
3882 : : Oid
1372 akapila@postgresql.o 3883 : 2200 : get_publication_oid(const char *pubname, bool missing_ok)
3884 : : {
3885 : : Oid oid;
3886 : :
3887 : 2200 : oid = GetSysCacheOid1(PUBLICATIONNAME, Anum_pg_publication_oid,
3888 : : CStringGetDatum(pubname));
3889 [ + + + + ]: 2200 : if (!OidIsValid(oid) && !missing_ok)
3890 [ + - ]: 4 : ereport(ERROR,
3891 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
3892 : : errmsg("publication \"%s\" does not exist", pubname)));
3893 : 2196 : return oid;
3894 : : }
3895 : :
3896 : : /*
3897 : : * get_publication_name - given a publication Oid, look up the name
3898 : : *
3899 : : * If missing_ok is false, throw an error if name not found. If true, just
3900 : : * return NULL.
3901 : : */
3902 : : char *
3903 : 512 : get_publication_name(Oid pubid, bool missing_ok)
3904 : : {
3905 : : HeapTuple tup;
3906 : : char *pubname;
3907 : : Form_pg_publication pubform;
3908 : :
3909 : 512 : tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
3910 : :
3911 [ + + ]: 512 : if (!HeapTupleIsValid(tup))
3912 : : {
3913 [ - + ]: 12 : if (!missing_ok)
1372 akapila@postgresql.o 3914 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for publication %u", pubid);
1372 akapila@postgresql.o 3915 :CBC 12 : return NULL;
3916 : : }
3917 : :
3918 : 500 : pubform = (Form_pg_publication) GETSTRUCT(tup);
3919 : 500 : pubname = pstrdup(NameStr(pubform->pubname));
3920 : :
3921 : 500 : ReleaseSysCache(tup);
3922 : :
3923 : 500 : return pubname;
3924 : : }
3925 : :
3926 : : /*
3927 : : * get_subscription_oid - given a subscription name, look up the OID
3928 : : *
3929 : : * If missing_ok is false, throw an error if name not found. If true, just
3930 : : * return InvalidOid.
3931 : : */
3932 : : Oid
1082 tgl@sss.pgh.pa.us 3933 : 47 : get_subscription_oid(const char *subname, bool missing_ok)
3934 : : {
3935 : : Oid oid;
3936 : :
1372 akapila@postgresql.o 3937 : 47 : oid = GetSysCacheOid2(SUBSCRIPTIONNAME, Anum_pg_subscription_oid,
3938 : : ObjectIdGetDatum(MyDatabaseId), CStringGetDatum(subname));
3939 [ + + + - ]: 47 : if (!OidIsValid(oid) && !missing_ok)
3940 [ + - ]: 4 : ereport(ERROR,
3941 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
3942 : : errmsg("subscription \"%s\" does not exist", subname)));
3943 : 43 : return oid;
3944 : : }
3945 : :
3946 : : /*
3947 : : * get_subscription_name - given a subscription OID, look up the name
3948 : : *
3949 : : * If missing_ok is false, throw an error if name not found. If true, just
3950 : : * return NULL.
3951 : : */
3952 : : char *
3953 : 40 : get_subscription_name(Oid subid, bool missing_ok)
3954 : : {
3955 : : HeapTuple tup;
3956 : : char *subname;
3957 : : Form_pg_subscription subform;
3958 : :
3959 : 40 : tup = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(subid));
3960 : :
3961 [ + + ]: 40 : if (!HeapTupleIsValid(tup))
3962 : : {
3963 [ - + ]: 12 : if (!missing_ok)
1372 akapila@postgresql.o 3964 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for subscription %u", subid);
1372 akapila@postgresql.o 3965 :CBC 12 : return NULL;
3966 : : }
3967 : :
3968 : 28 : subform = (Form_pg_subscription) GETSTRUCT(tup);
3969 : 28 : subname = pstrdup(NameStr(subform->subname));
3970 : :
3971 : 28 : ReleaseSysCache(tup);
3972 : :
3973 : 28 : return subname;
3974 : : }
3975 : :
3976 : : char *
50 peter@eisentraut.org 3977 :GNC 1106 : get_propgraph_label_name(Oid labeloid)
3978 : : {
3979 : : HeapTuple tuple;
3980 : : char *labelname;
3981 : :
15 3982 : 1106 : tuple = SearchSysCache1(PROPGRAPHLABELOID, ObjectIdGetDatum(labeloid));
50 3983 [ - + ]: 1106 : if (!tuple)
3984 : : {
50 peter@eisentraut.org 3985 [ # # ]:UNC 0 : elog(ERROR, "cache lookup failed for label %u", labeloid);
3986 : : return NULL;
3987 : : }
50 peter@eisentraut.org 3988 :GNC 1106 : labelname = pstrdup(NameStr(((Form_pg_propgraph_label) GETSTRUCT(tuple))->pgllabel));
3989 : 1106 : ReleaseSysCache(tuple);
3990 : :
3991 : 1106 : return labelname;
3992 : : }
3993 : :
3994 : : char *
3995 : 3672 : get_propgraph_property_name(Oid propoid)
3996 : : {
3997 : : HeapTuple tuple;
3998 : : char *propname;
3999 : :
15 4000 : 3672 : tuple = SearchSysCache1(PROPGRAPHPROPOID, ObjectIdGetDatum(propoid));
50 4001 [ - + ]: 3672 : if (!tuple)
4002 : : {
50 peter@eisentraut.org 4003 [ # # ]:UNC 0 : elog(ERROR, "cache lookup failed for property %u", propoid);
4004 : : return NULL;
4005 : : }
50 peter@eisentraut.org 4006 :GNC 3672 : propname = pstrdup(NameStr(((Form_pg_propgraph_property) GETSTRUCT(tuple))->pgpname));
4007 : 3672 : ReleaseSysCache(tuple);
4008 : :
4009 : 3672 : return propname;
4010 : : }
|