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-2017, 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 "access/nbtree.h"
21 : #include "bootstrap/bootstrap.h"
22 : #include "catalog/namespace.h"
23 : #include "catalog/pg_am.h"
24 : #include "catalog/pg_amop.h"
25 : #include "catalog/pg_amproc.h"
26 : #include "catalog/pg_collation.h"
27 : #include "catalog/pg_constraint.h"
28 : #include "catalog/pg_language.h"
29 : #include "catalog/pg_namespace.h"
30 : #include "catalog/pg_opclass.h"
31 : #include "catalog/pg_operator.h"
32 : #include "catalog/pg_proc.h"
33 : #include "catalog/pg_range.h"
34 : #include "catalog/pg_statistic.h"
35 : #include "catalog/pg_transform.h"
36 : #include "catalog/pg_type.h"
37 : #include "miscadmin.h"
38 : #include "nodes/makefuncs.h"
39 : #include "utils/array.h"
40 : #include "utils/builtins.h"
41 : #include "utils/catcache.h"
42 : #include "utils/datum.h"
43 : #include "utils/fmgroids.h"
44 : #include "utils/lsyscache.h"
45 : #include "utils/rel.h"
46 : #include "utils/syscache.h"
47 : #include "utils/typcache.h"
48 :
49 : /* Hook for plugins to get control in get_attavgwidth() */
50 : get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
51 :
52 :
53 : /* ---------- AMOP CACHES ---------- */
54 :
55 : /*
56 : * op_in_opfamily
57 : *
58 : * Return t iff operator 'opno' is in operator family 'opfamily'.
59 : *
60 : * This function only considers search operators, not ordering operators.
61 : */
62 : bool
63 13369 : op_in_opfamily(Oid opno, Oid opfamily)
64 : {
65 13369 : return SearchSysCacheExists3(AMOPOPID,
66 : ObjectIdGetDatum(opno),
67 : CharGetDatum(AMOP_SEARCH),
68 : ObjectIdGetDatum(opfamily));
69 : }
70 :
71 : /*
72 : * get_op_opfamily_strategy
73 : *
74 : * Get the operator's strategy number within the specified opfamily,
75 : * or 0 if it's not a member of the opfamily.
76 : *
77 : * This function only considers search operators, not ordering operators.
78 : */
79 : int
80 15402 : get_op_opfamily_strategy(Oid opno, Oid opfamily)
81 : {
82 : HeapTuple tp;
83 : Form_pg_amop amop_tup;
84 : int result;
85 :
86 15402 : tp = SearchSysCache3(AMOPOPID,
87 : ObjectIdGetDatum(opno),
88 : CharGetDatum(AMOP_SEARCH),
89 : ObjectIdGetDatum(opfamily));
90 15402 : if (!HeapTupleIsValid(tp))
91 0 : return 0;
92 15402 : amop_tup = (Form_pg_amop) GETSTRUCT(tp);
93 15402 : result = amop_tup->amopstrategy;
94 15402 : ReleaseSysCache(tp);
95 15402 : return result;
96 : }
97 :
98 : /*
99 : * get_op_opfamily_sortfamily
100 : *
101 : * If the operator is an ordering operator within the specified opfamily,
102 : * return its amopsortfamily OID; else return InvalidOid.
103 : */
104 : Oid
105 23 : get_op_opfamily_sortfamily(Oid opno, Oid opfamily)
106 : {
107 : HeapTuple tp;
108 : Form_pg_amop amop_tup;
109 : Oid result;
110 :
111 23 : tp = SearchSysCache3(AMOPOPID,
112 : ObjectIdGetDatum(opno),
113 : CharGetDatum(AMOP_ORDER),
114 : ObjectIdGetDatum(opfamily));
115 23 : if (!HeapTupleIsValid(tp))
116 0 : return InvalidOid;
117 23 : amop_tup = (Form_pg_amop) GETSTRUCT(tp);
118 23 : result = amop_tup->amopsortfamily;
119 23 : ReleaseSysCache(tp);
120 23 : return result;
121 : }
122 :
123 : /*
124 : * get_op_opfamily_properties
125 : *
126 : * Get the operator's strategy number and declared input data types
127 : * within the specified opfamily.
128 : *
129 : * Caller should already have verified that opno is a member of opfamily,
130 : * therefore we raise an error if the tuple is not found.
131 : */
132 : void
133 15559 : get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op,
134 : int *strategy,
135 : Oid *lefttype,
136 : Oid *righttype)
137 : {
138 : HeapTuple tp;
139 : Form_pg_amop amop_tup;
140 :
141 15559 : tp = SearchSysCache3(AMOPOPID,
142 : ObjectIdGetDatum(opno),
143 : CharGetDatum(ordering_op ? AMOP_ORDER : AMOP_SEARCH),
144 : ObjectIdGetDatum(opfamily));
145 15559 : if (!HeapTupleIsValid(tp))
146 0 : elog(ERROR, "operator %u is not a member of opfamily %u",
147 : opno, opfamily);
148 15559 : amop_tup = (Form_pg_amop) GETSTRUCT(tp);
149 15559 : *strategy = amop_tup->amopstrategy;
150 15559 : *lefttype = amop_tup->amoplefttype;
151 15559 : *righttype = amop_tup->amoprighttype;
152 15559 : ReleaseSysCache(tp);
153 15559 : }
154 :
155 : /*
156 : * get_opfamily_member
157 : * Get the OID of the operator that implements the specified strategy
158 : * with the specified datatypes for the specified opfamily.
159 : *
160 : * Returns InvalidOid if there is no pg_amop entry for the given keys.
161 : */
162 : Oid
163 82002 : get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
164 : int16 strategy)
165 : {
166 : HeapTuple tp;
167 : Form_pg_amop amop_tup;
168 : Oid result;
169 :
170 82002 : tp = SearchSysCache4(AMOPSTRATEGY,
171 : ObjectIdGetDatum(opfamily),
172 : ObjectIdGetDatum(lefttype),
173 : ObjectIdGetDatum(righttype),
174 : Int16GetDatum(strategy));
175 82002 : if (!HeapTupleIsValid(tp))
176 64 : return InvalidOid;
177 81938 : amop_tup = (Form_pg_amop) GETSTRUCT(tp);
178 81938 : result = amop_tup->amopopr;
179 81938 : ReleaseSysCache(tp);
180 81938 : return result;
181 : }
182 :
183 : /*
184 : * get_ordering_op_properties
185 : * Given the OID of an ordering operator (a btree "<" or ">" operator),
186 : * determine its opfamily, its declared input datatype, and its
187 : * strategy number (BTLessStrategyNumber or BTGreaterStrategyNumber).
188 : *
189 : * Returns TRUE if successful, FALSE if no matching pg_amop entry exists.
190 : * (This indicates that the operator is not a valid ordering operator.)
191 : *
192 : * Note: the operator could be registered in multiple families, for example
193 : * if someone were to build a "reverse sort" opfamily. This would result in
194 : * uncertainty as to whether "ORDER BY USING op" would default to NULLS FIRST
195 : * or NULLS LAST, as well as inefficient planning due to failure to match up
196 : * pathkeys that should be the same. So we want a determinate result here.
197 : * Because of the way the syscache search works, we'll use the interpretation
198 : * associated with the opfamily with smallest OID, which is probably
199 : * determinate enough. Since there is no longer any particularly good reason
200 : * to build reverse-sort opfamilies, it doesn't seem worth expending any
201 : * additional effort on ensuring consistency.
202 : */
203 : bool
204 10018 : get_ordering_op_properties(Oid opno,
205 : Oid *opfamily, Oid *opcintype, int16 *strategy)
206 : {
207 10018 : bool result = false;
208 : CatCList *catlist;
209 : int i;
210 :
211 : /* ensure outputs are initialized on failure */
212 10018 : *opfamily = InvalidOid;
213 10018 : *opcintype = InvalidOid;
214 10018 : *strategy = 0;
215 :
216 : /*
217 : * Search pg_amop to see if the target operator is registered as the "<"
218 : * or ">" operator of any btree opfamily.
219 : */
220 10018 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
221 :
222 10018 : for (i = 0; i < catlist->n_members; i++)
223 : {
224 10018 : HeapTuple tuple = &catlist->members[i]->tuple;
225 10018 : Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
226 :
227 : /* must be btree */
228 10018 : if (aform->amopmethod != BTREE_AM_OID)
229 0 : continue;
230 :
231 10427 : if (aform->amopstrategy == BTLessStrategyNumber ||
232 409 : aform->amopstrategy == BTGreaterStrategyNumber)
233 : {
234 : /* Found it ... should have consistent input types */
235 10018 : if (aform->amoplefttype == aform->amoprighttype)
236 : {
237 : /* Found a suitable opfamily, return info */
238 10018 : *opfamily = aform->amopfamily;
239 10018 : *opcintype = aform->amoplefttype;
240 10018 : *strategy = aform->amopstrategy;
241 10018 : result = true;
242 10018 : break;
243 : }
244 : }
245 : }
246 :
247 10018 : ReleaseSysCacheList(catlist);
248 :
249 10018 : return result;
250 : }
251 :
252 : /*
253 : * get_equality_op_for_ordering_op
254 : * Get the OID of the datatype-specific btree equality operator
255 : * associated with an ordering operator (a "<" or ">" operator).
256 : *
257 : * If "reverse" isn't NULL, also set *reverse to FALSE if the operator is "<",
258 : * TRUE if it's ">"
259 : *
260 : * Returns InvalidOid if no matching equality operator can be found.
261 : * (This indicates that the operator is not a valid ordering operator.)
262 : */
263 : Oid
264 157 : get_equality_op_for_ordering_op(Oid opno, bool *reverse)
265 : {
266 157 : Oid result = InvalidOid;
267 : Oid opfamily;
268 : Oid opcintype;
269 : int16 strategy;
270 :
271 : /* Find the operator in pg_amop */
272 157 : if (get_ordering_op_properties(opno,
273 : &opfamily, &opcintype, &strategy))
274 : {
275 : /* Found a suitable opfamily, get matching equality operator */
276 157 : result = get_opfamily_member(opfamily,
277 : opcintype,
278 : opcintype,
279 : BTEqualStrategyNumber);
280 157 : if (reverse)
281 157 : *reverse = (strategy == BTGreaterStrategyNumber);
282 : }
283 :
284 157 : return result;
285 : }
286 :
287 : /*
288 : * get_ordering_op_for_equality_op
289 : * Get the OID of a datatype-specific btree ordering operator
290 : * associated with an equality operator. (If there are multiple
291 : * possibilities, assume any one will do.)
292 : *
293 : * This function is used when we have to sort data before unique-ifying,
294 : * and don't much care which sorting op is used as long as it's compatible
295 : * with the intended equality operator. Since we need a sorting operator,
296 : * it should be single-data-type even if the given operator is cross-type.
297 : * The caller specifies whether to find an op for the LHS or RHS data type.
298 : *
299 : * Returns InvalidOid if no matching ordering operator can be found.
300 : */
301 : Oid
302 0 : get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
303 : {
304 0 : Oid result = InvalidOid;
305 : CatCList *catlist;
306 : int i;
307 :
308 : /*
309 : * Search pg_amop to see if the target operator is registered as the "="
310 : * operator of any btree opfamily.
311 : */
312 0 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
313 :
314 0 : for (i = 0; i < catlist->n_members; i++)
315 : {
316 0 : HeapTuple tuple = &catlist->members[i]->tuple;
317 0 : Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
318 :
319 : /* must be btree */
320 0 : if (aform->amopmethod != BTREE_AM_OID)
321 0 : continue;
322 :
323 0 : if (aform->amopstrategy == BTEqualStrategyNumber)
324 : {
325 : /* Found a suitable opfamily, get matching ordering operator */
326 : Oid typid;
327 :
328 0 : typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
329 0 : result = get_opfamily_member(aform->amopfamily,
330 : typid, typid,
331 : BTLessStrategyNumber);
332 0 : if (OidIsValid(result))
333 0 : break;
334 : /* failure probably shouldn't happen, but keep looking if so */
335 : }
336 : }
337 :
338 0 : ReleaseSysCacheList(catlist);
339 :
340 0 : return result;
341 : }
342 :
343 : /*
344 : * get_mergejoin_opfamilies
345 : * Given a putatively mergejoinable operator, return a list of the OIDs
346 : * of the btree opfamilies in which it represents equality.
347 : *
348 : * It is possible (though at present unusual) for an operator to be equality
349 : * in more than one opfamily, hence the result is a list. This also lets us
350 : * return NIL if the operator is not found in any opfamilies.
351 : *
352 : * The planner currently uses simple equal() tests to compare the lists
353 : * returned by this function, which makes the list order relevant, though
354 : * strictly speaking it should not be. Because of the way syscache list
355 : * searches are handled, in normal operation the result will be sorted by OID
356 : * so everything works fine. If running with system index usage disabled,
357 : * the result ordering is unspecified and hence the planner might fail to
358 : * recognize optimization opportunities ... but that's hardly a scenario in
359 : * which performance is good anyway, so there's no point in expending code
360 : * or cycles here to guarantee the ordering in that case.
361 : */
362 : List *
363 63636 : get_mergejoin_opfamilies(Oid opno)
364 : {
365 63636 : List *result = NIL;
366 : CatCList *catlist;
367 : int i;
368 :
369 : /*
370 : * Search pg_amop to see if the target operator is registered as the "="
371 : * operator of any btree opfamily.
372 : */
373 63636 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
374 :
375 259323 : for (i = 0; i < catlist->n_members; i++)
376 : {
377 195687 : HeapTuple tuple = &catlist->members[i]->tuple;
378 195687 : Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
379 :
380 : /* must be btree equality */
381 261092 : if (aform->amopmethod == BTREE_AM_OID &&
382 65405 : aform->amopstrategy == BTEqualStrategyNumber)
383 65405 : result = lappend_oid(result, aform->amopfamily);
384 : }
385 :
386 63636 : ReleaseSysCacheList(catlist);
387 :
388 63636 : return result;
389 : }
390 :
391 : /*
392 : * get_compatible_hash_operators
393 : * Get the OID(s) of hash equality operator(s) compatible with the given
394 : * operator, but operating on its LHS and/or RHS datatype.
395 : *
396 : * An operator for the LHS type is sought and returned into *lhs_opno if
397 : * lhs_opno isn't NULL. Similarly, an operator for the RHS type is sought
398 : * and returned into *rhs_opno if rhs_opno isn't NULL.
399 : *
400 : * If the given operator is not cross-type, the results should be the same
401 : * operator, but in cross-type situations they will be different.
402 : *
403 : * Returns true if able to find the requested operator(s), false if not.
404 : * (This indicates that the operator should not have been marked oprcanhash.)
405 : */
406 : bool
407 215 : get_compatible_hash_operators(Oid opno,
408 : Oid *lhs_opno, Oid *rhs_opno)
409 : {
410 215 : bool result = false;
411 : CatCList *catlist;
412 : int i;
413 :
414 : /* Ensure output args are initialized on failure */
415 215 : if (lhs_opno)
416 0 : *lhs_opno = InvalidOid;
417 215 : if (rhs_opno)
418 215 : *rhs_opno = InvalidOid;
419 :
420 : /*
421 : * Search pg_amop to see if the target operator is registered as the "="
422 : * operator of any hash opfamily. If the operator is registered in
423 : * multiple opfamilies, assume we can use any one.
424 : */
425 215 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
426 :
427 430 : for (i = 0; i < catlist->n_members; i++)
428 : {
429 430 : HeapTuple tuple = &catlist->members[i]->tuple;
430 430 : Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
431 :
432 645 : if (aform->amopmethod == HASH_AM_OID &&
433 215 : aform->amopstrategy == HTEqualStrategyNumber)
434 : {
435 : /* No extra lookup needed if given operator is single-type */
436 215 : if (aform->amoplefttype == aform->amoprighttype)
437 : {
438 207 : if (lhs_opno)
439 0 : *lhs_opno = opno;
440 207 : if (rhs_opno)
441 207 : *rhs_opno = opno;
442 207 : result = true;
443 207 : break;
444 : }
445 :
446 : /*
447 : * Get the matching single-type operator(s). Failure probably
448 : * shouldn't happen --- it implies a bogus opfamily --- but
449 : * continue looking if so.
450 : */
451 8 : if (lhs_opno)
452 : {
453 0 : *lhs_opno = get_opfamily_member(aform->amopfamily,
454 : aform->amoplefttype,
455 : aform->amoplefttype,
456 : HTEqualStrategyNumber);
457 0 : if (!OidIsValid(*lhs_opno))
458 0 : continue;
459 : /* Matching LHS found, done if caller doesn't want RHS */
460 0 : if (!rhs_opno)
461 : {
462 0 : result = true;
463 0 : break;
464 : }
465 : }
466 8 : if (rhs_opno)
467 : {
468 8 : *rhs_opno = get_opfamily_member(aform->amopfamily,
469 : aform->amoprighttype,
470 : aform->amoprighttype,
471 : HTEqualStrategyNumber);
472 8 : if (!OidIsValid(*rhs_opno))
473 : {
474 : /* Forget any LHS operator from this opfamily */
475 0 : if (lhs_opno)
476 0 : *lhs_opno = InvalidOid;
477 0 : continue;
478 : }
479 : /* Matching RHS found, so done */
480 8 : result = true;
481 8 : break;
482 : }
483 : }
484 : }
485 :
486 215 : ReleaseSysCacheList(catlist);
487 :
488 215 : return result;
489 : }
490 :
491 : /*
492 : * get_op_hash_functions
493 : * Get the OID(s) of the standard hash support function(s) compatible with
494 : * the given operator, operating on its LHS and/or RHS datatype as required.
495 : *
496 : * A function for the LHS type is sought and returned into *lhs_procno if
497 : * lhs_procno isn't NULL. Similarly, a function for the RHS type is sought
498 : * and returned into *rhs_procno if rhs_procno isn't NULL.
499 : *
500 : * If the given operator is not cross-type, the results should be the same
501 : * function, but in cross-type situations they will be different.
502 : *
503 : * Returns true if able to find the requested function(s), false if not.
504 : * (This indicates that the operator should not have been marked oprcanhash.)
505 : */
506 : bool
507 1745 : get_op_hash_functions(Oid opno,
508 : RegProcedure *lhs_procno, RegProcedure *rhs_procno)
509 : {
510 1745 : bool result = false;
511 : CatCList *catlist;
512 : int i;
513 :
514 : /* Ensure output args are initialized on failure */
515 1745 : if (lhs_procno)
516 1745 : *lhs_procno = InvalidOid;
517 1745 : if (rhs_procno)
518 1745 : *rhs_procno = InvalidOid;
519 :
520 : /*
521 : * Search pg_amop to see if the target operator is registered as the "="
522 : * operator of any hash opfamily. If the operator is registered in
523 : * multiple opfamilies, assume we can use any one.
524 : */
525 1745 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
526 :
527 3485 : for (i = 0; i < catlist->n_members; i++)
528 : {
529 3485 : HeapTuple tuple = &catlist->members[i]->tuple;
530 3485 : Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
531 :
532 5230 : if (aform->amopmethod == HASH_AM_OID &&
533 1745 : aform->amopstrategy == HTEqualStrategyNumber)
534 : {
535 : /*
536 : * Get the matching support function(s). Failure probably
537 : * shouldn't happen --- it implies a bogus opfamily --- but
538 : * continue looking if so.
539 : */
540 1745 : if (lhs_procno)
541 : {
542 1745 : *lhs_procno = get_opfamily_proc(aform->amopfamily,
543 : aform->amoplefttype,
544 : aform->amoplefttype,
545 : HASHSTANDARD_PROC);
546 1745 : if (!OidIsValid(*lhs_procno))
547 0 : continue;
548 : /* Matching LHS found, done if caller doesn't want RHS */
549 1745 : if (!rhs_procno)
550 : {
551 0 : result = true;
552 0 : break;
553 : }
554 : /* Only one lookup needed if given operator is single-type */
555 1745 : if (aform->amoplefttype == aform->amoprighttype)
556 : {
557 1714 : *rhs_procno = *lhs_procno;
558 1714 : result = true;
559 1714 : break;
560 : }
561 : }
562 31 : if (rhs_procno)
563 : {
564 31 : *rhs_procno = get_opfamily_proc(aform->amopfamily,
565 : aform->amoprighttype,
566 : aform->amoprighttype,
567 : HASHSTANDARD_PROC);
568 31 : if (!OidIsValid(*rhs_procno))
569 : {
570 : /* Forget any LHS function from this opfamily */
571 0 : if (lhs_procno)
572 0 : *lhs_procno = InvalidOid;
573 0 : continue;
574 : }
575 : /* Matching RHS found, so done */
576 31 : result = true;
577 31 : break;
578 : }
579 : }
580 : }
581 :
582 1745 : ReleaseSysCacheList(catlist);
583 :
584 1745 : return result;
585 : }
586 :
587 : /*
588 : * get_op_btree_interpretation
589 : * Given an operator's OID, find out which btree opfamilies it belongs to,
590 : * and what properties it has within each one. The results are returned
591 : * as a palloc'd list of OpBtreeInterpretation structs.
592 : *
593 : * In addition to the normal btree operators, we consider a <> operator to be
594 : * a "member" of an opfamily if its negator is an equality operator of the
595 : * opfamily. ROWCOMPARE_NE is returned as the strategy number for this case.
596 : */
597 : List *
598 269 : get_op_btree_interpretation(Oid opno)
599 : {
600 269 : List *result = NIL;
601 : OpBtreeInterpretation *thisresult;
602 : CatCList *catlist;
603 : int i;
604 :
605 : /*
606 : * Find all the pg_amop entries containing the operator.
607 : */
608 269 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
609 :
610 918 : for (i = 0; i < catlist->n_members; i++)
611 : {
612 649 : HeapTuple op_tuple = &catlist->members[i]->tuple;
613 649 : Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
614 : StrategyNumber op_strategy;
615 :
616 : /* must be btree */
617 649 : if (op_form->amopmethod != BTREE_AM_OID)
618 390 : continue;
619 :
620 : /* Get the operator's btree strategy number */
621 259 : op_strategy = (StrategyNumber) op_form->amopstrategy;
622 259 : Assert(op_strategy >= 1 && op_strategy <= 5);
623 :
624 259 : thisresult = (OpBtreeInterpretation *)
625 : palloc(sizeof(OpBtreeInterpretation));
626 259 : thisresult->opfamily_id = op_form->amopfamily;
627 259 : thisresult->strategy = op_strategy;
628 259 : thisresult->oplefttype = op_form->amoplefttype;
629 259 : thisresult->oprighttype = op_form->amoprighttype;
630 259 : result = lappend(result, thisresult);
631 : }
632 :
633 269 : ReleaseSysCacheList(catlist);
634 :
635 : /*
636 : * If we didn't find any btree opfamily containing the operator, perhaps
637 : * it is a <> operator. See if it has a negator that is in an opfamily.
638 : */
639 269 : if (result == NIL)
640 : {
641 24 : Oid op_negator = get_negator(opno);
642 :
643 24 : if (OidIsValid(op_negator))
644 : {
645 20 : catlist = SearchSysCacheList1(AMOPOPID,
646 : ObjectIdGetDatum(op_negator));
647 :
648 71 : for (i = 0; i < catlist->n_members; i++)
649 : {
650 51 : HeapTuple op_tuple = &catlist->members[i]->tuple;
651 51 : Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
652 : StrategyNumber op_strategy;
653 :
654 : /* must be btree */
655 51 : if (op_form->amopmethod != BTREE_AM_OID)
656 34 : continue;
657 :
658 : /* Get the operator's btree strategy number */
659 17 : op_strategy = (StrategyNumber) op_form->amopstrategy;
660 17 : Assert(op_strategy >= 1 && op_strategy <= 5);
661 :
662 : /* Only consider negators that are = */
663 17 : if (op_strategy != BTEqualStrategyNumber)
664 0 : continue;
665 :
666 : /* OK, report it with "strategy" ROWCOMPARE_NE */
667 17 : thisresult = (OpBtreeInterpretation *)
668 : palloc(sizeof(OpBtreeInterpretation));
669 17 : thisresult->opfamily_id = op_form->amopfamily;
670 17 : thisresult->strategy = ROWCOMPARE_NE;
671 17 : thisresult->oplefttype = op_form->amoplefttype;
672 17 : thisresult->oprighttype = op_form->amoprighttype;
673 17 : result = lappend(result, thisresult);
674 : }
675 :
676 20 : ReleaseSysCacheList(catlist);
677 : }
678 : }
679 :
680 269 : return result;
681 : }
682 :
683 : /*
684 : * equality_ops_are_compatible
685 : * Return TRUE if the two given equality operators have compatible
686 : * semantics.
687 : *
688 : * This is trivially true if they are the same operator. Otherwise,
689 : * we look to see if they can be found in the same btree or hash opfamily.
690 : * Either finding allows us to assume that they have compatible notions
691 : * of equality. (The reason we need to do these pushups is that one might
692 : * be a cross-type operator; for instance int24eq vs int4eq.)
693 : */
694 : bool
695 20 : equality_ops_are_compatible(Oid opno1, Oid opno2)
696 : {
697 : bool result;
698 : CatCList *catlist;
699 : int i;
700 :
701 : /* Easy if they're the same operator */
702 20 : if (opno1 == opno2)
703 19 : return true;
704 :
705 : /*
706 : * We search through all the pg_amop entries for opno1.
707 : */
708 1 : catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno1));
709 :
710 1 : result = false;
711 1 : for (i = 0; i < catlist->n_members; i++)
712 : {
713 1 : HeapTuple op_tuple = &catlist->members[i]->tuple;
714 1 : Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
715 :
716 : /* must be btree or hash */
717 1 : if (op_form->amopmethod == BTREE_AM_OID ||
718 0 : op_form->amopmethod == HASH_AM_OID)
719 : {
720 1 : if (op_in_opfamily(opno2, op_form->amopfamily))
721 : {
722 1 : result = true;
723 1 : break;
724 : }
725 : }
726 : }
727 :
728 1 : ReleaseSysCacheList(catlist);
729 :
730 1 : return result;
731 : }
732 :
733 :
734 : /* ---------- AMPROC CACHES ---------- */
735 :
736 : /*
737 : * get_opfamily_proc
738 : * Get the OID of the specified support function
739 : * for the specified opfamily and datatypes.
740 : *
741 : * Returns InvalidOid if there is no pg_amproc entry for the given keys.
742 : */
743 : Oid
744 14390 : get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
745 : {
746 : HeapTuple tp;
747 : Form_pg_amproc amproc_tup;
748 : RegProcedure result;
749 :
750 14390 : tp = SearchSysCache4(AMPROCNUM,
751 : ObjectIdGetDatum(opfamily),
752 : ObjectIdGetDatum(lefttype),
753 : ObjectIdGetDatum(righttype),
754 : Int16GetDatum(procnum));
755 14390 : if (!HeapTupleIsValid(tp))
756 543 : return InvalidOid;
757 13847 : amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
758 13847 : result = amproc_tup->amproc;
759 13847 : ReleaseSysCache(tp);
760 13847 : return result;
761 : }
762 :
763 :
764 : /* ---------- ATTRIBUTE CACHES ---------- */
765 :
766 : /*
767 : * get_attname
768 : * Given the relation id and the attribute number,
769 : * return the "attname" field from the attribute relation.
770 : *
771 : * Note: returns a palloc'd copy of the string, or NULL if no such attribute.
772 : */
773 : char *
774 1039 : get_attname(Oid relid, AttrNumber attnum)
775 : {
776 : HeapTuple tp;
777 :
778 1039 : tp = SearchSysCache2(ATTNUM,
779 : ObjectIdGetDatum(relid),
780 : Int16GetDatum(attnum));
781 1039 : if (HeapTupleIsValid(tp))
782 : {
783 1038 : Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
784 : char *result;
785 :
786 1038 : result = pstrdup(NameStr(att_tup->attname));
787 1038 : ReleaseSysCache(tp);
788 1038 : return result;
789 : }
790 : else
791 1 : return NULL;
792 : }
793 :
794 : /*
795 : * get_relid_attribute_name
796 : *
797 : * Same as above routine get_attname(), except that error
798 : * is handled by elog() instead of returning NULL.
799 : */
800 : char *
801 1002 : get_relid_attribute_name(Oid relid, AttrNumber attnum)
802 : {
803 : char *attname;
804 :
805 1002 : attname = get_attname(relid, attnum);
806 1002 : if (attname == NULL)
807 0 : elog(ERROR, "cache lookup failed for attribute %d of relation %u",
808 : attnum, relid);
809 1002 : return attname;
810 : }
811 :
812 : /*
813 : * get_attnum
814 : *
815 : * Given the relation id and the attribute name,
816 : * return the "attnum" field from the attribute relation.
817 : *
818 : * Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
819 : */
820 : AttrNumber
821 362 : get_attnum(Oid relid, const char *attname)
822 : {
823 : HeapTuple tp;
824 :
825 362 : tp = SearchSysCacheAttName(relid, attname);
826 362 : if (HeapTupleIsValid(tp))
827 : {
828 331 : Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
829 : AttrNumber result;
830 :
831 331 : result = att_tup->attnum;
832 331 : ReleaseSysCache(tp);
833 331 : return result;
834 : }
835 : else
836 31 : return InvalidAttrNumber;
837 : }
838 :
839 : /*
840 : * get_attidentity
841 : *
842 : * Given the relation id and the attribute name,
843 : * return the "attidentity" field from the attribute relation.
844 : *
845 : * Returns '\0' if not found.
846 : *
847 : * Since no identity is represented by '\0', this can also be used as a
848 : * Boolean test.
849 : */
850 : char
851 113 : get_attidentity(Oid relid, AttrNumber attnum)
852 : {
853 : HeapTuple tp;
854 :
855 113 : tp = SearchSysCache2(ATTNUM,
856 : ObjectIdGetDatum(relid),
857 : Int16GetDatum(attnum));
858 113 : if (HeapTupleIsValid(tp))
859 : {
860 113 : Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
861 : char result;
862 :
863 113 : result = att_tup->attidentity;
864 113 : ReleaseSysCache(tp);
865 113 : return result;
866 : }
867 : else
868 0 : return '\0';
869 : }
870 :
871 : /*
872 : * get_atttype
873 : *
874 : * Given the relation OID and the attribute number with the relation,
875 : * return the attribute type OID.
876 : */
877 : Oid
878 17 : get_atttype(Oid relid, AttrNumber attnum)
879 : {
880 : HeapTuple tp;
881 :
882 17 : tp = SearchSysCache2(ATTNUM,
883 : ObjectIdGetDatum(relid),
884 : Int16GetDatum(attnum));
885 17 : if (HeapTupleIsValid(tp))
886 : {
887 17 : Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
888 : Oid result;
889 :
890 17 : result = att_tup->atttypid;
891 17 : ReleaseSysCache(tp);
892 17 : return result;
893 : }
894 : else
895 0 : return InvalidOid;
896 : }
897 :
898 : /*
899 : * get_atttypmod
900 : *
901 : * Given the relation id and the attribute number,
902 : * return the "atttypmod" field from the attribute relation.
903 : */
904 : int32
905 0 : get_atttypmod(Oid relid, AttrNumber attnum)
906 : {
907 : HeapTuple tp;
908 :
909 0 : tp = SearchSysCache2(ATTNUM,
910 : ObjectIdGetDatum(relid),
911 : Int16GetDatum(attnum));
912 0 : if (HeapTupleIsValid(tp))
913 : {
914 0 : Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
915 : int32 result;
916 :
917 0 : result = att_tup->atttypmod;
918 0 : ReleaseSysCache(tp);
919 0 : return result;
920 : }
921 : else
922 0 : return -1;
923 : }
924 :
925 : /*
926 : * get_atttypetypmodcoll
927 : *
928 : * A three-fer: given the relation id and the attribute number,
929 : * fetch atttypid, atttypmod, and attcollation in a single cache lookup.
930 : *
931 : * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
932 : * raises an error if it can't obtain the information.
933 : */
934 : void
935 276 : get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
936 : Oid *typid, int32 *typmod, Oid *collid)
937 : {
938 : HeapTuple tp;
939 : Form_pg_attribute att_tup;
940 :
941 276 : tp = SearchSysCache2(ATTNUM,
942 : ObjectIdGetDatum(relid),
943 : Int16GetDatum(attnum));
944 276 : if (!HeapTupleIsValid(tp))
945 0 : elog(ERROR, "cache lookup failed for attribute %d of relation %u",
946 : attnum, relid);
947 276 : att_tup = (Form_pg_attribute) GETSTRUCT(tp);
948 :
949 276 : *typid = att_tup->atttypid;
950 276 : *typmod = att_tup->atttypmod;
951 276 : *collid = att_tup->attcollation;
952 276 : ReleaseSysCache(tp);
953 276 : }
954 :
955 : /* ---------- COLLATION CACHE ---------- */
956 :
957 : /*
958 : * get_collation_name
959 : * Returns the name of a given pg_collation entry.
960 : *
961 : * Returns a palloc'd copy of the string, or NULL if no such constraint.
962 : *
963 : * NOTE: since collation name is not unique, be wary of code that uses this
964 : * for anything except preparing error messages.
965 : */
966 : char *
967 24 : get_collation_name(Oid colloid)
968 : {
969 : HeapTuple tp;
970 :
971 24 : tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
972 24 : if (HeapTupleIsValid(tp))
973 : {
974 24 : Form_pg_collation colltup = (Form_pg_collation) GETSTRUCT(tp);
975 : char *result;
976 :
977 24 : result = pstrdup(NameStr(colltup->collname));
978 24 : ReleaseSysCache(tp);
979 24 : return result;
980 : }
981 : else
982 0 : return NULL;
983 : }
984 :
985 : /* ---------- CONSTRAINT CACHE ---------- */
986 :
987 : /*
988 : * get_constraint_name
989 : * Returns the name of a given pg_constraint entry.
990 : *
991 : * Returns a palloc'd copy of the string, or NULL if no such constraint.
992 : *
993 : * NOTE: since constraint name is not unique, be wary of code that uses this
994 : * for anything except preparing error messages.
995 : */
996 : char *
997 0 : get_constraint_name(Oid conoid)
998 : {
999 : HeapTuple tp;
1000 :
1001 0 : tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
1002 0 : if (HeapTupleIsValid(tp))
1003 : {
1004 0 : Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
1005 : char *result;
1006 :
1007 0 : result = pstrdup(NameStr(contup->conname));
1008 0 : ReleaseSysCache(tp);
1009 0 : return result;
1010 : }
1011 : else
1012 0 : return NULL;
1013 : }
1014 :
1015 : /* ---------- LANGUAGE CACHE ---------- */
1016 :
1017 : char *
1018 7 : get_language_name(Oid langoid, bool missing_ok)
1019 : {
1020 : HeapTuple tp;
1021 :
1022 7 : tp = SearchSysCache1(LANGOID, ObjectIdGetDatum(langoid));
1023 7 : if (HeapTupleIsValid(tp))
1024 : {
1025 7 : Form_pg_language lantup = (Form_pg_language) GETSTRUCT(tp);
1026 : char *result;
1027 :
1028 7 : result = pstrdup(NameStr(lantup->lanname));
1029 7 : ReleaseSysCache(tp);
1030 7 : return result;
1031 : }
1032 :
1033 0 : if (!missing_ok)
1034 0 : elog(ERROR, "cache lookup failed for language %u",
1035 : langoid);
1036 0 : return NULL;
1037 : }
1038 :
1039 : /* ---------- OPCLASS CACHE ---------- */
1040 :
1041 : /*
1042 : * get_opclass_family
1043 : *
1044 : * Returns the OID of the operator family the opclass belongs to.
1045 : */
1046 : Oid
1047 963 : get_opclass_family(Oid opclass)
1048 : {
1049 : HeapTuple tp;
1050 : Form_pg_opclass cla_tup;
1051 : Oid result;
1052 :
1053 963 : tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
1054 963 : if (!HeapTupleIsValid(tp))
1055 0 : elog(ERROR, "cache lookup failed for opclass %u", opclass);
1056 963 : cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1057 :
1058 963 : result = cla_tup->opcfamily;
1059 963 : ReleaseSysCache(tp);
1060 963 : return result;
1061 : }
1062 :
1063 : /*
1064 : * get_opclass_input_type
1065 : *
1066 : * Returns the OID of the datatype the opclass indexes.
1067 : */
1068 : Oid
1069 988 : get_opclass_input_type(Oid opclass)
1070 : {
1071 : HeapTuple tp;
1072 : Form_pg_opclass cla_tup;
1073 : Oid result;
1074 :
1075 988 : tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
1076 988 : if (!HeapTupleIsValid(tp))
1077 0 : elog(ERROR, "cache lookup failed for opclass %u", opclass);
1078 988 : cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1079 :
1080 988 : result = cla_tup->opcintype;
1081 988 : ReleaseSysCache(tp);
1082 988 : return result;
1083 : }
1084 :
1085 : /* ---------- OPERATOR CACHE ---------- */
1086 :
1087 : /*
1088 : * get_opcode
1089 : *
1090 : * Returns the regproc id of the routine used to implement an
1091 : * operator given the operator oid.
1092 : */
1093 : RegProcedure
1094 26609 : get_opcode(Oid opno)
1095 : {
1096 : HeapTuple tp;
1097 :
1098 26609 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1099 26609 : if (HeapTupleIsValid(tp))
1100 : {
1101 26609 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1102 : RegProcedure result;
1103 :
1104 26609 : result = optup->oprcode;
1105 26609 : ReleaseSysCache(tp);
1106 26609 : return result;
1107 : }
1108 : else
1109 0 : return (RegProcedure) InvalidOid;
1110 : }
1111 :
1112 : /*
1113 : * get_opname
1114 : * returns the name of the operator with the given opno
1115 : *
1116 : * Note: returns a palloc'd copy of the string, or NULL if no such operator.
1117 : */
1118 : char *
1119 2 : get_opname(Oid opno)
1120 : {
1121 : HeapTuple tp;
1122 :
1123 2 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1124 2 : if (HeapTupleIsValid(tp))
1125 : {
1126 2 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1127 : char *result;
1128 :
1129 2 : result = pstrdup(NameStr(optup->oprname));
1130 2 : ReleaseSysCache(tp);
1131 2 : return result;
1132 : }
1133 : else
1134 0 : return NULL;
1135 : }
1136 :
1137 : /*
1138 : * get_op_rettype
1139 : * Given operator oid, return the operator's result type.
1140 : */
1141 : Oid
1142 3 : get_op_rettype(Oid opno)
1143 : {
1144 : HeapTuple tp;
1145 :
1146 3 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1147 3 : if (HeapTupleIsValid(tp))
1148 : {
1149 3 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1150 : Oid result;
1151 :
1152 3 : result = optup->oprresult;
1153 3 : ReleaseSysCache(tp);
1154 3 : return result;
1155 : }
1156 : else
1157 0 : return InvalidOid;
1158 : }
1159 :
1160 : /*
1161 : * op_input_types
1162 : *
1163 : * Returns the left and right input datatypes for an operator
1164 : * (InvalidOid if not relevant).
1165 : */
1166 : void
1167 13312 : op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
1168 : {
1169 : HeapTuple tp;
1170 : Form_pg_operator optup;
1171 :
1172 13312 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1173 13312 : if (!HeapTupleIsValid(tp)) /* shouldn't happen */
1174 0 : elog(ERROR, "cache lookup failed for operator %u", opno);
1175 13312 : optup = (Form_pg_operator) GETSTRUCT(tp);
1176 13312 : *lefttype = optup->oprleft;
1177 13312 : *righttype = optup->oprright;
1178 13312 : ReleaseSysCache(tp);
1179 13312 : }
1180 :
1181 : /*
1182 : * op_mergejoinable
1183 : *
1184 : * Returns true if the operator is potentially mergejoinable. (The planner
1185 : * will fail to find any mergejoin plans unless there are suitable btree
1186 : * opfamily entries for this operator and associated sortops. The pg_operator
1187 : * flag is just a hint to tell the planner whether to bother looking.)
1188 : *
1189 : * In some cases (currently only array_eq and record_eq), mergejoinability
1190 : * depends on the specific input data type the operator is invoked for, so
1191 : * that must be passed as well. We currently assume that only one input's type
1192 : * is needed to check this --- by convention, pass the left input's data type.
1193 : */
1194 : bool
1195 19187 : op_mergejoinable(Oid opno, Oid inputtype)
1196 : {
1197 19187 : bool result = false;
1198 : HeapTuple tp;
1199 : TypeCacheEntry *typentry;
1200 :
1201 : /*
1202 : * For array_eq or record_eq, we can sort if the element or field types
1203 : * are all sortable. We could implement all the checks for that here, but
1204 : * the typcache already does that and caches the results too, so let's
1205 : * rely on the typcache.
1206 : */
1207 19187 : if (opno == ARRAY_EQ_OP)
1208 : {
1209 12 : typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
1210 12 : if (typentry->cmp_proc == F_BTARRAYCMP)
1211 12 : result = true;
1212 : }
1213 19175 : else if (opno == RECORD_EQ_OP)
1214 : {
1215 2 : typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
1216 2 : if (typentry->cmp_proc == F_BTRECORDCMP)
1217 2 : result = true;
1218 : }
1219 : else
1220 : {
1221 : /* For all other operators, rely on pg_operator.oprcanmerge */
1222 19173 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1223 19173 : if (HeapTupleIsValid(tp))
1224 : {
1225 19173 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1226 :
1227 19173 : result = optup->oprcanmerge;
1228 19173 : ReleaseSysCache(tp);
1229 : }
1230 : }
1231 19187 : return result;
1232 : }
1233 :
1234 : /*
1235 : * op_hashjoinable
1236 : *
1237 : * Returns true if the operator is hashjoinable. (There must be a suitable
1238 : * hash opfamily entry for this operator if it is so marked.)
1239 : *
1240 : * In some cases (currently only array_eq), hashjoinability depends on the
1241 : * specific input data type the operator is invoked for, so that must be
1242 : * passed as well. We currently assume that only one input's type is needed
1243 : * to check this --- by convention, pass the left input's data type.
1244 : */
1245 : bool
1246 12545 : op_hashjoinable(Oid opno, Oid inputtype)
1247 : {
1248 12545 : bool result = false;
1249 : HeapTuple tp;
1250 : TypeCacheEntry *typentry;
1251 :
1252 : /* As in op_mergejoinable, let the typcache handle the hard cases */
1253 : /* Eventually we'll need a similar case for record_eq ... */
1254 12545 : if (opno == ARRAY_EQ_OP)
1255 : {
1256 0 : typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
1257 0 : if (typentry->hash_proc == F_HASH_ARRAY)
1258 0 : result = true;
1259 : }
1260 : else
1261 : {
1262 : /* For all other operators, rely on pg_operator.oprcanhash */
1263 12545 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1264 12545 : if (HeapTupleIsValid(tp))
1265 : {
1266 12545 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1267 :
1268 12545 : result = optup->oprcanhash;
1269 12545 : ReleaseSysCache(tp);
1270 : }
1271 : }
1272 12545 : return result;
1273 : }
1274 :
1275 : /*
1276 : * op_strict
1277 : *
1278 : * Get the proisstrict flag for the operator's underlying function.
1279 : */
1280 : bool
1281 1123 : op_strict(Oid opno)
1282 : {
1283 1123 : RegProcedure funcid = get_opcode(opno);
1284 :
1285 1123 : if (funcid == (RegProcedure) InvalidOid)
1286 0 : elog(ERROR, "operator %u does not exist", opno);
1287 :
1288 1123 : return func_strict((Oid) funcid);
1289 : }
1290 :
1291 : /*
1292 : * op_volatile
1293 : *
1294 : * Get the provolatile flag for the operator's underlying function.
1295 : */
1296 : char
1297 92 : op_volatile(Oid opno)
1298 : {
1299 92 : RegProcedure funcid = get_opcode(opno);
1300 :
1301 92 : if (funcid == (RegProcedure) InvalidOid)
1302 0 : elog(ERROR, "operator %u does not exist", opno);
1303 :
1304 92 : return func_volatile((Oid) funcid);
1305 : }
1306 :
1307 : /*
1308 : * get_commutator
1309 : *
1310 : * Returns the corresponding commutator of an operator.
1311 : */
1312 : Oid
1313 2091 : get_commutator(Oid opno)
1314 : {
1315 : HeapTuple tp;
1316 :
1317 2091 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1318 2091 : if (HeapTupleIsValid(tp))
1319 : {
1320 2091 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1321 : Oid result;
1322 :
1323 2091 : result = optup->oprcom;
1324 2091 : ReleaseSysCache(tp);
1325 2091 : return result;
1326 : }
1327 : else
1328 0 : return InvalidOid;
1329 : }
1330 :
1331 : /*
1332 : * get_negator
1333 : *
1334 : * Returns the corresponding negator of an operator.
1335 : */
1336 : Oid
1337 1836 : get_negator(Oid opno)
1338 : {
1339 : HeapTuple tp;
1340 :
1341 1836 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1342 1836 : if (HeapTupleIsValid(tp))
1343 : {
1344 1836 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1345 : Oid result;
1346 :
1347 1836 : result = optup->oprnegate;
1348 1836 : ReleaseSysCache(tp);
1349 1836 : return result;
1350 : }
1351 : else
1352 0 : return InvalidOid;
1353 : }
1354 :
1355 : /*
1356 : * get_oprrest
1357 : *
1358 : * Returns procedure id for computing selectivity of an operator.
1359 : */
1360 : RegProcedure
1361 33301 : get_oprrest(Oid opno)
1362 : {
1363 : HeapTuple tp;
1364 :
1365 33301 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1366 33301 : if (HeapTupleIsValid(tp))
1367 : {
1368 33301 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1369 : RegProcedure result;
1370 :
1371 33301 : result = optup->oprrest;
1372 33301 : ReleaseSysCache(tp);
1373 33301 : return result;
1374 : }
1375 : else
1376 0 : return (RegProcedure) InvalidOid;
1377 : }
1378 :
1379 : /*
1380 : * get_oprjoin
1381 : *
1382 : * Returns procedure id for computing selectivity of a join.
1383 : */
1384 : RegProcedure
1385 6128 : get_oprjoin(Oid opno)
1386 : {
1387 : HeapTuple tp;
1388 :
1389 6128 : tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1390 6128 : if (HeapTupleIsValid(tp))
1391 : {
1392 6128 : Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1393 : RegProcedure result;
1394 :
1395 6128 : result = optup->oprjoin;
1396 6128 : ReleaseSysCache(tp);
1397 6128 : return result;
1398 : }
1399 : else
1400 0 : return (RegProcedure) InvalidOid;
1401 : }
1402 :
1403 : /* ---------- FUNCTION CACHE ---------- */
1404 :
1405 : /*
1406 : * get_func_name
1407 : * returns the name of the function with the given funcid
1408 : *
1409 : * Note: returns a palloc'd copy of the string, or NULL if no such function.
1410 : */
1411 : char *
1412 29 : get_func_name(Oid funcid)
1413 : {
1414 : HeapTuple tp;
1415 :
1416 29 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1417 29 : if (HeapTupleIsValid(tp))
1418 : {
1419 29 : Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
1420 : char *result;
1421 :
1422 29 : result = pstrdup(NameStr(functup->proname));
1423 29 : ReleaseSysCache(tp);
1424 29 : return result;
1425 : }
1426 : else
1427 0 : return NULL;
1428 : }
1429 :
1430 : /*
1431 : * get_func_namespace
1432 : *
1433 : * Returns the pg_namespace OID associated with a given function.
1434 : */
1435 : Oid
1436 6 : get_func_namespace(Oid funcid)
1437 : {
1438 : HeapTuple tp;
1439 :
1440 6 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1441 6 : if (HeapTupleIsValid(tp))
1442 : {
1443 6 : Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
1444 : Oid result;
1445 :
1446 6 : result = functup->pronamespace;
1447 6 : ReleaseSysCache(tp);
1448 6 : return result;
1449 : }
1450 : else
1451 0 : return InvalidOid;
1452 : }
1453 :
1454 : /*
1455 : * get_func_rettype
1456 : * Given procedure id, return the function's result type.
1457 : */
1458 : Oid
1459 877 : get_func_rettype(Oid funcid)
1460 : {
1461 : HeapTuple tp;
1462 : Oid result;
1463 :
1464 877 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1465 877 : if (!HeapTupleIsValid(tp))
1466 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1467 :
1468 877 : result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
1469 877 : ReleaseSysCache(tp);
1470 877 : return result;
1471 : }
1472 :
1473 : /*
1474 : * get_func_nargs
1475 : * Given procedure id, return the number of arguments.
1476 : */
1477 : int
1478 0 : get_func_nargs(Oid funcid)
1479 : {
1480 : HeapTuple tp;
1481 : int result;
1482 :
1483 0 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1484 0 : if (!HeapTupleIsValid(tp))
1485 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1486 :
1487 0 : result = ((Form_pg_proc) GETSTRUCT(tp))->pronargs;
1488 0 : ReleaseSysCache(tp);
1489 0 : return result;
1490 : }
1491 :
1492 : /*
1493 : * get_func_signature
1494 : * Given procedure id, return the function's argument and result types.
1495 : * (The return value is the result type.)
1496 : *
1497 : * The arguments are returned as a palloc'd array.
1498 : */
1499 : Oid
1500 65 : get_func_signature(Oid funcid, Oid **argtypes, int *nargs)
1501 : {
1502 : HeapTuple tp;
1503 : Form_pg_proc procstruct;
1504 : Oid result;
1505 :
1506 65 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1507 65 : if (!HeapTupleIsValid(tp))
1508 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1509 :
1510 65 : procstruct = (Form_pg_proc) GETSTRUCT(tp);
1511 :
1512 65 : result = procstruct->prorettype;
1513 65 : *nargs = (int) procstruct->pronargs;
1514 65 : Assert(*nargs == procstruct->proargtypes.dim1);
1515 65 : *argtypes = (Oid *) palloc(*nargs * sizeof(Oid));
1516 65 : memcpy(*argtypes, procstruct->proargtypes.values, *nargs * sizeof(Oid));
1517 :
1518 65 : ReleaseSysCache(tp);
1519 65 : return result;
1520 : }
1521 :
1522 : /*
1523 : * get_func_variadictype
1524 : * Given procedure id, return the function's provariadic field.
1525 : */
1526 : Oid
1527 27 : get_func_variadictype(Oid funcid)
1528 : {
1529 : HeapTuple tp;
1530 : Oid result;
1531 :
1532 27 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1533 27 : if (!HeapTupleIsValid(tp))
1534 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1535 :
1536 27 : result = ((Form_pg_proc) GETSTRUCT(tp))->provariadic;
1537 27 : ReleaseSysCache(tp);
1538 27 : return result;
1539 : }
1540 :
1541 : /*
1542 : * get_func_retset
1543 : * Given procedure id, return the function's proretset flag.
1544 : */
1545 : bool
1546 20105 : get_func_retset(Oid funcid)
1547 : {
1548 : HeapTuple tp;
1549 : bool result;
1550 :
1551 20105 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1552 20105 : if (!HeapTupleIsValid(tp))
1553 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1554 :
1555 20105 : result = ((Form_pg_proc) GETSTRUCT(tp))->proretset;
1556 20105 : ReleaseSysCache(tp);
1557 20105 : return result;
1558 : }
1559 :
1560 : /*
1561 : * func_strict
1562 : * Given procedure id, return the function's proisstrict flag.
1563 : */
1564 : bool
1565 8775 : func_strict(Oid funcid)
1566 : {
1567 : HeapTuple tp;
1568 : bool result;
1569 :
1570 8775 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1571 8775 : if (!HeapTupleIsValid(tp))
1572 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1573 :
1574 8775 : result = ((Form_pg_proc) GETSTRUCT(tp))->proisstrict;
1575 8775 : ReleaseSysCache(tp);
1576 8775 : return result;
1577 : }
1578 :
1579 : /*
1580 : * func_volatile
1581 : * Given procedure id, return the function's provolatile flag.
1582 : */
1583 : char
1584 42457 : func_volatile(Oid funcid)
1585 : {
1586 : HeapTuple tp;
1587 : char result;
1588 :
1589 42457 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1590 42457 : if (!HeapTupleIsValid(tp))
1591 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1592 :
1593 42457 : result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
1594 42457 : ReleaseSysCache(tp);
1595 42457 : return result;
1596 : }
1597 :
1598 : /*
1599 : * func_parallel
1600 : * Given procedure id, return the function's proparallel flag.
1601 : */
1602 : char
1603 47414 : func_parallel(Oid funcid)
1604 : {
1605 : HeapTuple tp;
1606 : char result;
1607 :
1608 47414 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1609 47414 : if (!HeapTupleIsValid(tp))
1610 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1611 :
1612 47414 : result = ((Form_pg_proc) GETSTRUCT(tp))->proparallel;
1613 47414 : ReleaseSysCache(tp);
1614 47414 : return result;
1615 : }
1616 :
1617 : /*
1618 : * get_func_leakproof
1619 : * Given procedure id, return the function's leakproof field.
1620 : */
1621 : bool
1622 738 : get_func_leakproof(Oid funcid)
1623 : {
1624 : HeapTuple tp;
1625 : bool result;
1626 :
1627 738 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1628 738 : if (!HeapTupleIsValid(tp))
1629 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1630 :
1631 738 : result = ((Form_pg_proc) GETSTRUCT(tp))->proleakproof;
1632 738 : ReleaseSysCache(tp);
1633 738 : return result;
1634 : }
1635 :
1636 : /*
1637 : * get_func_cost
1638 : * Given procedure id, return the function's procost field.
1639 : */
1640 : float4
1641 44657 : get_func_cost(Oid funcid)
1642 : {
1643 : HeapTuple tp;
1644 : float4 result;
1645 :
1646 44657 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1647 44657 : if (!HeapTupleIsValid(tp))
1648 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1649 :
1650 44657 : result = ((Form_pg_proc) GETSTRUCT(tp))->procost;
1651 44657 : ReleaseSysCache(tp);
1652 44657 : return result;
1653 : }
1654 :
1655 : /*
1656 : * get_func_rows
1657 : * Given procedure id, return the function's prorows field.
1658 : */
1659 : float4
1660 1347 : get_func_rows(Oid funcid)
1661 : {
1662 : HeapTuple tp;
1663 : float4 result;
1664 :
1665 1347 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1666 1347 : if (!HeapTupleIsValid(tp))
1667 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1668 :
1669 1347 : result = ((Form_pg_proc) GETSTRUCT(tp))->prorows;
1670 1347 : ReleaseSysCache(tp);
1671 1347 : return result;
1672 : }
1673 :
1674 : /* ---------- RELATION CACHE ---------- */
1675 :
1676 : /*
1677 : * get_relname_relid
1678 : * Given name and namespace of a relation, look up the OID.
1679 : *
1680 : * Returns InvalidOid if there is no such relation.
1681 : */
1682 : Oid
1683 54151 : get_relname_relid(const char *relname, Oid relnamespace)
1684 : {
1685 54151 : return GetSysCacheOid2(RELNAMENSP,
1686 : PointerGetDatum(relname),
1687 : ObjectIdGetDatum(relnamespace));
1688 : }
1689 :
1690 : #ifdef NOT_USED
1691 : /*
1692 : * get_relnatts
1693 : *
1694 : * Returns the number of attributes for a given relation.
1695 : */
1696 : int
1697 : get_relnatts(Oid relid)
1698 : {
1699 : HeapTuple tp;
1700 :
1701 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1702 : if (HeapTupleIsValid(tp))
1703 : {
1704 : Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1705 : int result;
1706 :
1707 : result = reltup->relnatts;
1708 : ReleaseSysCache(tp);
1709 : return result;
1710 : }
1711 : else
1712 : return InvalidAttrNumber;
1713 : }
1714 : #endif
1715 :
1716 : /*
1717 : * get_rel_name
1718 : * Returns the name of a given relation.
1719 : *
1720 : * Returns a palloc'd copy of the string, or NULL if no such relation.
1721 : *
1722 : * NOTE: since relation name is not unique, be wary of code that uses this
1723 : * for anything except preparing error messages.
1724 : */
1725 : char *
1726 4598 : get_rel_name(Oid relid)
1727 : {
1728 : HeapTuple tp;
1729 :
1730 4598 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1731 4598 : if (HeapTupleIsValid(tp))
1732 : {
1733 4598 : Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1734 : char *result;
1735 :
1736 4598 : result = pstrdup(NameStr(reltup->relname));
1737 4598 : ReleaseSysCache(tp);
1738 4598 : return result;
1739 : }
1740 : else
1741 0 : return NULL;
1742 : }
1743 :
1744 : /*
1745 : * get_rel_namespace
1746 : *
1747 : * Returns the pg_namespace OID associated with a given relation.
1748 : */
1749 : Oid
1750 235 : get_rel_namespace(Oid relid)
1751 : {
1752 : HeapTuple tp;
1753 :
1754 235 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1755 235 : if (HeapTupleIsValid(tp))
1756 : {
1757 235 : Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1758 : Oid result;
1759 :
1760 235 : result = reltup->relnamespace;
1761 235 : ReleaseSysCache(tp);
1762 235 : return result;
1763 : }
1764 : else
1765 0 : return InvalidOid;
1766 : }
1767 :
1768 : /*
1769 : * get_rel_type_id
1770 : *
1771 : * Returns the pg_type OID associated with a given relation.
1772 : *
1773 : * Note: not all pg_class entries have associated pg_type OIDs; so be
1774 : * careful to check for InvalidOid result.
1775 : */
1776 : Oid
1777 450 : get_rel_type_id(Oid relid)
1778 : {
1779 : HeapTuple tp;
1780 :
1781 450 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1782 450 : if (HeapTupleIsValid(tp))
1783 : {
1784 450 : Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1785 : Oid result;
1786 :
1787 450 : result = reltup->reltype;
1788 450 : ReleaseSysCache(tp);
1789 450 : return result;
1790 : }
1791 : else
1792 0 : return InvalidOid;
1793 : }
1794 :
1795 : /*
1796 : * get_rel_relkind
1797 : *
1798 : * Returns the relkind associated with a given relation.
1799 : */
1800 : char
1801 3938 : get_rel_relkind(Oid relid)
1802 : {
1803 : HeapTuple tp;
1804 :
1805 3938 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1806 3938 : if (HeapTupleIsValid(tp))
1807 : {
1808 3938 : Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1809 : char result;
1810 :
1811 3938 : result = reltup->relkind;
1812 3938 : ReleaseSysCache(tp);
1813 3938 : return result;
1814 : }
1815 : else
1816 0 : return '\0';
1817 : }
1818 :
1819 : /*
1820 : * get_rel_tablespace
1821 : *
1822 : * Returns the pg_tablespace OID associated with a given relation.
1823 : *
1824 : * Note: InvalidOid might mean either that we couldn't find the relation,
1825 : * or that it is in the database's default tablespace.
1826 : */
1827 : Oid
1828 19 : get_rel_tablespace(Oid relid)
1829 : {
1830 : HeapTuple tp;
1831 :
1832 19 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1833 19 : if (HeapTupleIsValid(tp))
1834 : {
1835 19 : Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1836 : Oid result;
1837 :
1838 19 : result = reltup->reltablespace;
1839 19 : ReleaseSysCache(tp);
1840 19 : return result;
1841 : }
1842 : else
1843 0 : return InvalidOid;
1844 : }
1845 :
1846 : /*
1847 : * get_rel_persistence
1848 : *
1849 : * Returns the relpersistence associated with a given relation.
1850 : */
1851 : char
1852 12778 : get_rel_persistence(Oid relid)
1853 : {
1854 : HeapTuple tp;
1855 : Form_pg_class reltup;
1856 : char result;
1857 :
1858 12778 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1859 12778 : if (!HeapTupleIsValid(tp))
1860 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
1861 12778 : reltup = (Form_pg_class) GETSTRUCT(tp);
1862 12778 : result = reltup->relpersistence;
1863 12778 : ReleaseSysCache(tp);
1864 :
1865 12778 : return result;
1866 : }
1867 :
1868 :
1869 : /* ---------- TRANSFORM CACHE ---------- */
1870 :
1871 : Oid
1872 0 : get_transform_fromsql(Oid typid, Oid langid, List *trftypes)
1873 : {
1874 : HeapTuple tup;
1875 :
1876 0 : if (!list_member_oid(trftypes, typid))
1877 0 : return InvalidOid;
1878 :
1879 0 : tup = SearchSysCache2(TRFTYPELANG, typid, langid);
1880 0 : if (HeapTupleIsValid(tup))
1881 : {
1882 : Oid funcid;
1883 :
1884 0 : funcid = ((Form_pg_transform) GETSTRUCT(tup))->trffromsql;
1885 0 : ReleaseSysCache(tup);
1886 0 : return funcid;
1887 : }
1888 : else
1889 0 : return InvalidOid;
1890 : }
1891 :
1892 : Oid
1893 0 : get_transform_tosql(Oid typid, Oid langid, List *trftypes)
1894 : {
1895 : HeapTuple tup;
1896 :
1897 0 : if (!list_member_oid(trftypes, typid))
1898 0 : return InvalidOid;
1899 :
1900 0 : tup = SearchSysCache2(TRFTYPELANG, typid, langid);
1901 0 : if (HeapTupleIsValid(tup))
1902 : {
1903 : Oid funcid;
1904 :
1905 0 : funcid = ((Form_pg_transform) GETSTRUCT(tup))->trftosql;
1906 0 : ReleaseSysCache(tup);
1907 0 : return funcid;
1908 : }
1909 : else
1910 0 : return InvalidOid;
1911 : }
1912 :
1913 :
1914 : /* ---------- TYPE CACHE ---------- */
1915 :
1916 : /*
1917 : * get_typisdefined
1918 : *
1919 : * Given the type OID, determine whether the type is defined
1920 : * (if not, it's only a shell).
1921 : */
1922 : bool
1923 15 : get_typisdefined(Oid typid)
1924 : {
1925 : HeapTuple tp;
1926 :
1927 15 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1928 15 : if (HeapTupleIsValid(tp))
1929 : {
1930 15 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1931 : bool result;
1932 :
1933 15 : result = typtup->typisdefined;
1934 15 : ReleaseSysCache(tp);
1935 15 : return result;
1936 : }
1937 : else
1938 0 : return false;
1939 : }
1940 :
1941 : /*
1942 : * get_typlen
1943 : *
1944 : * Given the type OID, return the length of the type.
1945 : */
1946 : int16
1947 105113 : get_typlen(Oid typid)
1948 : {
1949 : HeapTuple tp;
1950 :
1951 105113 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1952 105113 : if (HeapTupleIsValid(tp))
1953 : {
1954 105113 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1955 : int16 result;
1956 :
1957 105113 : result = typtup->typlen;
1958 105113 : ReleaseSysCache(tp);
1959 105113 : return result;
1960 : }
1961 : else
1962 0 : return 0;
1963 : }
1964 :
1965 : /*
1966 : * get_typbyval
1967 : *
1968 : * Given the type OID, determine whether the type is returned by value or
1969 : * not. Returns true if by value, false if by reference.
1970 : */
1971 : bool
1972 2662 : get_typbyval(Oid typid)
1973 : {
1974 : HeapTuple tp;
1975 :
1976 2662 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1977 2662 : if (HeapTupleIsValid(tp))
1978 : {
1979 2662 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
1980 : bool result;
1981 :
1982 2662 : result = typtup->typbyval;
1983 2662 : ReleaseSysCache(tp);
1984 2662 : return result;
1985 : }
1986 : else
1987 0 : return false;
1988 : }
1989 :
1990 : /*
1991 : * get_typlenbyval
1992 : *
1993 : * A two-fer: given the type OID, return both typlen and typbyval.
1994 : *
1995 : * Since both pieces of info are needed to know how to copy a Datum,
1996 : * many places need both. Might as well get them with one cache lookup
1997 : * instead of two. Also, this routine raises an error instead of
1998 : * returning a bogus value when given a bad type OID.
1999 : */
2000 : void
2001 19468 : get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
2002 : {
2003 : HeapTuple tp;
2004 : Form_pg_type typtup;
2005 :
2006 19468 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2007 19468 : if (!HeapTupleIsValid(tp))
2008 0 : elog(ERROR, "cache lookup failed for type %u", typid);
2009 19468 : typtup = (Form_pg_type) GETSTRUCT(tp);
2010 19468 : *typlen = typtup->typlen;
2011 19468 : *typbyval = typtup->typbyval;
2012 19468 : ReleaseSysCache(tp);
2013 19468 : }
2014 :
2015 : /*
2016 : * get_typlenbyvalalign
2017 : *
2018 : * A three-fer: given the type OID, return typlen, typbyval, typalign.
2019 : */
2020 : void
2021 43621 : get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
2022 : char *typalign)
2023 : {
2024 : HeapTuple tp;
2025 : Form_pg_type typtup;
2026 :
2027 43621 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2028 43621 : if (!HeapTupleIsValid(tp))
2029 0 : elog(ERROR, "cache lookup failed for type %u", typid);
2030 43621 : typtup = (Form_pg_type) GETSTRUCT(tp);
2031 43621 : *typlen = typtup->typlen;
2032 43621 : *typbyval = typtup->typbyval;
2033 43621 : *typalign = typtup->typalign;
2034 43621 : ReleaseSysCache(tp);
2035 43621 : }
2036 :
2037 : /*
2038 : * getTypeIOParam
2039 : * Given a pg_type row, select the type OID to pass to I/O functions
2040 : *
2041 : * Formerly, all I/O functions were passed pg_type.typelem as their second
2042 : * parameter, but we now have a more complex rule about what to pass.
2043 : * This knowledge is intended to be centralized here --- direct references
2044 : * to typelem elsewhere in the code are wrong, if they are associated with
2045 : * I/O calls and not with actual subscripting operations! (But see
2046 : * bootstrap.c's boot_get_type_io_data() if you need to change this.)
2047 : *
2048 : * As of PostgreSQL 8.1, output functions receive only the value itself
2049 : * and not any auxiliary parameters, so the name of this routine is now
2050 : * a bit of a misnomer ... it should be getTypeInputParam.
2051 : */
2052 : Oid
2053 38109 : getTypeIOParam(HeapTuple typeTuple)
2054 : {
2055 38109 : Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
2056 :
2057 : /*
2058 : * Array types get their typelem as parameter; everybody else gets their
2059 : * own type OID as parameter.
2060 : */
2061 38109 : if (OidIsValid(typeStruct->typelem))
2062 4240 : return typeStruct->typelem;
2063 : else
2064 33869 : return HeapTupleGetOid(typeTuple);
2065 : }
2066 :
2067 : /*
2068 : * get_type_io_data
2069 : *
2070 : * A six-fer: given the type OID, return typlen, typbyval, typalign,
2071 : * typdelim, typioparam, and IO function OID. The IO function
2072 : * returned is controlled by IOFuncSelector
2073 : */
2074 : void
2075 3182 : get_type_io_data(Oid typid,
2076 : IOFuncSelector which_func,
2077 : int16 *typlen,
2078 : bool *typbyval,
2079 : char *typalign,
2080 : char *typdelim,
2081 : Oid *typioparam,
2082 : Oid *func)
2083 : {
2084 : HeapTuple typeTuple;
2085 : Form_pg_type typeStruct;
2086 :
2087 : /*
2088 : * In bootstrap mode, pass it off to bootstrap.c. This hack allows us to
2089 : * use array_in and array_out during bootstrap.
2090 : */
2091 3182 : if (IsBootstrapProcessingMode())
2092 : {
2093 : Oid typinput;
2094 : Oid typoutput;
2095 :
2096 275 : boot_get_type_io_data(typid,
2097 : typlen,
2098 : typbyval,
2099 : typalign,
2100 : typdelim,
2101 : typioparam,
2102 : &typinput,
2103 : &typoutput);
2104 275 : switch (which_func)
2105 : {
2106 : case IOFunc_input:
2107 275 : *func = typinput;
2108 275 : break;
2109 : case IOFunc_output:
2110 0 : *func = typoutput;
2111 0 : break;
2112 : default:
2113 0 : elog(ERROR, "binary I/O not supported during bootstrap");
2114 : break;
2115 : }
2116 3457 : return;
2117 : }
2118 :
2119 2907 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2120 2907 : if (!HeapTupleIsValid(typeTuple))
2121 0 : elog(ERROR, "cache lookup failed for type %u", typid);
2122 2907 : typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
2123 :
2124 2907 : *typlen = typeStruct->typlen;
2125 2907 : *typbyval = typeStruct->typbyval;
2126 2907 : *typalign = typeStruct->typalign;
2127 2907 : *typdelim = typeStruct->typdelim;
2128 2907 : *typioparam = getTypeIOParam(typeTuple);
2129 2907 : switch (which_func)
2130 : {
2131 : case IOFunc_input:
2132 1529 : *func = typeStruct->typinput;
2133 1529 : break;
2134 : case IOFunc_output:
2135 1378 : *func = typeStruct->typoutput;
2136 1378 : break;
2137 : case IOFunc_receive:
2138 0 : *func = typeStruct->typreceive;
2139 0 : break;
2140 : case IOFunc_send:
2141 0 : *func = typeStruct->typsend;
2142 0 : break;
2143 : }
2144 2907 : ReleaseSysCache(typeTuple);
2145 : }
2146 :
2147 : #ifdef NOT_USED
2148 : char
2149 : get_typalign(Oid typid)
2150 : {
2151 : HeapTuple tp;
2152 :
2153 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2154 : if (HeapTupleIsValid(tp))
2155 : {
2156 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2157 : char result;
2158 :
2159 : result = typtup->typalign;
2160 : ReleaseSysCache(tp);
2161 : return result;
2162 : }
2163 : else
2164 : return 'i';
2165 : }
2166 : #endif
2167 :
2168 : char
2169 5930 : get_typstorage(Oid typid)
2170 : {
2171 : HeapTuple tp;
2172 :
2173 5930 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2174 5930 : if (HeapTupleIsValid(tp))
2175 : {
2176 5930 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2177 : char result;
2178 :
2179 5930 : result = typtup->typstorage;
2180 5930 : ReleaseSysCache(tp);
2181 5930 : return result;
2182 : }
2183 : else
2184 0 : return 'p';
2185 : }
2186 :
2187 : /*
2188 : * get_typdefault
2189 : * Given a type OID, return the type's default value, if any.
2190 : *
2191 : * The result is a palloc'd expression node tree, or NULL if there
2192 : * is no defined default for the datatype.
2193 : *
2194 : * NB: caller should be prepared to coerce result to correct datatype;
2195 : * the returned expression tree might produce something of the wrong type.
2196 : */
2197 : Node *
2198 788 : get_typdefault(Oid typid)
2199 : {
2200 : HeapTuple typeTuple;
2201 : Form_pg_type type;
2202 : Datum datum;
2203 : bool isNull;
2204 : Node *expr;
2205 :
2206 788 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2207 788 : if (!HeapTupleIsValid(typeTuple))
2208 0 : elog(ERROR, "cache lookup failed for type %u", typid);
2209 788 : type = (Form_pg_type) GETSTRUCT(typeTuple);
2210 :
2211 : /*
2212 : * typdefault and typdefaultbin are potentially null, so don't try to
2213 : * access 'em as struct fields. Must do it the hard way with
2214 : * SysCacheGetAttr.
2215 : */
2216 788 : datum = SysCacheGetAttr(TYPEOID,
2217 : typeTuple,
2218 : Anum_pg_type_typdefaultbin,
2219 : &isNull);
2220 :
2221 788 : if (!isNull)
2222 : {
2223 : /* We have an expression default */
2224 34 : expr = stringToNode(TextDatumGetCString(datum));
2225 : }
2226 : else
2227 : {
2228 : /* Perhaps we have a plain literal default */
2229 754 : datum = SysCacheGetAttr(TYPEOID,
2230 : typeTuple,
2231 : Anum_pg_type_typdefault,
2232 : &isNull);
2233 :
2234 754 : if (!isNull)
2235 : {
2236 : char *strDefaultVal;
2237 :
2238 : /* Convert text datum to C string */
2239 2 : strDefaultVal = TextDatumGetCString(datum);
2240 : /* Convert C string to a value of the given type */
2241 2 : datum = OidInputFunctionCall(type->typinput, strDefaultVal,
2242 : getTypeIOParam(typeTuple), -1);
2243 : /* Build a Const node containing the value */
2244 4 : expr = (Node *) makeConst(typid,
2245 : -1,
2246 : type->typcollation,
2247 2 : type->typlen,
2248 : datum,
2249 : false,
2250 2 : type->typbyval);
2251 2 : pfree(strDefaultVal);
2252 : }
2253 : else
2254 : {
2255 : /* No default */
2256 752 : expr = NULL;
2257 : }
2258 : }
2259 :
2260 788 : ReleaseSysCache(typeTuple);
2261 :
2262 788 : return expr;
2263 : }
2264 :
2265 : /*
2266 : * getBaseType
2267 : * If the given type is a domain, return its base type;
2268 : * otherwise return the type's own OID.
2269 : */
2270 : Oid
2271 139384 : getBaseType(Oid typid)
2272 : {
2273 139384 : int32 typmod = -1;
2274 :
2275 139384 : return getBaseTypeAndTypmod(typid, &typmod);
2276 : }
2277 :
2278 : /*
2279 : * getBaseTypeAndTypmod
2280 : * If the given type is a domain, return its base type and typmod;
2281 : * otherwise return the type's own OID, and leave *typmod unchanged.
2282 : *
2283 : * Note that the "applied typmod" should be -1 for every domain level
2284 : * above the bottommost; therefore, if the passed-in typid is indeed
2285 : * a domain, *typmod should be -1.
2286 : */
2287 : Oid
2288 208540 : getBaseTypeAndTypmod(Oid typid, int32 *typmod)
2289 : {
2290 : /*
2291 : * We loop to find the bottom base type in a stack of domains.
2292 : */
2293 : for (;;)
2294 : {
2295 : HeapTuple tup;
2296 : Form_pg_type typTup;
2297 :
2298 208540 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2299 208540 : if (!HeapTupleIsValid(tup))
2300 0 : elog(ERROR, "cache lookup failed for type %u", typid);
2301 208540 : typTup = (Form_pg_type) GETSTRUCT(tup);
2302 208540 : if (typTup->typtype != TYPTYPE_DOMAIN)
2303 : {
2304 : /* Not a domain, so done */
2305 203245 : ReleaseSysCache(tup);
2306 203245 : break;
2307 : }
2308 :
2309 5295 : Assert(*typmod == -1);
2310 5295 : typid = typTup->typbasetype;
2311 5295 : *typmod = typTup->typtypmod;
2312 :
2313 5295 : ReleaseSysCache(tup);
2314 5295 : }
2315 :
2316 203245 : return typid;
2317 : }
2318 :
2319 : /*
2320 : * get_typavgwidth
2321 : *
2322 : * Given a type OID and a typmod value (pass -1 if typmod is unknown),
2323 : * estimate the average width of values of the type. This is used by
2324 : * the planner, which doesn't require absolutely correct results;
2325 : * it's OK (and expected) to guess if we don't know for sure.
2326 : */
2327 : int32
2328 65814 : get_typavgwidth(Oid typid, int32 typmod)
2329 : {
2330 65814 : int typlen = get_typlen(typid);
2331 : int32 maxwidth;
2332 :
2333 : /*
2334 : * Easy if it's a fixed-width type
2335 : */
2336 65814 : if (typlen > 0)
2337 42665 : return typlen;
2338 :
2339 : /*
2340 : * type_maximum_size knows the encoding of typmod for some datatypes;
2341 : * don't duplicate that knowledge here.
2342 : */
2343 23149 : maxwidth = type_maximum_size(typid, typmod);
2344 23149 : if (maxwidth > 0)
2345 : {
2346 : /*
2347 : * For BPCHAR, the max width is also the only width. Otherwise we
2348 : * need to guess about the typical data width given the max. A sliding
2349 : * scale for percentage of max width seems reasonable.
2350 : */
2351 2508 : if (typid == BPCHAROID)
2352 1691 : return maxwidth;
2353 817 : if (maxwidth <= 32)
2354 206 : return maxwidth; /* assume full width */
2355 611 : if (maxwidth < 1000)
2356 597 : return 32 + (maxwidth - 32) / 2; /* assume 50% */
2357 :
2358 : /*
2359 : * Beyond 1000, assume we're looking at something like
2360 : * "varchar(10000)" where the limit isn't actually reached often, and
2361 : * use a fixed estimate.
2362 : */
2363 14 : return 32 + (1000 - 32) / 2;
2364 : }
2365 :
2366 : /*
2367 : * Oops, we have no idea ... wild guess time.
2368 : */
2369 20641 : return 32;
2370 : }
2371 :
2372 : /*
2373 : * get_typtype
2374 : *
2375 : * Given the type OID, find if it is a basic type, a complex type, etc.
2376 : * It returns the null char if the cache lookup fails...
2377 : */
2378 : char
2379 36935 : get_typtype(Oid typid)
2380 : {
2381 : HeapTuple tp;
2382 :
2383 36935 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2384 36935 : if (HeapTupleIsValid(tp))
2385 : {
2386 36917 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2387 : char result;
2388 :
2389 36917 : result = typtup->typtype;
2390 36917 : ReleaseSysCache(tp);
2391 36917 : return result;
2392 : }
2393 : else
2394 18 : return '\0';
2395 : }
2396 :
2397 : /*
2398 : * type_is_rowtype
2399 : *
2400 : * Convenience function to determine whether a type OID represents
2401 : * a "rowtype" type --- either RECORD or a named composite type.
2402 : */
2403 : bool
2404 13903 : type_is_rowtype(Oid typid)
2405 : {
2406 13903 : return (typid == RECORDOID || get_typtype(typid) == TYPTYPE_COMPOSITE);
2407 : }
2408 :
2409 : /*
2410 : * type_is_enum
2411 : * Returns true if the given type is an enum type.
2412 : */
2413 : bool
2414 1926 : type_is_enum(Oid typid)
2415 : {
2416 1926 : return (get_typtype(typid) == TYPTYPE_ENUM);
2417 : }
2418 :
2419 : /*
2420 : * type_is_range
2421 : * Returns true if the given type is a range type.
2422 : */
2423 : bool
2424 542 : type_is_range(Oid typid)
2425 : {
2426 542 : return (get_typtype(typid) == TYPTYPE_RANGE);
2427 : }
2428 :
2429 : /*
2430 : * get_type_category_preferred
2431 : *
2432 : * Given the type OID, fetch its category and preferred-type status.
2433 : * Throws error on failure.
2434 : */
2435 : void
2436 12158 : get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
2437 : {
2438 : HeapTuple tp;
2439 : Form_pg_type typtup;
2440 :
2441 12158 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2442 12158 : if (!HeapTupleIsValid(tp))
2443 0 : elog(ERROR, "cache lookup failed for type %u", typid);
2444 12158 : typtup = (Form_pg_type) GETSTRUCT(tp);
2445 12158 : *typcategory = typtup->typcategory;
2446 12158 : *typispreferred = typtup->typispreferred;
2447 12158 : ReleaseSysCache(tp);
2448 12158 : }
2449 :
2450 : /*
2451 : * get_typ_typrelid
2452 : *
2453 : * Given the type OID, get the typrelid (InvalidOid if not a complex
2454 : * type).
2455 : */
2456 : Oid
2457 52 : get_typ_typrelid(Oid typid)
2458 : {
2459 : HeapTuple tp;
2460 :
2461 52 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2462 52 : if (HeapTupleIsValid(tp))
2463 : {
2464 52 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2465 : Oid result;
2466 :
2467 52 : result = typtup->typrelid;
2468 52 : ReleaseSysCache(tp);
2469 52 : return result;
2470 : }
2471 : else
2472 0 : return InvalidOid;
2473 : }
2474 :
2475 : /*
2476 : * get_element_type
2477 : *
2478 : * Given the type OID, get the typelem (InvalidOid if not an array type).
2479 : *
2480 : * NB: this only considers varlena arrays to be true arrays; InvalidOid is
2481 : * returned if the input is a fixed-length array type.
2482 : */
2483 : Oid
2484 43807 : get_element_type(Oid typid)
2485 : {
2486 : HeapTuple tp;
2487 :
2488 43807 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2489 43807 : if (HeapTupleIsValid(tp))
2490 : {
2491 43793 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2492 : Oid result;
2493 :
2494 43793 : if (typtup->typlen == -1)
2495 16217 : result = typtup->typelem;
2496 : else
2497 27576 : result = InvalidOid;
2498 43793 : ReleaseSysCache(tp);
2499 43793 : return result;
2500 : }
2501 : else
2502 14 : return InvalidOid;
2503 : }
2504 :
2505 : /*
2506 : * get_array_type
2507 : *
2508 : * Given the type OID, get the corresponding "true" array type.
2509 : * Returns InvalidOid if no array type can be found.
2510 : */
2511 : Oid
2512 4297 : get_array_type(Oid typid)
2513 : {
2514 : HeapTuple tp;
2515 4297 : Oid result = InvalidOid;
2516 :
2517 4297 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2518 4297 : if (HeapTupleIsValid(tp))
2519 : {
2520 4297 : result = ((Form_pg_type) GETSTRUCT(tp))->typarray;
2521 4297 : ReleaseSysCache(tp);
2522 : }
2523 4297 : return result;
2524 : }
2525 :
2526 : /*
2527 : * get_promoted_array_type
2528 : *
2529 : * The "promoted" type is what you'd get from an ARRAY(SELECT ...)
2530 : * construct, that is, either the corresponding "true" array type
2531 : * if the input is a scalar type that has such an array type,
2532 : * or the same type if the input is already a "true" array type.
2533 : * Returns InvalidOid if neither rule is satisfied.
2534 : */
2535 : Oid
2536 947 : get_promoted_array_type(Oid typid)
2537 : {
2538 947 : Oid array_type = get_array_type(typid);
2539 :
2540 947 : if (OidIsValid(array_type))
2541 941 : return array_type;
2542 6 : if (OidIsValid(get_element_type(typid)))
2543 6 : return typid;
2544 0 : return InvalidOid;
2545 : }
2546 :
2547 : /*
2548 : * get_base_element_type
2549 : * Given the type OID, get the typelem, looking "through" any domain
2550 : * to its underlying array type.
2551 : *
2552 : * This is equivalent to get_element_type(getBaseType(typid)), but avoids
2553 : * an extra cache lookup. Note that it fails to provide any information
2554 : * about the typmod of the array.
2555 : */
2556 : Oid
2557 3713 : get_base_element_type(Oid typid)
2558 : {
2559 : /*
2560 : * We loop to find the bottom base type in a stack of domains.
2561 : */
2562 : for (;;)
2563 : {
2564 : HeapTuple tup;
2565 : Form_pg_type typTup;
2566 :
2567 3713 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2568 3713 : if (!HeapTupleIsValid(tup))
2569 20 : break;
2570 3693 : typTup = (Form_pg_type) GETSTRUCT(tup);
2571 3693 : if (typTup->typtype != TYPTYPE_DOMAIN)
2572 : {
2573 : /* Not a domain, so stop descending */
2574 : Oid result;
2575 :
2576 : /* This test must match get_element_type */
2577 3690 : if (typTup->typlen == -1)
2578 1522 : result = typTup->typelem;
2579 : else
2580 2168 : result = InvalidOid;
2581 3690 : ReleaseSysCache(tup);
2582 3690 : return result;
2583 : }
2584 :
2585 3 : typid = typTup->typbasetype;
2586 3 : ReleaseSysCache(tup);
2587 3 : }
2588 :
2589 : /* Like get_element_type, silently return InvalidOid for bogus input */
2590 20 : return InvalidOid;
2591 : }
2592 :
2593 : /*
2594 : * getTypeInputInfo
2595 : *
2596 : * Get info needed for converting values of a type to internal form
2597 : */
2598 : void
2599 8367 : getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
2600 : {
2601 : HeapTuple typeTuple;
2602 : Form_pg_type pt;
2603 :
2604 8367 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
2605 8367 : if (!HeapTupleIsValid(typeTuple))
2606 0 : elog(ERROR, "cache lookup failed for type %u", type);
2607 8367 : pt = (Form_pg_type) GETSTRUCT(typeTuple);
2608 :
2609 8367 : if (!pt->typisdefined)
2610 0 : ereport(ERROR,
2611 : (errcode(ERRCODE_UNDEFINED_OBJECT),
2612 : errmsg("type %s is only a shell",
2613 : format_type_be(type))));
2614 8367 : if (!OidIsValid(pt->typinput))
2615 0 : ereport(ERROR,
2616 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2617 : errmsg("no input function available for type %s",
2618 : format_type_be(type))));
2619 :
2620 8367 : *typInput = pt->typinput;
2621 8367 : *typIOParam = getTypeIOParam(typeTuple);
2622 :
2623 8367 : ReleaseSysCache(typeTuple);
2624 8367 : }
2625 :
2626 : /*
2627 : * getTypeOutputInfo
2628 : *
2629 : * Get info needed for printing values of a type
2630 : */
2631 : void
2632 37841 : getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
2633 : {
2634 : HeapTuple typeTuple;
2635 : Form_pg_type pt;
2636 :
2637 37841 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
2638 37841 : if (!HeapTupleIsValid(typeTuple))
2639 0 : elog(ERROR, "cache lookup failed for type %u", type);
2640 37841 : pt = (Form_pg_type) GETSTRUCT(typeTuple);
2641 :
2642 37841 : if (!pt->typisdefined)
2643 0 : ereport(ERROR,
2644 : (errcode(ERRCODE_UNDEFINED_OBJECT),
2645 : errmsg("type %s is only a shell",
2646 : format_type_be(type))));
2647 37841 : if (!OidIsValid(pt->typoutput))
2648 0 : ereport(ERROR,
2649 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2650 : errmsg("no output function available for type %s",
2651 : format_type_be(type))));
2652 :
2653 37841 : *typOutput = pt->typoutput;
2654 37841 : *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
2655 :
2656 37841 : ReleaseSysCache(typeTuple);
2657 37841 : }
2658 :
2659 : /*
2660 : * getTypeBinaryInputInfo
2661 : *
2662 : * Get info needed for binary input of values of a type
2663 : */
2664 : void
2665 827 : getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
2666 : {
2667 : HeapTuple typeTuple;
2668 : Form_pg_type pt;
2669 :
2670 827 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
2671 827 : if (!HeapTupleIsValid(typeTuple))
2672 0 : elog(ERROR, "cache lookup failed for type %u", type);
2673 827 : pt = (Form_pg_type) GETSTRUCT(typeTuple);
2674 :
2675 827 : if (!pt->typisdefined)
2676 0 : ereport(ERROR,
2677 : (errcode(ERRCODE_UNDEFINED_OBJECT),
2678 : errmsg("type %s is only a shell",
2679 : format_type_be(type))));
2680 827 : if (!OidIsValid(pt->typreceive))
2681 0 : ereport(ERROR,
2682 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2683 : errmsg("no binary input function available for type %s",
2684 : format_type_be(type))));
2685 :
2686 827 : *typReceive = pt->typreceive;
2687 827 : *typIOParam = getTypeIOParam(typeTuple);
2688 :
2689 827 : ReleaseSysCache(typeTuple);
2690 827 : }
2691 :
2692 : /*
2693 : * getTypeBinaryOutputInfo
2694 : *
2695 : * Get info needed for binary output of values of a type
2696 : */
2697 : void
2698 265 : getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
2699 : {
2700 : HeapTuple typeTuple;
2701 : Form_pg_type pt;
2702 :
2703 265 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
2704 265 : if (!HeapTupleIsValid(typeTuple))
2705 0 : elog(ERROR, "cache lookup failed for type %u", type);
2706 265 : pt = (Form_pg_type) GETSTRUCT(typeTuple);
2707 :
2708 265 : if (!pt->typisdefined)
2709 0 : ereport(ERROR,
2710 : (errcode(ERRCODE_UNDEFINED_OBJECT),
2711 : errmsg("type %s is only a shell",
2712 : format_type_be(type))));
2713 265 : if (!OidIsValid(pt->typsend))
2714 0 : ereport(ERROR,
2715 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2716 : errmsg("no binary output function available for type %s",
2717 : format_type_be(type))));
2718 :
2719 265 : *typSend = pt->typsend;
2720 265 : *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
2721 :
2722 265 : ReleaseSysCache(typeTuple);
2723 265 : }
2724 :
2725 : /*
2726 : * get_typmodin
2727 : *
2728 : * Given the type OID, return the type's typmodin procedure, if any.
2729 : */
2730 : Oid
2731 0 : get_typmodin(Oid typid)
2732 : {
2733 : HeapTuple tp;
2734 :
2735 0 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2736 0 : if (HeapTupleIsValid(tp))
2737 : {
2738 0 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2739 : Oid result;
2740 :
2741 0 : result = typtup->typmodin;
2742 0 : ReleaseSysCache(tp);
2743 0 : return result;
2744 : }
2745 : else
2746 0 : return InvalidOid;
2747 : }
2748 :
2749 : #ifdef NOT_USED
2750 : /*
2751 : * get_typmodout
2752 : *
2753 : * Given the type OID, return the type's typmodout procedure, if any.
2754 : */
2755 : Oid
2756 : get_typmodout(Oid typid)
2757 : {
2758 : HeapTuple tp;
2759 :
2760 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2761 : if (HeapTupleIsValid(tp))
2762 : {
2763 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2764 : Oid result;
2765 :
2766 : result = typtup->typmodout;
2767 : ReleaseSysCache(tp);
2768 : return result;
2769 : }
2770 : else
2771 : return InvalidOid;
2772 : }
2773 : #endif /* NOT_USED */
2774 :
2775 : /*
2776 : * get_typcollation
2777 : *
2778 : * Given the type OID, return the type's typcollation attribute.
2779 : */
2780 : Oid
2781 78145 : get_typcollation(Oid typid)
2782 : {
2783 : HeapTuple tp;
2784 :
2785 78145 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2786 78145 : if (HeapTupleIsValid(tp))
2787 : {
2788 78135 : Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2789 : Oid result;
2790 :
2791 78135 : result = typtup->typcollation;
2792 78135 : ReleaseSysCache(tp);
2793 78135 : return result;
2794 : }
2795 : else
2796 10 : return InvalidOid;
2797 : }
2798 :
2799 :
2800 : /*
2801 : * type_is_collatable
2802 : *
2803 : * Return whether the type cares about collations
2804 : */
2805 : bool
2806 10965 : type_is_collatable(Oid typid)
2807 : {
2808 10965 : return OidIsValid(get_typcollation(typid));
2809 : }
2810 :
2811 :
2812 : /* ---------- STATISTICS CACHE ---------- */
2813 :
2814 : /*
2815 : * get_attavgwidth
2816 : *
2817 : * Given the table and attribute number of a column, get the average
2818 : * width of entries in the column. Return zero if no data available.
2819 : *
2820 : * Currently this is only consulted for individual tables, not for inheritance
2821 : * trees, so we don't need an "inh" parameter.
2822 : *
2823 : * Calling a hook at this point looks somewhat strange, but is required
2824 : * because the optimizer calls this function without any other way for
2825 : * plug-ins to control the result.
2826 : */
2827 : int32
2828 39723 : get_attavgwidth(Oid relid, AttrNumber attnum)
2829 : {
2830 : HeapTuple tp;
2831 : int32 stawidth;
2832 :
2833 39723 : if (get_attavgwidth_hook)
2834 : {
2835 0 : stawidth = (*get_attavgwidth_hook) (relid, attnum);
2836 0 : if (stawidth > 0)
2837 0 : return stawidth;
2838 : }
2839 39723 : tp = SearchSysCache3(STATRELATTINH,
2840 : ObjectIdGetDatum(relid),
2841 : Int16GetDatum(attnum),
2842 : BoolGetDatum(false));
2843 39723 : if (HeapTupleIsValid(tp))
2844 : {
2845 16333 : stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
2846 16333 : ReleaseSysCache(tp);
2847 16333 : if (stawidth > 0)
2848 16032 : return stawidth;
2849 : }
2850 23691 : return 0;
2851 : }
2852 :
2853 : /*
2854 : * get_attstatsslot
2855 : *
2856 : * Extract the contents of a "slot" of a pg_statistic tuple.
2857 : * Returns TRUE if requested slot type was found, else FALSE.
2858 : *
2859 : * Unlike other routines in this file, this takes a pointer to an
2860 : * already-looked-up tuple in the pg_statistic cache. We do this since
2861 : * most callers will want to extract more than one value from the cache
2862 : * entry, and we don't want to repeat the cache lookup unnecessarily.
2863 : * Also, this API allows this routine to be used with statistics tuples
2864 : * that have been provided by a stats hook and didn't really come from
2865 : * pg_statistic.
2866 : *
2867 : * sslot: pointer to output area (typically, a local variable in the caller).
2868 : * statstuple: pg_statistic tuple to be examined.
2869 : * reqkind: STAKIND code for desired statistics slot kind.
2870 : * reqop: STAOP value wanted, or InvalidOid if don't care.
2871 : * flags: bitmask of ATTSTATSSLOT_VALUES and/or ATTSTATSSLOT_NUMBERS.
2872 : *
2873 : * If a matching slot is found, TRUE is returned, and *sslot is filled thus:
2874 : * staop: receives the actual STAOP value.
2875 : * valuetype: receives actual datatype of the elements of stavalues.
2876 : * values: receives pointer to an array of the slot's stavalues.
2877 : * nvalues: receives number of stavalues.
2878 : * numbers: receives pointer to an array of the slot's stanumbers (as float4).
2879 : * nnumbers: receives number of stanumbers.
2880 : *
2881 : * valuetype/values/nvalues are InvalidOid/NULL/0 if ATTSTATSSLOT_VALUES
2882 : * wasn't specified. Likewise, numbers/nnumbers are NULL/0 if
2883 : * ATTSTATSSLOT_NUMBERS wasn't specified.
2884 : *
2885 : * If no matching slot is found, FALSE is returned, and *sslot is zeroed.
2886 : *
2887 : * The data referred to by the fields of sslot is locally palloc'd and
2888 : * is independent of the original pg_statistic tuple. When the caller
2889 : * is done with it, call free_attstatsslot to release the palloc'd data.
2890 : *
2891 : * If it's desirable to call free_attstatsslot when get_attstatsslot might
2892 : * not have been called, memset'ing sslot to zeroes will allow that.
2893 : */
2894 : bool
2895 28519 : get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple,
2896 : int reqkind, Oid reqop, int flags)
2897 : {
2898 28519 : Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
2899 : int i;
2900 : Datum val;
2901 : bool isnull;
2902 : ArrayType *statarray;
2903 : Oid arrayelemtype;
2904 : int narrayelem;
2905 : HeapTuple typeTuple;
2906 : Form_pg_type typeForm;
2907 :
2908 : /* initialize *sslot properly */
2909 28519 : memset(sslot, 0, sizeof(AttStatsSlot));
2910 :
2911 65850 : for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
2912 : {
2913 61073 : if ((&stats->stakind1)[i] == reqkind &&
2914 8755 : (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
2915 : break;
2916 : }
2917 28519 : if (i >= STATISTIC_NUM_SLOTS)
2918 4777 : return false; /* not there */
2919 :
2920 23742 : sslot->staop = (&stats->staop1)[i];
2921 :
2922 23742 : if (flags & ATTSTATSSLOT_VALUES)
2923 : {
2924 11148 : val = SysCacheGetAttr(STATRELATTINH, statstuple,
2925 : Anum_pg_statistic_stavalues1 + i,
2926 : &isnull);
2927 11148 : if (isnull)
2928 0 : elog(ERROR, "stavalues is null");
2929 :
2930 : /*
2931 : * Detoast the array if needed, and in any case make a copy that's
2932 : * under control of this AttStatsSlot.
2933 : */
2934 11148 : statarray = DatumGetArrayTypePCopy(val);
2935 :
2936 : /*
2937 : * Extract the actual array element type, and pass it back in case the
2938 : * caller needs it.
2939 : */
2940 11148 : sslot->valuetype = arrayelemtype = ARR_ELEMTYPE(statarray);
2941 :
2942 : /* Need info about element type */
2943 11148 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrayelemtype));
2944 11148 : if (!HeapTupleIsValid(typeTuple))
2945 0 : elog(ERROR, "cache lookup failed for type %u", arrayelemtype);
2946 11148 : typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
2947 :
2948 : /* Deconstruct array into Datum elements; NULLs not expected */
2949 44592 : deconstruct_array(statarray,
2950 : arrayelemtype,
2951 11148 : typeForm->typlen,
2952 11148 : typeForm->typbyval,
2953 11148 : typeForm->typalign,
2954 : &sslot->values, NULL, &sslot->nvalues);
2955 :
2956 : /*
2957 : * If the element type is pass-by-reference, we now have a bunch of
2958 : * Datums that are pointers into the statarray, so we need to keep
2959 : * that until free_attstatsslot. Otherwise, all the useful info is in
2960 : * sslot->values[], so we can free the array object immediately.
2961 : */
2962 11148 : if (!typeForm->typbyval)
2963 1133 : sslot->values_arr = statarray;
2964 : else
2965 10015 : pfree(statarray);
2966 :
2967 11148 : ReleaseSysCache(typeTuple);
2968 : }
2969 :
2970 23742 : if (flags & ATTSTATSSLOT_NUMBERS)
2971 : {
2972 20572 : val = SysCacheGetAttr(STATRELATTINH, statstuple,
2973 : Anum_pg_statistic_stanumbers1 + i,
2974 : &isnull);
2975 20572 : if (isnull)
2976 0 : elog(ERROR, "stanumbers is null");
2977 :
2978 : /*
2979 : * Detoast the array if needed, and in any case make a copy that's
2980 : * under control of this AttStatsSlot.
2981 : */
2982 20572 : statarray = DatumGetArrayTypePCopy(val);
2983 :
2984 : /*
2985 : * We expect the array to be a 1-D float4 array; verify that. We don't
2986 : * need to use deconstruct_array() since the array data is just going
2987 : * to look like a C array of float4 values.
2988 : */
2989 20572 : narrayelem = ARR_DIMS(statarray)[0];
2990 41144 : if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
2991 41144 : ARR_HASNULL(statarray) ||
2992 20572 : ARR_ELEMTYPE(statarray) != FLOAT4OID)
2993 0 : elog(ERROR, "stanumbers is not a 1-D float4 array");
2994 :
2995 : /* Give caller a pointer directly into the statarray */
2996 20572 : sslot->numbers = (float4 *) ARR_DATA_PTR(statarray);
2997 20572 : sslot->nnumbers = narrayelem;
2998 :
2999 : /* We'll free the statarray in free_attstatsslot */
3000 20572 : sslot->numbers_arr = statarray;
3001 : }
3002 :
3003 23742 : return true;
3004 : }
3005 :
3006 : /*
3007 : * free_attstatsslot
3008 : * Free data allocated by get_attstatsslot
3009 : */
3010 : void
3011 33587 : free_attstatsslot(AttStatsSlot *sslot)
3012 : {
3013 : /* The values[] array was separately palloc'd by deconstruct_array */
3014 33587 : if (sslot->values)
3015 11148 : pfree(sslot->values);
3016 : /* The numbers[] array points into numbers_arr, do not pfree it */
3017 : /* Free the detoasted array objects, if any */
3018 33587 : if (sslot->values_arr)
3019 1133 : pfree(sslot->values_arr);
3020 33587 : if (sslot->numbers_arr)
3021 20572 : pfree(sslot->numbers_arr);
3022 33587 : }
3023 :
3024 : /* ---------- PG_NAMESPACE CACHE ---------- */
3025 :
3026 : /*
3027 : * get_namespace_name
3028 : * Returns the name of a given namespace
3029 : *
3030 : * Returns a palloc'd copy of the string, or NULL if no such namespace.
3031 : */
3032 : char *
3033 11897 : get_namespace_name(Oid nspid)
3034 : {
3035 : HeapTuple tp;
3036 :
3037 11897 : tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
3038 11897 : if (HeapTupleIsValid(tp))
3039 : {
3040 11897 : Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
3041 : char *result;
3042 :
3043 11897 : result = pstrdup(NameStr(nsptup->nspname));
3044 11897 : ReleaseSysCache(tp);
3045 11897 : return result;
3046 : }
3047 : else
3048 0 : return NULL;
3049 : }
3050 :
3051 : /*
3052 : * get_namespace_name_or_temp
3053 : * As above, but if it is this backend's temporary namespace, return
3054 : * "pg_temp" instead.
3055 : */
3056 : char *
3057 967 : get_namespace_name_or_temp(Oid nspid)
3058 : {
3059 967 : if (isTempNamespace(nspid))
3060 3 : return "pg_temp";
3061 : else
3062 964 : return get_namespace_name(nspid);
3063 : }
3064 :
3065 : /* ---------- PG_RANGE CACHE ---------- */
3066 :
3067 : /*
3068 : * get_range_subtype
3069 : * Returns the subtype of a given range type
3070 : *
3071 : * Returns InvalidOid if the type is not a range type.
3072 : */
3073 : Oid
3074 574 : get_range_subtype(Oid rangeOid)
3075 : {
3076 : HeapTuple tp;
3077 :
3078 574 : tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
3079 574 : if (HeapTupleIsValid(tp))
3080 : {
3081 338 : Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
3082 : Oid result;
3083 :
3084 338 : result = rngtup->rngsubtype;
3085 338 : ReleaseSysCache(tp);
3086 338 : return result;
3087 : }
3088 : else
3089 236 : return InvalidOid;
3090 : }
|