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