1 /*-------------------------------------------------------------------------
2  *
3  * parse_type.c
4  *		handle type operations for parser
5  *
6  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/parser/parse_type.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/htup_details.h"
18 #include "catalog/namespace.h"
19 #include "catalog/pg_type.h"
20 #include "lib/stringinfo.h"
21 #include "nodes/makefuncs.h"
22 #include "parser/parse_type.h"
23 #include "parser/parser.h"
24 #include "utils/array.h"
25 #include "utils/builtins.h"
26 #include "utils/lsyscache.h"
27 #include "utils/syscache.h"
28 
29 static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
30 							 Type typ);
31 
32 
33 /*
34  * LookupTypeName
35  *		Wrapper for typical case.
36  */
37 Type
LookupTypeName(ParseState * pstate,const TypeName * typeName,int32 * typmod_p,bool missing_ok)38 LookupTypeName(ParseState *pstate, const TypeName *typeName,
39 			   int32 *typmod_p, bool missing_ok)
40 {
41 	return LookupTypeNameExtended(pstate,
42 								  typeName, typmod_p, true, missing_ok);
43 }
44 
45 /*
46  * LookupTypeNameExtended
47  *		Given a TypeName object, lookup the pg_type syscache entry of the type.
48  *		Returns NULL if no such type can be found.  If the type is found,
49  *		the typmod value represented in the TypeName struct is computed and
50  *		stored into *typmod_p.
51  *
52  * NB: on success, the caller must ReleaseSysCache the type tuple when done
53  * with it.
54  *
55  * NB: direct callers of this function MUST check typisdefined before assuming
56  * that the type is fully valid.  Most code should go through typenameType
57  * or typenameTypeId instead.
58  *
59  * typmod_p can be passed as NULL if the caller does not care to know the
60  * typmod value, but the typmod decoration (if any) will be validated anyway,
61  * except in the case where the type is not found.  Note that if the type is
62  * found but is a shell, and there is typmod decoration, an error will be
63  * thrown --- this is intentional.
64  *
65  * If temp_ok is false, ignore types in the temporary namespace.  Pass false
66  * when the caller will decide, using goodness of fit criteria, whether the
67  * typeName is actually a type or something else.  If typeName always denotes
68  * a type (or denotes nothing), pass true.
69  *
70  * pstate is only used for error location info, and may be NULL.
71  */
72 Type
LookupTypeNameExtended(ParseState * pstate,const TypeName * typeName,int32 * typmod_p,bool temp_ok,bool missing_ok)73 LookupTypeNameExtended(ParseState *pstate,
74 					   const TypeName *typeName, int32 *typmod_p,
75 					   bool temp_ok, bool missing_ok)
76 {
77 	Oid			typoid;
78 	HeapTuple	tup;
79 	int32		typmod;
80 
81 	if (typeName->names == NIL)
82 	{
83 		/* We have the OID already if it's an internally generated TypeName */
84 		typoid = typeName->typeOid;
85 	}
86 	else if (typeName->pct_type)
87 	{
88 		/* Handle %TYPE reference to type of an existing field */
89 		RangeVar   *rel = makeRangeVar(NULL, NULL, typeName->location);
90 		char	   *field = NULL;
91 		Oid			relid;
92 		AttrNumber	attnum;
93 
94 		/* deconstruct the name list */
95 		switch (list_length(typeName->names))
96 		{
97 			case 1:
98 				ereport(ERROR,
99 						(errcode(ERRCODE_SYNTAX_ERROR),
100 						 errmsg("improper %%TYPE reference (too few dotted names): %s",
101 								NameListToString(typeName->names)),
102 						 parser_errposition(pstate, typeName->location)));
103 				break;
104 			case 2:
105 				rel->relname = strVal(linitial(typeName->names));
106 				field = strVal(lsecond(typeName->names));
107 				break;
108 			case 3:
109 				rel->schemaname = strVal(linitial(typeName->names));
110 				rel->relname = strVal(lsecond(typeName->names));
111 				field = strVal(lthird(typeName->names));
112 				break;
113 			case 4:
114 				rel->catalogname = strVal(linitial(typeName->names));
115 				rel->schemaname = strVal(lsecond(typeName->names));
116 				rel->relname = strVal(lthird(typeName->names));
117 				field = strVal(lfourth(typeName->names));
118 				break;
119 			default:
120 				ereport(ERROR,
121 						(errcode(ERRCODE_SYNTAX_ERROR),
122 						 errmsg("improper %%TYPE reference (too many dotted names): %s",
123 								NameListToString(typeName->names)),
124 						 parser_errposition(pstate, typeName->location)));
125 				break;
126 		}
127 
128 		/*
129 		 * Look up the field.
130 		 *
131 		 * XXX: As no lock is taken here, this might fail in the presence of
132 		 * concurrent DDL.  But taking a lock would carry a performance
133 		 * penalty and would also require a permissions check.
134 		 */
135 		relid = RangeVarGetRelid(rel, NoLock, missing_ok);
136 		attnum = get_attnum(relid, field);
137 		if (attnum == InvalidAttrNumber)
138 		{
139 			if (missing_ok)
140 				typoid = InvalidOid;
141 			else
142 				ereport(ERROR,
143 						(errcode(ERRCODE_UNDEFINED_COLUMN),
144 						 errmsg("column \"%s\" of relation \"%s\" does not exist",
145 								field, rel->relname),
146 						 parser_errposition(pstate, typeName->location)));
147 		}
148 		else
149 		{
150 			typoid = get_atttype(relid, attnum);
151 
152 			/* this construct should never have an array indicator */
153 			Assert(typeName->arrayBounds == NIL);
154 
155 			/* emit nuisance notice (intentionally not errposition'd) */
156 			ereport(NOTICE,
157 					(errmsg("type reference %s converted to %s",
158 							TypeNameToString(typeName),
159 							format_type_be(typoid))));
160 		}
161 	}
162 	else
163 	{
164 		/* Normal reference to a type name */
165 		char	   *schemaname;
166 		char	   *typname;
167 
168 		/* deconstruct the name list */
169 		DeconstructQualifiedName(typeName->names, &schemaname, &typname);
170 
171 		if (schemaname)
172 		{
173 			/* Look in specific schema only */
174 			Oid			namespaceId;
175 			ParseCallbackState pcbstate;
176 
177 			setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
178 
179 			namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
180 			if (OidIsValid(namespaceId))
181 				typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
182 										 PointerGetDatum(typname),
183 										 ObjectIdGetDatum(namespaceId));
184 			else
185 				typoid = InvalidOid;
186 
187 			cancel_parser_errposition_callback(&pcbstate);
188 		}
189 		else
190 		{
191 			/* Unqualified type name, so search the search path */
192 			typoid = TypenameGetTypidExtended(typname, temp_ok);
193 		}
194 
195 		/* If an array reference, return the array type instead */
196 		if (typeName->arrayBounds != NIL)
197 			typoid = get_array_type(typoid);
198 	}
199 
200 	if (!OidIsValid(typoid))
201 	{
202 		if (typmod_p)
203 			*typmod_p = -1;
204 		return NULL;
205 	}
206 
207 	tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
208 	if (!HeapTupleIsValid(tup)) /* should not happen */
209 		elog(ERROR, "cache lookup failed for type %u", typoid);
210 
211 	typmod = typenameTypeMod(pstate, typeName, (Type) tup);
212 
213 	if (typmod_p)
214 		*typmod_p = typmod;
215 
216 	return (Type) tup;
217 }
218 
219 /*
220  * LookupTypeNameOid
221  *		Given a TypeName object, lookup the pg_type syscache entry of the type.
222  *		Returns InvalidOid if no such type can be found.  If the type is found,
223  *		return its Oid.
224  *
225  * NB: direct callers of this function need to be aware that the type OID
226  * returned may correspond to a shell type.  Most code should go through
227  * typenameTypeId instead.
228  *
229  * pstate is only used for error location info, and may be NULL.
230  */
231 Oid
LookupTypeNameOid(ParseState * pstate,const TypeName * typeName,bool missing_ok)232 LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
233 {
234 	Oid			typoid;
235 	Type		tup;
236 
237 	tup = LookupTypeName(pstate, typeName, NULL, missing_ok);
238 	if (tup == NULL)
239 	{
240 		if (!missing_ok)
241 			ereport(ERROR,
242 					(errcode(ERRCODE_UNDEFINED_OBJECT),
243 					 errmsg("type \"%s\" does not exist",
244 							TypeNameToString(typeName)),
245 					 parser_errposition(pstate, typeName->location)));
246 
247 		return InvalidOid;
248 	}
249 
250 	typoid = ((Form_pg_type) GETSTRUCT(tup))->oid;
251 	ReleaseSysCache(tup);
252 
253 	return typoid;
254 }
255 
256 /*
257  * typenameType - given a TypeName, return a Type structure and typmod
258  *
259  * This is equivalent to LookupTypeName, except that this will report
260  * a suitable error message if the type cannot be found or is not defined.
261  * Callers of this can therefore assume the result is a fully valid type.
262  */
263 Type
typenameType(ParseState * pstate,const TypeName * typeName,int32 * typmod_p)264 typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
265 {
266 	Type		tup;
267 
268 	tup = LookupTypeName(pstate, typeName, typmod_p, false);
269 	if (tup == NULL)
270 		ereport(ERROR,
271 				(errcode(ERRCODE_UNDEFINED_OBJECT),
272 				 errmsg("type \"%s\" does not exist",
273 						TypeNameToString(typeName)),
274 				 parser_errposition(pstate, typeName->location)));
275 	if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
276 		ereport(ERROR,
277 				(errcode(ERRCODE_UNDEFINED_OBJECT),
278 				 errmsg("type \"%s\" is only a shell",
279 						TypeNameToString(typeName)),
280 				 parser_errposition(pstate, typeName->location)));
281 	return tup;
282 }
283 
284 /*
285  * typenameTypeId - given a TypeName, return the type's OID
286  *
287  * This is similar to typenameType, but we only hand back the type OID
288  * not the syscache entry.
289  */
290 Oid
typenameTypeId(ParseState * pstate,const TypeName * typeName)291 typenameTypeId(ParseState *pstate, const TypeName *typeName)
292 {
293 	Oid			typoid;
294 	Type		tup;
295 
296 	tup = typenameType(pstate, typeName, NULL);
297 	typoid = ((Form_pg_type) GETSTRUCT(tup))->oid;
298 	ReleaseSysCache(tup);
299 
300 	return typoid;
301 }
302 
303 /*
304  * typenameTypeIdAndMod - given a TypeName, return the type's OID and typmod
305  *
306  * This is equivalent to typenameType, but we only hand back the type OID
307  * and typmod, not the syscache entry.
308  */
309 void
typenameTypeIdAndMod(ParseState * pstate,const TypeName * typeName,Oid * typeid_p,int32 * typmod_p)310 typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
311 					 Oid *typeid_p, int32 *typmod_p)
312 {
313 	Type		tup;
314 
315 	tup = typenameType(pstate, typeName, typmod_p);
316 	*typeid_p = ((Form_pg_type) GETSTRUCT(tup))->oid;
317 	ReleaseSysCache(tup);
318 }
319 
320 /*
321  * typenameTypeMod - given a TypeName, return the internal typmod value
322  *
323  * This will throw an error if the TypeName includes type modifiers that are
324  * illegal for the data type.
325  *
326  * The actual type OID represented by the TypeName must already have been
327  * looked up, and is passed as "typ".
328  *
329  * pstate is only used for error location info, and may be NULL.
330  */
331 static int32
typenameTypeMod(ParseState * pstate,const TypeName * typeName,Type typ)332 typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ)
333 {
334 	int32		result;
335 	Oid			typmodin;
336 	Datum	   *datums;
337 	int			n;
338 	ListCell   *l;
339 	ArrayType  *arrtypmod;
340 	ParseCallbackState pcbstate;
341 
342 	/* Return prespecified typmod if no typmod expressions */
343 	if (typeName->typmods == NIL)
344 		return typeName->typemod;
345 
346 	/*
347 	 * Else, type had better accept typmods.  We give a special error message
348 	 * for the shell-type case, since a shell couldn't possibly have a
349 	 * typmodin function.
350 	 */
351 	if (!((Form_pg_type) GETSTRUCT(typ))->typisdefined)
352 		ereport(ERROR,
353 				(errcode(ERRCODE_SYNTAX_ERROR),
354 				 errmsg("type modifier cannot be specified for shell type \"%s\"",
355 						TypeNameToString(typeName)),
356 				 parser_errposition(pstate, typeName->location)));
357 
358 	typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin;
359 
360 	if (typmodin == InvalidOid)
361 		ereport(ERROR,
362 				(errcode(ERRCODE_SYNTAX_ERROR),
363 				 errmsg("type modifier is not allowed for type \"%s\"",
364 						TypeNameToString(typeName)),
365 				 parser_errposition(pstate, typeName->location)));
366 
367 	/*
368 	 * Convert the list of raw-grammar-output expressions to a cstring array.
369 	 * Currently, we allow simple numeric constants, string literals, and
370 	 * identifiers; possibly this list could be extended.
371 	 */
372 	datums = (Datum *) palloc(list_length(typeName->typmods) * sizeof(Datum));
373 	n = 0;
374 	foreach(l, typeName->typmods)
375 	{
376 		Node	   *tm = (Node *) lfirst(l);
377 		char	   *cstr = NULL;
378 
379 		if (IsA(tm, A_Const))
380 		{
381 			A_Const    *ac = (A_Const *) tm;
382 
383 			if (IsA(&ac->val, Integer))
384 			{
385 				cstr = psprintf("%ld", (long) ac->val.val.ival);
386 			}
387 			else if (IsA(&ac->val, Float) ||
388 					 IsA(&ac->val, String))
389 			{
390 				/* we can just use the str field directly. */
391 				cstr = ac->val.val.str;
392 			}
393 		}
394 		else if (IsA(tm, ColumnRef))
395 		{
396 			ColumnRef  *cr = (ColumnRef *) tm;
397 
398 			if (list_length(cr->fields) == 1 &&
399 				IsA(linitial(cr->fields), String))
400 				cstr = strVal(linitial(cr->fields));
401 		}
402 		if (!cstr)
403 			ereport(ERROR,
404 					(errcode(ERRCODE_SYNTAX_ERROR),
405 					 errmsg("type modifiers must be simple constants or identifiers"),
406 					 parser_errposition(pstate, typeName->location)));
407 		datums[n++] = CStringGetDatum(cstr);
408 	}
409 
410 	/* hardwired knowledge about cstring's representation details here */
411 	arrtypmod = construct_array(datums, n, CSTRINGOID,
412 								-2, false, TYPALIGN_CHAR);
413 
414 	/* arrange to report location if type's typmodin function fails */
415 	setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
416 
417 	result = DatumGetInt32(OidFunctionCall1(typmodin,
418 											PointerGetDatum(arrtypmod)));
419 
420 	cancel_parser_errposition_callback(&pcbstate);
421 
422 	pfree(datums);
423 	pfree(arrtypmod);
424 
425 	return result;
426 }
427 
428 /*
429  * appendTypeNameToBuffer
430  *		Append a string representing the name of a TypeName to a StringInfo.
431  *		This is the shared guts of TypeNameToString and TypeNameListToString.
432  *
433  * NB: this must work on TypeNames that do not describe any actual type;
434  * it is mostly used for reporting lookup errors.
435  */
436 static void
appendTypeNameToBuffer(const TypeName * typeName,StringInfo string)437 appendTypeNameToBuffer(const TypeName *typeName, StringInfo string)
438 {
439 	if (typeName->names != NIL)
440 	{
441 		/* Emit possibly-qualified name as-is */
442 		ListCell   *l;
443 
444 		foreach(l, typeName->names)
445 		{
446 			if (l != list_head(typeName->names))
447 				appendStringInfoChar(string, '.');
448 			appendStringInfoString(string, strVal(lfirst(l)));
449 		}
450 	}
451 	else
452 	{
453 		/* Look up internally-specified type */
454 		appendStringInfoString(string, format_type_be(typeName->typeOid));
455 	}
456 
457 	/*
458 	 * Add decoration as needed, but only for fields considered by
459 	 * LookupTypeName
460 	 */
461 	if (typeName->pct_type)
462 		appendStringInfoString(string, "%TYPE");
463 
464 	if (typeName->arrayBounds != NIL)
465 		appendStringInfoString(string, "[]");
466 }
467 
468 /*
469  * TypeNameToString
470  *		Produce a string representing the name of a TypeName.
471  *
472  * NB: this must work on TypeNames that do not describe any actual type;
473  * it is mostly used for reporting lookup errors.
474  */
475 char *
TypeNameToString(const TypeName * typeName)476 TypeNameToString(const TypeName *typeName)
477 {
478 	StringInfoData string;
479 
480 	initStringInfo(&string);
481 	appendTypeNameToBuffer(typeName, &string);
482 	return string.data;
483 }
484 
485 /*
486  * TypeNameListToString
487  *		Produce a string representing the name(s) of a List of TypeNames
488  */
489 char *
TypeNameListToString(List * typenames)490 TypeNameListToString(List *typenames)
491 {
492 	StringInfoData string;
493 	ListCell   *l;
494 
495 	initStringInfo(&string);
496 	foreach(l, typenames)
497 	{
498 		TypeName   *typeName = lfirst_node(TypeName, l);
499 
500 		if (l != list_head(typenames))
501 			appendStringInfoChar(&string, ',');
502 		appendTypeNameToBuffer(typeName, &string);
503 	}
504 	return string.data;
505 }
506 
507 /*
508  * LookupCollation
509  *
510  * Look up collation by name, return OID, with support for error location.
511  */
512 Oid
LookupCollation(ParseState * pstate,List * collnames,int location)513 LookupCollation(ParseState *pstate, List *collnames, int location)
514 {
515 	Oid			colloid;
516 	ParseCallbackState pcbstate;
517 
518 	if (pstate)
519 		setup_parser_errposition_callback(&pcbstate, pstate, location);
520 
521 	colloid = get_collation_oid(collnames, false);
522 
523 	if (pstate)
524 		cancel_parser_errposition_callback(&pcbstate);
525 
526 	return colloid;
527 }
528 
529 /*
530  * GetColumnDefCollation
531  *
532  * Get the collation to be used for a column being defined, given the
533  * ColumnDef node and the previously-determined column type OID.
534  *
535  * pstate is only used for error location purposes, and can be NULL.
536  */
537 Oid
GetColumnDefCollation(ParseState * pstate,ColumnDef * coldef,Oid typeOid)538 GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid)
539 {
540 	Oid			result;
541 	Oid			typcollation = get_typcollation(typeOid);
542 	int			location = coldef->location;
543 
544 	if (coldef->collClause)
545 	{
546 		/* We have a raw COLLATE clause, so look up the collation */
547 		location = coldef->collClause->location;
548 		result = LookupCollation(pstate, coldef->collClause->collname,
549 								 location);
550 	}
551 	else if (OidIsValid(coldef->collOid))
552 	{
553 		/* Precooked collation spec, use that */
554 		result = coldef->collOid;
555 	}
556 	else
557 	{
558 		/* Use the type's default collation if any */
559 		result = typcollation;
560 	}
561 
562 	/* Complain if COLLATE is applied to an uncollatable type */
563 	if (OidIsValid(result) && !OidIsValid(typcollation))
564 		ereport(ERROR,
565 				(errcode(ERRCODE_DATATYPE_MISMATCH),
566 				 errmsg("collations are not supported by type %s",
567 						format_type_be(typeOid)),
568 				 parser_errposition(pstate, location)));
569 
570 	return result;
571 }
572 
573 /* return a Type structure, given a type id */
574 /* NB: caller must ReleaseSysCache the type tuple when done with it */
575 Type
typeidType(Oid id)576 typeidType(Oid id)
577 {
578 	HeapTuple	tup;
579 
580 	tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(id));
581 	if (!HeapTupleIsValid(tup))
582 		elog(ERROR, "cache lookup failed for type %u", id);
583 	return (Type) tup;
584 }
585 
586 /* given type (as type struct), return the type OID */
587 Oid
typeTypeId(Type tp)588 typeTypeId(Type tp)
589 {
590 	if (tp == NULL)				/* probably useless */
591 		elog(ERROR, "typeTypeId() called with NULL type struct");
592 	return ((Form_pg_type) GETSTRUCT(tp))->oid;
593 }
594 
595 /* given type (as type struct), return the length of type */
596 int16
typeLen(Type t)597 typeLen(Type t)
598 {
599 	Form_pg_type typ;
600 
601 	typ = (Form_pg_type) GETSTRUCT(t);
602 	return typ->typlen;
603 }
604 
605 /* given type (as type struct), return its 'byval' attribute */
606 bool
typeByVal(Type t)607 typeByVal(Type t)
608 {
609 	Form_pg_type typ;
610 
611 	typ = (Form_pg_type) GETSTRUCT(t);
612 	return typ->typbyval;
613 }
614 
615 /* given type (as type struct), return the type's name */
616 char *
typeTypeName(Type t)617 typeTypeName(Type t)
618 {
619 	Form_pg_type typ;
620 
621 	typ = (Form_pg_type) GETSTRUCT(t);
622 	/* pstrdup here because result may need to outlive the syscache entry */
623 	return pstrdup(NameStr(typ->typname));
624 }
625 
626 /* given type (as type struct), return its 'typrelid' attribute */
627 Oid
typeTypeRelid(Type typ)628 typeTypeRelid(Type typ)
629 {
630 	Form_pg_type typtup;
631 
632 	typtup = (Form_pg_type) GETSTRUCT(typ);
633 	return typtup->typrelid;
634 }
635 
636 /* given type (as type struct), return its 'typcollation' attribute */
637 Oid
typeTypeCollation(Type typ)638 typeTypeCollation(Type typ)
639 {
640 	Form_pg_type typtup;
641 
642 	typtup = (Form_pg_type) GETSTRUCT(typ);
643 	return typtup->typcollation;
644 }
645 
646 /*
647  * Given a type structure and a string, returns the internal representation
648  * of that string.  The "string" can be NULL to perform conversion of a NULL
649  * (which might result in failure, if the input function rejects NULLs).
650  */
651 Datum
stringTypeDatum(Type tp,char * string,int32 atttypmod)652 stringTypeDatum(Type tp, char *string, int32 atttypmod)
653 {
654 	Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
655 	Oid			typinput = typform->typinput;
656 	Oid			typioparam = getTypeIOParam(tp);
657 
658 	return OidInputFunctionCall(typinput, string, typioparam, atttypmod);
659 }
660 
661 /*
662  * Given a typeid, return the type's typrelid (associated relation), if any.
663  * Returns InvalidOid if type is not a composite type.
664  */
665 Oid
typeidTypeRelid(Oid type_id)666 typeidTypeRelid(Oid type_id)
667 {
668 	HeapTuple	typeTuple;
669 	Form_pg_type type;
670 	Oid			result;
671 
672 	typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
673 	if (!HeapTupleIsValid(typeTuple))
674 		elog(ERROR, "cache lookup failed for type %u", type_id);
675 	type = (Form_pg_type) GETSTRUCT(typeTuple);
676 	result = type->typrelid;
677 	ReleaseSysCache(typeTuple);
678 	return result;
679 }
680 
681 /*
682  * Given a typeid, return the type's typrelid (associated relation), if any.
683  * Returns InvalidOid if type is not a composite type or a domain over one.
684  * This is the same as typeidTypeRelid(getBaseType(type_id)), but faster.
685  */
686 Oid
typeOrDomainTypeRelid(Oid type_id)687 typeOrDomainTypeRelid(Oid type_id)
688 {
689 	HeapTuple	typeTuple;
690 	Form_pg_type type;
691 	Oid			result;
692 
693 	for (;;)
694 	{
695 		typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
696 		if (!HeapTupleIsValid(typeTuple))
697 			elog(ERROR, "cache lookup failed for type %u", type_id);
698 		type = (Form_pg_type) GETSTRUCT(typeTuple);
699 		if (type->typtype != TYPTYPE_DOMAIN)
700 		{
701 			/* Not a domain, so done looking through domains */
702 			break;
703 		}
704 		/* It is a domain, so examine the base type instead */
705 		type_id = type->typbasetype;
706 		ReleaseSysCache(typeTuple);
707 	}
708 	result = type->typrelid;
709 	ReleaseSysCache(typeTuple);
710 	return result;
711 }
712 
713 /*
714  * error context callback for parse failure during parseTypeString()
715  */
716 static void
pts_error_callback(void * arg)717 pts_error_callback(void *arg)
718 {
719 	const char *str = (const char *) arg;
720 
721 	errcontext("invalid type name \"%s\"", str);
722 }
723 
724 /*
725  * Given a string that is supposed to be a SQL-compatible type declaration,
726  * such as "int4" or "integer" or "character varying(32)", parse
727  * the string and return the result as a TypeName.
728  * If the string cannot be parsed as a type, an error is raised.
729  */
730 TypeName *
typeStringToTypeName(const char * str)731 typeStringToTypeName(const char *str)
732 {
733 	List	   *raw_parsetree_list;
734 	TypeName   *typeName;
735 	ErrorContextCallback ptserrcontext;
736 
737 	/* make sure we give useful error for empty input */
738 	if (strspn(str, " \t\n\r\f") == strlen(str))
739 		goto fail;
740 
741 	/*
742 	 * Setup error traceback support in case of ereport() during parse
743 	 */
744 	ptserrcontext.callback = pts_error_callback;
745 	ptserrcontext.arg = unconstify(char *, str);
746 	ptserrcontext.previous = error_context_stack;
747 	error_context_stack = &ptserrcontext;
748 
749 	raw_parsetree_list = raw_parser(str, RAW_PARSE_TYPE_NAME);
750 
751 	error_context_stack = ptserrcontext.previous;
752 
753 	/* We should get back exactly one TypeName node. */
754 	Assert(list_length(raw_parsetree_list) == 1);
755 	typeName = linitial_node(TypeName, raw_parsetree_list);
756 
757 	/* The grammar allows SETOF in TypeName, but we don't want that here. */
758 	if (typeName->setof)
759 		goto fail;
760 
761 	return typeName;
762 
763 fail:
764 	ereport(ERROR,
765 			(errcode(ERRCODE_SYNTAX_ERROR),
766 			 errmsg("invalid type name \"%s\"", str)));
767 	return NULL;				/* keep compiler quiet */
768 }
769 
770 /*
771  * Given a string that is supposed to be a SQL-compatible type declaration,
772  * such as "int4" or "integer" or "character varying(32)", parse
773  * the string and convert it to a type OID and type modifier.
774  * If missing_ok is true, InvalidOid is returned rather than raising an error
775  * when the type name is not found.
776  */
777 void
parseTypeString(const char * str,Oid * typeid_p,int32 * typmod_p,bool missing_ok)778 parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok)
779 {
780 	TypeName   *typeName;
781 	Type		tup;
782 
783 	typeName = typeStringToTypeName(str);
784 
785 	tup = LookupTypeName(NULL, typeName, typmod_p, missing_ok);
786 	if (tup == NULL)
787 	{
788 		if (!missing_ok)
789 			ereport(ERROR,
790 					(errcode(ERRCODE_UNDEFINED_OBJECT),
791 					 errmsg("type \"%s\" does not exist",
792 							TypeNameToString(typeName)),
793 					 parser_errposition(NULL, typeName->location)));
794 		*typeid_p = InvalidOid;
795 	}
796 	else
797 	{
798 		Form_pg_type typ = (Form_pg_type) GETSTRUCT(tup);
799 
800 		if (!typ->typisdefined)
801 			ereport(ERROR,
802 					(errcode(ERRCODE_UNDEFINED_OBJECT),
803 					 errmsg("type \"%s\" is only a shell",
804 							TypeNameToString(typeName)),
805 					 parser_errposition(NULL, typeName->location)));
806 		*typeid_p = typ->oid;
807 		ReleaseSysCache(tup);
808 	}
809 }
810