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