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