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