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