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