Avoid updating inactive_since for invalid replication slots.
[pgsql.git] / src / backend / parser / parse_type.c
blob7713bdc6af0a977407167c6f10fa6ac424112c99
1 /*-------------------------------------------------------------------------
3 * parse_type.c
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
10 * IDENTIFICATION
11 * src/backend/parser/parse_type.c
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
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,
30 Type typ);
34 * LookupTypeName
35 * Wrapper for typical case.
37 Type
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
53 * with it.
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.
72 Type
73 LookupTypeNameExtended(ParseState *pstate,
74 const TypeName *typeName, int32 *typmod_p,
75 bool temp_ok, bool missing_ok)
77 Oid typoid;
78 HeapTuple tup;
79 int32 typmod;
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);
90 char *field = NULL;
91 Oid relid;
92 AttrNumber attnum;
94 /* deconstruct the name list */
95 switch (list_length(typeName->names))
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;
129 * Look up the field.
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)
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)));
148 else
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) */
156 ereport(NOTICE,
157 (errmsg("type reference %s converted to %s",
158 TypeNameToString(typeName),
159 format_type_be(typoid))));
162 else
164 /* Normal reference to a type name */
165 char *schemaname;
166 char *typname;
168 /* deconstruct the name list */
169 DeconstructQualifiedName(typeName->names, &schemaname, &typname);
171 if (schemaname)
173 /* Look in specific schema only */
174 Oid namespaceId;
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));
184 else
185 typoid = InvalidOid;
187 cancel_parser_errposition_callback(&pcbstate);
189 else
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))
202 if (typmod_p)
203 *typmod_p = -1;
204 return NULL;
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);
213 if (typmod_p)
214 *typmod_p = typmod;
216 return (Type) tup;
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.
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)
234 Oid typoid;
235 Type tup;
237 tup = LookupTypeName(pstate, typeName, NULL, missing_ok);
238 if (tup == NULL)
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)));
247 return InvalidOid;
250 typoid = ((Form_pg_type) GETSTRUCT(tup))->oid;
251 ReleaseSysCache(tup);
253 return typoid;
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.
263 Type
264 typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
266 Type tup;
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;
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)
293 Oid typoid;
294 Type tup;
296 tup = typenameType(pstate, typeName, NULL);
297 typoid = ((Form_pg_type) GETSTRUCT(tup))->oid;
298 ReleaseSysCache(tup);
300 return typoid;
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.
309 void
310 typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
311 Oid *typeid_p, int32 *typmod_p)
313 Type tup;
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.
331 static int32
332 typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ)
334 int32 result;
335 Oid typmodin;
336 Datum *datums;
337 int n;
338 ListCell *l;
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
349 * typmodin function.
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)));
358 typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin;
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)));
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));
373 n = 0;
374 foreach(l, typeName->typmods)
376 Node *tm = (Node *) lfirst(l);
377 char *cstr = NULL;
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));
406 if (!cstr)
407 ereport(ERROR,
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);
424 pfree(datums);
425 pfree(arrtypmod);
427 return result;
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.
438 static void
439 appendTypeNameToBuffer(const TypeName *typeName, StringInfo string)
441 if (typeName->names != NIL)
443 /* Emit possibly-qualified name as-is */
444 ListCell *l;
446 foreach(l, typeName->names)
448 if (l != list_head(typeName->names))
449 appendStringInfoChar(string, '.');
450 appendStringInfoString(string, strVal(lfirst(l)));
453 else
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
461 * LookupTypeName
463 if (typeName->pct_type)
464 appendStringInfoString(string, "%TYPE");
466 if (typeName->arrayBounds != NIL)
467 appendStringInfoString(string, "[]");
471 * TypeNameToString
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.
477 char *
478 TypeNameToString(const TypeName *typeName)
480 StringInfoData string;
482 initStringInfo(&string);
483 appendTypeNameToBuffer(typeName, &string);
484 return string.data;
488 * TypeNameListToString
489 * Produce a string representing the name(s) of a List of TypeNames
491 char *
492 TypeNameListToString(List *typenames)
494 StringInfoData string;
495 ListCell *l;
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);
506 return string.data;
510 * LookupCollation
512 * Look up collation by name, return OID, with support for error location.
515 LookupCollation(ParseState *pstate, List *collnames, int location)
517 Oid colloid;
518 ParseCallbackState pcbstate;
520 if (pstate)
521 setup_parser_errposition_callback(&pcbstate, pstate, location);
523 colloid = get_collation_oid(collnames, false);
525 if (pstate)
526 cancel_parser_errposition_callback(&pcbstate);
528 return colloid;
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)
542 Oid result;
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,
551 location);
553 else if (OidIsValid(coldef->collOid))
555 /* Precooked collation spec, use that */
556 result = coldef->collOid;
558 else
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))
566 ereport(ERROR,
567 (errcode(ERRCODE_DATATYPE_MISMATCH),
568 errmsg("collations are not supported by type %s",
569 format_type_be(typeOid)),
570 parser_errposition(pstate, location)));
572 return result;
575 /* return a Type structure, given a type id */
576 /* NB: caller must ReleaseSysCache the type tuple when done with it */
577 Type
578 typeidType(Oid id)
580 HeapTuple tup;
582 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(id));
583 if (!HeapTupleIsValid(tup))
584 elog(ERROR, "cache lookup failed for type %u", id);
585 return (Type) tup;
588 /* given type (as type struct), return the type OID */
590 typeTypeId(Type tp)
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 */
598 int16
599 typeLen(Type t)
601 Form_pg_type typ;
603 typ = (Form_pg_type) GETSTRUCT(t);
604 return typ->typlen;
607 /* given type (as type struct), return its 'byval' attribute */
608 bool
609 typeByVal(Type t)
611 Form_pg_type typ;
613 typ = (Form_pg_type) GETSTRUCT(t);
614 return typ->typbyval;
617 /* given type (as type struct), return the type's name */
618 char *
619 typeTypeName(Type t)
621 Form_pg_type typ;
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)
632 Form_pg_type typtup;
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)
642 Form_pg_type typtup;
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).
653 Datum
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)
670 HeapTuple typeTuple;
671 Form_pg_type type;
672 Oid result;
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);
680 return result;
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)
691 HeapTuple typeTuple;
692 Form_pg_type type;
693 Oid result;
695 for (;;)
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 */
704 break;
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);
712 return result;
716 * error context callback for parse failure during parseTypeString()
718 static void
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.
737 TypeName *
738 typeStringToTypeName(const char *str, Node *escontext)
740 List *raw_parsetree_list;
741 TypeName *typeName;
742 ErrorContextCallback ptserrcontext;
744 /* make sure we give useful error for empty input */
745 if (strspn(str, " \t\n\r\f\v") == strlen(str))
746 goto fail;
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. */
765 if (typeName->setof)
766 goto fail;
768 return typeName;
770 fail:
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.
784 bool
785 parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
786 Node *escontext)
788 TypeName *typeName;
789 Type tup;
791 typeName = typeStringToTypeName(str, escontext);
792 if (typeName == NULL)
793 return false;
795 tup = LookupTypeName(NULL, typeName, typmod_p,
796 (escontext && IsA(escontext, ErrorSaveContext)));
797 if (tup == NULL)
799 ereturn(escontext, false,
800 (errcode(ERRCODE_UNDEFINED_OBJECT),
801 errmsg("type \"%s\" does not exist",
802 TypeNameToString(typeName))));
804 else
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);
820 return true;