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