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