1 /*-------------------------------------------------------------------------
4 * handle type operations for parser
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/parser/parse_type.c
13 *-------------------------------------------------------------------------
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"
29 static int32
typenameTypeMod(ParseState
*pstate
, const TypeName
*typeName
,
35 * Wrapper for typical case.
38 LookupTypeName(ParseState
*pstate
, const TypeName
*typeName
,
39 int32
*typmod_p
, bool missing_ok
)
41 return LookupTypeNameExtended(pstate
,
42 typeName
, typmod_p
, true, missing_ok
);
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.
52 * NB: on success, the caller must ReleaseSysCache the type tuple when done
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.
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.
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.
70 * pstate is only used for error location info, and may be NULL.
73 LookupTypeNameExtended(ParseState
*pstate
,
74 const TypeName
*typeName
, int32
*typmod_p
,
75 bool temp_ok
, bool missing_ok
)
81 if (typeName
->names
== NIL
)
83 /* We have the OID already if it's an internally generated TypeName */
84 typoid
= typeName
->typeOid
;
86 else if (typeName
->pct_type
)
88 /* Handle %TYPE reference to type of an existing field */
89 RangeVar
*rel
= makeRangeVar(NULL
, NULL
, typeName
->location
);
94 /* deconstruct the name list */
95 switch (list_length(typeName
->names
))
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
)));
105 rel
->relname
= strVal(linitial(typeName
->names
));
106 field
= strVal(lsecond(typeName
->names
));
109 rel
->schemaname
= strVal(linitial(typeName
->names
));
110 rel
->relname
= strVal(lsecond(typeName
->names
));
111 field
= strVal(lthird(typeName
->names
));
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
));
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
)));
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.
135 relid
= RangeVarGetRelid(rel
, NoLock
, missing_ok
);
136 attnum
= get_attnum(relid
, field
);
137 if (attnum
== InvalidAttrNumber
)
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
)));
150 typoid
= get_atttype(relid
, attnum
);
152 /* this construct should never have an array indicator */
153 Assert(typeName
->arrayBounds
== NIL
);
155 /* emit nuisance notice (intentionally not errposition'd) */
157 (errmsg("type reference %s converted to %s",
158 TypeNameToString(typeName
),
159 format_type_be(typoid
))));
164 /* Normal reference to a type name */
168 /* deconstruct the name list */
169 DeconstructQualifiedName(typeName
->names
, &schemaname
, &typname
);
173 /* Look in specific schema only */
175 ParseCallbackState pcbstate
;
177 setup_parser_errposition_callback(&pcbstate
, pstate
, typeName
->location
);
179 namespaceId
= LookupExplicitNamespace(schemaname
, missing_ok
);
180 if (OidIsValid(namespaceId
))
181 typoid
= GetSysCacheOid2(TYPENAMENSP
, Anum_pg_type_oid
,
182 PointerGetDatum(typname
),
183 ObjectIdGetDatum(namespaceId
));
187 cancel_parser_errposition_callback(&pcbstate
);
191 /* Unqualified type name, so search the search path */
192 typoid
= TypenameGetTypidExtended(typname
, temp_ok
);
195 /* If an array reference, return the array type instead */
196 if (typeName
->arrayBounds
!= NIL
)
197 typoid
= get_array_type(typoid
);
200 if (!OidIsValid(typoid
))
207 tup
= SearchSysCache1(TYPEOID
, ObjectIdGetDatum(typoid
));
208 if (!HeapTupleIsValid(tup
)) /* should not happen */
209 elog(ERROR
, "cache lookup failed for type %u", typoid
);
211 typmod
= typenameTypeMod(pstate
, typeName
, (Type
) tup
);
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,
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.
229 * pstate is only used for error location info, and may be NULL.
232 LookupTypeNameOid(ParseState
*pstate
, const TypeName
*typeName
, bool missing_ok
)
237 tup
= LookupTypeName(pstate
, typeName
, NULL
, missing_ok
);
242 (errcode(ERRCODE_UNDEFINED_OBJECT
),
243 errmsg("type \"%s\" does not exist",
244 TypeNameToString(typeName
)),
245 parser_errposition(pstate
, typeName
->location
)));
250 typoid
= ((Form_pg_type
) GETSTRUCT(tup
))->oid
;
251 ReleaseSysCache(tup
);
257 * typenameType - given a TypeName, return a Type structure and typmod
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.
264 typenameType(ParseState
*pstate
, const TypeName
*typeName
, int32
*typmod_p
)
268 tup
= LookupTypeName(pstate
, typeName
, typmod_p
, false);
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
)
277 (errcode(ERRCODE_UNDEFINED_OBJECT
),
278 errmsg("type \"%s\" is only a shell",
279 TypeNameToString(typeName
)),
280 parser_errposition(pstate
, typeName
->location
)));
285 * typenameTypeId - given a TypeName, return the type's OID
287 * This is similar to typenameType, but we only hand back the type OID
288 * not the syscache entry.
291 typenameTypeId(ParseState
*pstate
, const TypeName
*typeName
)
296 tup
= typenameType(pstate
, typeName
, NULL
);
297 typoid
= ((Form_pg_type
) GETSTRUCT(tup
))->oid
;
298 ReleaseSysCache(tup
);
304 * typenameTypeIdAndMod - given a TypeName, return the type's OID and typmod
306 * This is equivalent to typenameType, but we only hand back the type OID
307 * and typmod, not the syscache entry.
310 typenameTypeIdAndMod(ParseState
*pstate
, const TypeName
*typeName
,
311 Oid
*typeid_p
, int32
*typmod_p
)
315 tup
= typenameType(pstate
, typeName
, typmod_p
);
316 *typeid_p
= ((Form_pg_type
) GETSTRUCT(tup
))->oid
;
317 ReleaseSysCache(tup
);
321 * typenameTypeMod - given a TypeName, return the internal typmod value
323 * This will throw an error if the TypeName includes type modifiers that are
324 * illegal for the data type.
326 * The actual type OID represented by the TypeName must already have been
327 * looked up, and is passed as "typ".
329 * pstate is only used for error location info, and may be NULL.
332 typenameTypeMod(ParseState
*pstate
, const TypeName
*typeName
, Type typ
)
339 ArrayType
*arrtypmod
;
340 ParseCallbackState pcbstate
;
342 /* Return prespecified typmod if no typmod expressions */
343 if (typeName
->typmods
== NIL
)
344 return typeName
->typemod
;
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
351 if (!((Form_pg_type
) GETSTRUCT(typ
))->typisdefined
)
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
)));
358 typmodin
= ((Form_pg_type
) GETSTRUCT(typ
))->typmodin
;
360 if (typmodin
== InvalidOid
)
362 (errcode(ERRCODE_SYNTAX_ERROR
),
363 errmsg("type modifier is not allowed for type \"%s\"",
364 TypeNameToString(typeName
)),
365 parser_errposition(pstate
, typeName
->location
)));
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.
372 datums
= (Datum
*) palloc(list_length(typeName
->typmods
) * sizeof(Datum
));
374 foreach(l
, typeName
->typmods
)
376 Node
*tm
= (Node
*) lfirst(l
);
379 if (IsA(tm
, A_Const
))
381 A_Const
*ac
= (A_Const
*) tm
;
383 if (IsA(&ac
->val
, Integer
))
385 cstr
= psprintf("%ld", (long) intVal(&ac
->val
));
387 else if (IsA(&ac
->val
, Float
))
389 /* we can just use the string representation directly. */
390 cstr
= ac
->val
.fval
.fval
;
392 else if (IsA(&ac
->val
, String
))
394 /* we can just use the string representation directly. */
395 cstr
= strVal(&ac
->val
);
398 else if (IsA(tm
, ColumnRef
))
400 ColumnRef
*cr
= (ColumnRef
*) tm
;
402 if (list_length(cr
->fields
) == 1 &&
403 IsA(linitial(cr
->fields
), String
))
404 cstr
= strVal(linitial(cr
->fields
));
408 (errcode(ERRCODE_SYNTAX_ERROR
),
409 errmsg("type modifiers must be simple constants or identifiers"),
410 parser_errposition(pstate
, typeName
->location
)));
411 datums
[n
++] = CStringGetDatum(cstr
);
414 arrtypmod
= construct_array_builtin(datums
, n
, CSTRINGOID
);
416 /* arrange to report location if type's typmodin function fails */
417 setup_parser_errposition_callback(&pcbstate
, pstate
, typeName
->location
);
419 result
= DatumGetInt32(OidFunctionCall1(typmodin
,
420 PointerGetDatum(arrtypmod
)));
422 cancel_parser_errposition_callback(&pcbstate
);
431 * appendTypeNameToBuffer
432 * Append a string representing the name of a TypeName to a StringInfo.
433 * This is the shared guts of TypeNameToString and TypeNameListToString.
435 * NB: this must work on TypeNames that do not describe any actual type;
436 * it is mostly used for reporting lookup errors.
439 appendTypeNameToBuffer(const TypeName
*typeName
, StringInfo string
)
441 if (typeName
->names
!= NIL
)
443 /* Emit possibly-qualified name as-is */
446 foreach(l
, typeName
->names
)
448 if (l
!= list_head(typeName
->names
))
449 appendStringInfoChar(string
, '.');
450 appendStringInfoString(string
, strVal(lfirst(l
)));
455 /* Look up internally-specified type */
456 appendStringInfoString(string
, format_type_be(typeName
->typeOid
));
460 * Add decoration as needed, but only for fields considered by
463 if (typeName
->pct_type
)
464 appendStringInfoString(string
, "%TYPE");
466 if (typeName
->arrayBounds
!= NIL
)
467 appendStringInfoString(string
, "[]");
472 * Produce a string representing the name of a TypeName.
474 * NB: this must work on TypeNames that do not describe any actual type;
475 * it is mostly used for reporting lookup errors.
478 TypeNameToString(const TypeName
*typeName
)
480 StringInfoData string
;
482 initStringInfo(&string
);
483 appendTypeNameToBuffer(typeName
, &string
);
488 * TypeNameListToString
489 * Produce a string representing the name(s) of a List of TypeNames
492 TypeNameListToString(List
*typenames
)
494 StringInfoData string
;
497 initStringInfo(&string
);
498 foreach(l
, typenames
)
500 TypeName
*typeName
= lfirst_node(TypeName
, l
);
502 if (l
!= list_head(typenames
))
503 appendStringInfoChar(&string
, ',');
504 appendTypeNameToBuffer(typeName
, &string
);
512 * Look up collation by name, return OID, with support for error location.
515 LookupCollation(ParseState
*pstate
, List
*collnames
, int location
)
518 ParseCallbackState pcbstate
;
521 setup_parser_errposition_callback(&pcbstate
, pstate
, location
);
523 colloid
= get_collation_oid(collnames
, false);
526 cancel_parser_errposition_callback(&pcbstate
);
532 * GetColumnDefCollation
534 * Get the collation to be used for a column being defined, given the
535 * ColumnDef node and the previously-determined column type OID.
537 * pstate is only used for error location purposes, and can be NULL.
540 GetColumnDefCollation(ParseState
*pstate
, const ColumnDef
*coldef
, Oid typeOid
)
543 Oid typcollation
= get_typcollation(typeOid
);
544 int location
= coldef
->location
;
546 if (coldef
->collClause
)
548 /* We have a raw COLLATE clause, so look up the collation */
549 location
= coldef
->collClause
->location
;
550 result
= LookupCollation(pstate
, coldef
->collClause
->collname
,
553 else if (OidIsValid(coldef
->collOid
))
555 /* Precooked collation spec, use that */
556 result
= coldef
->collOid
;
560 /* Use the type's default collation if any */
561 result
= typcollation
;
564 /* Complain if COLLATE is applied to an uncollatable type */
565 if (OidIsValid(result
) && !OidIsValid(typcollation
))
567 (errcode(ERRCODE_DATATYPE_MISMATCH
),
568 errmsg("collations are not supported by type %s",
569 format_type_be(typeOid
)),
570 parser_errposition(pstate
, location
)));
575 /* return a Type structure, given a type id */
576 /* NB: caller must ReleaseSysCache the type tuple when done with it */
582 tup
= SearchSysCache1(TYPEOID
, ObjectIdGetDatum(id
));
583 if (!HeapTupleIsValid(tup
))
584 elog(ERROR
, "cache lookup failed for type %u", id
);
588 /* given type (as type struct), return the type OID */
592 if (tp
== NULL
) /* probably useless */
593 elog(ERROR
, "typeTypeId() called with NULL type struct");
594 return ((Form_pg_type
) GETSTRUCT(tp
))->oid
;
597 /* given type (as type struct), return the length of type */
603 typ
= (Form_pg_type
) GETSTRUCT(t
);
607 /* given type (as type struct), return its 'byval' attribute */
613 typ
= (Form_pg_type
) GETSTRUCT(t
);
614 return typ
->typbyval
;
617 /* given type (as type struct), return the type's name */
623 typ
= (Form_pg_type
) GETSTRUCT(t
);
624 /* pstrdup here because result may need to outlive the syscache entry */
625 return pstrdup(NameStr(typ
->typname
));
628 /* given type (as type struct), return its 'typrelid' attribute */
630 typeTypeRelid(Type typ
)
634 typtup
= (Form_pg_type
) GETSTRUCT(typ
);
635 return typtup
->typrelid
;
638 /* given type (as type struct), return its 'typcollation' attribute */
640 typeTypeCollation(Type typ
)
644 typtup
= (Form_pg_type
) GETSTRUCT(typ
);
645 return typtup
->typcollation
;
649 * Given a type structure and a string, returns the internal representation
650 * of that string. The "string" can be NULL to perform conversion of a NULL
651 * (which might result in failure, if the input function rejects NULLs).
654 stringTypeDatum(Type tp
, char *string
, int32 atttypmod
)
656 Form_pg_type typform
= (Form_pg_type
) GETSTRUCT(tp
);
657 Oid typinput
= typform
->typinput
;
658 Oid typioparam
= getTypeIOParam(tp
);
660 return OidInputFunctionCall(typinput
, string
, typioparam
, atttypmod
);
664 * Given a typeid, return the type's typrelid (associated relation), if any.
665 * Returns InvalidOid if type is not a composite type.
668 typeidTypeRelid(Oid type_id
)
674 typeTuple
= SearchSysCache1(TYPEOID
, ObjectIdGetDatum(type_id
));
675 if (!HeapTupleIsValid(typeTuple
))
676 elog(ERROR
, "cache lookup failed for type %u", type_id
);
677 type
= (Form_pg_type
) GETSTRUCT(typeTuple
);
678 result
= type
->typrelid
;
679 ReleaseSysCache(typeTuple
);
684 * Given a typeid, return the type's typrelid (associated relation), if any.
685 * Returns InvalidOid if type is not a composite type or a domain over one.
686 * This is the same as typeidTypeRelid(getBaseType(type_id)), but faster.
689 typeOrDomainTypeRelid(Oid type_id
)
697 typeTuple
= SearchSysCache1(TYPEOID
, ObjectIdGetDatum(type_id
));
698 if (!HeapTupleIsValid(typeTuple
))
699 elog(ERROR
, "cache lookup failed for type %u", type_id
);
700 type
= (Form_pg_type
) GETSTRUCT(typeTuple
);
701 if (type
->typtype
!= TYPTYPE_DOMAIN
)
703 /* Not a domain, so done looking through domains */
706 /* It is a domain, so examine the base type instead */
707 type_id
= type
->typbasetype
;
708 ReleaseSysCache(typeTuple
);
710 result
= type
->typrelid
;
711 ReleaseSysCache(typeTuple
);
716 * error context callback for parse failure during parseTypeString()
719 pts_error_callback(void *arg
)
721 const char *str
= (const char *) arg
;
723 errcontext("invalid type name \"%s\"", str
);
727 * Given a string that is supposed to be a SQL-compatible type declaration,
728 * such as "int4" or "integer" or "character varying(32)", parse
729 * the string and return the result as a TypeName.
731 * If the string cannot be parsed as a type, an error is raised,
732 * unless escontext is an ErrorSaveContext node, in which case we may
733 * fill that and return NULL. But note that the ErrorSaveContext option
734 * is mostly aspirational at present: errors detected by the main
735 * grammar, rather than here, will still be thrown.
738 typeStringToTypeName(const char *str
, Node
*escontext
)
740 List
*raw_parsetree_list
;
742 ErrorContextCallback ptserrcontext
;
744 /* make sure we give useful error for empty input */
745 if (strspn(str
, " \t\n\r\f\v") == strlen(str
))
749 * Setup error traceback support in case of ereport() during parse
751 ptserrcontext
.callback
= pts_error_callback
;
752 ptserrcontext
.arg
= unconstify(char *, str
);
753 ptserrcontext
.previous
= error_context_stack
;
754 error_context_stack
= &ptserrcontext
;
756 raw_parsetree_list
= raw_parser(str
, RAW_PARSE_TYPE_NAME
);
758 error_context_stack
= ptserrcontext
.previous
;
760 /* We should get back exactly one TypeName node. */
761 Assert(list_length(raw_parsetree_list
) == 1);
762 typeName
= linitial_node(TypeName
, raw_parsetree_list
);
764 /* The grammar allows SETOF in TypeName, but we don't want that here. */
771 ereturn(escontext
, NULL
,
772 (errcode(ERRCODE_SYNTAX_ERROR
),
773 errmsg("invalid type name \"%s\"", str
)));
777 * Given a string that is supposed to be a SQL-compatible type declaration,
778 * such as "int4" or "integer" or "character varying(32)", parse
779 * the string and convert it to a type OID and type modifier.
781 * If escontext is an ErrorSaveContext node, then errors are reported by
782 * filling escontext and returning false, instead of throwing them.
785 parseTypeString(const char *str
, Oid
*typeid_p
, int32
*typmod_p
,
791 typeName
= typeStringToTypeName(str
, escontext
);
792 if (typeName
== NULL
)
795 tup
= LookupTypeName(NULL
, typeName
, typmod_p
,
796 (escontext
&& IsA(escontext
, ErrorSaveContext
)));
799 ereturn(escontext
, false,
800 (errcode(ERRCODE_UNDEFINED_OBJECT
),
801 errmsg("type \"%s\" does not exist",
802 TypeNameToString(typeName
))));
806 Form_pg_type typ
= (Form_pg_type
) GETSTRUCT(tup
);
808 if (!typ
->typisdefined
)
810 ReleaseSysCache(tup
);
811 ereturn(escontext
, false,
812 (errcode(ERRCODE_UNDEFINED_OBJECT
),
813 errmsg("type \"%s\" is only a shell",
814 TypeNameToString(typeName
))));
816 *typeid_p
= typ
->oid
;
817 ReleaseSysCache(tup
);