Print out error position for CREATE DOMAIN

This is simply done by pushing down the ParseState available in
ProcessUtility() to DefineDomain(), giving more information about the
position of an error when running a CREATE DOMAIN query.

Most of the queries impacted by this change have been added previously
in 0172b4c944.

Author: Kirill Reshke, Jian He
Reviewed-by: Álvaro Herrera, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/CALdSSPhqfvKbDwqJaY=yEePi_aq61GmMpW88i6ZH7CMG_2Z4Cg@mail.gmail.com
This commit is contained in:
Michael Paquier 2024-12-16 14:52:11 +09:00
parent 3ad8b840ce
commit 39240bcad5
8 changed files with 70 additions and 26 deletions

View File

@ -694,7 +694,7 @@ RemoveTypeById(Oid typeOid)
* Registers a new domain.
*/
ObjectAddress
DefineDomain(CreateDomainStmt *stmt)
DefineDomain(ParseState *pstate, CreateDomainStmt *stmt)
{
char *domainName;
char *domainArrayName;
@ -761,7 +761,7 @@ DefineDomain(CreateDomainStmt *stmt)
/*
* Look up the base type.
*/
typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
typeTup = typenameType(pstate, stmt->typeName, &basetypeMod);
baseType = (Form_pg_type) GETSTRUCT(typeTup);
basetypeoid = baseType->oid;
@ -783,7 +783,8 @@ DefineDomain(CreateDomainStmt *stmt)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("\"%s\" is not a valid base type for a domain",
TypeNameToString(stmt->typeName))));
TypeNameToString(stmt->typeName)),
parser_errposition(pstate, stmt->typeName->location)));
aclresult = object_aclcheck(TypeRelationId, basetypeoid, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
@ -809,7 +810,8 @@ DefineDomain(CreateDomainStmt *stmt)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("collations are not supported by type %s",
format_type_be(basetypeoid))));
format_type_be(basetypeoid)),
parser_errposition(pstate, stmt->typeName->location)));
/* passed by value */
byValue = baseType->typbyval;
@ -879,18 +881,15 @@ DefineDomain(CreateDomainStmt *stmt)
*/
if (saw_default)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple default expressions")));
errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple default expressions"),
parser_errposition(pstate, constr->location));
saw_default = true;
if (constr->raw_expr)
{
ParseState *pstate;
Node *defaultExpr;
/* Create a dummy ParseState for transformExpr */
pstate = make_parsestate(NULL);
/*
* Cook the constr->raw_expr into an expression. Note:
* name is strictly for error message
@ -942,12 +941,14 @@ DefineDomain(CreateDomainStmt *stmt)
case CONSTR_NOTNULL:
if (nullDefined && !typNotNull)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NULL/NOT NULL constraints")));
errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NULL/NOT NULL constraints"),
parser_errposition(pstate, constr->location));
if (constr->is_no_inherit)
ereport(ERROR,
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("not-null constraints for domains cannot be marked NO INHERIT"));
errmsg("not-null constraints for domains cannot be marked NO INHERIT"),
parser_errposition(pstate, constr->location));
typNotNull = true;
nullDefined = true;
break;
@ -955,8 +956,9 @@ DefineDomain(CreateDomainStmt *stmt)
case CONSTR_NULL:
if (nullDefined && typNotNull)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NULL/NOT NULL constraints")));
errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NULL/NOT NULL constraints"),
parser_errposition(pstate, constr->location));
typNotNull = false;
nullDefined = true;
break;
@ -971,8 +973,10 @@ DefineDomain(CreateDomainStmt *stmt)
*/
if (constr->is_no_inherit)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("check constraints for domains cannot be marked NO INHERIT")));
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("check constraints for domains cannot be marked NO INHERIT"),
parser_errposition(pstate, constr->location));
break;
/*
@ -980,26 +984,30 @@ DefineDomain(CreateDomainStmt *stmt)
*/
case CONSTR_UNIQUE:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("unique constraints not possible for domains")));
errcode(ERRCODE_SYNTAX_ERROR),
errmsg("unique constraints not possible for domains"),
parser_errposition(pstate, constr->location));
break;
case CONSTR_PRIMARY:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("primary key constraints not possible for domains")));
errmsg("primary key constraints not possible for domains"),
parser_errposition(pstate, constr->location)));
break;
case CONSTR_EXCLUSION:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("exclusion constraints not possible for domains")));
errmsg("exclusion constraints not possible for domains"),
parser_errposition(pstate, constr->location)));
break;
case CONSTR_FOREIGN:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("foreign key constraints not possible for domains")));
errmsg("foreign key constraints not possible for domains"),
parser_errposition(pstate, constr->location)));
break;
case CONSTR_ATTR_DEFERRABLE:
@ -1008,14 +1016,16 @@ DefineDomain(CreateDomainStmt *stmt)
case CONSTR_ATTR_IMMEDIATE:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("specifying constraint deferrability not supported for domains")));
errmsg("specifying constraint deferrability not supported for domains"),
parser_errposition(pstate, constr->location)));
break;
case CONSTR_GENERATED:
case CONSTR_IDENTITY:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("specifying GENERATED not supported for domains")));
errmsg("specifying GENERATED not supported for domains"),
parser_errposition(pstate, constr->location)));
break;
/* no default, to let compiler warn about missing case */

View File

@ -1712,7 +1712,7 @@ ProcessUtilitySlow(ParseState *pstate,
break;
case T_CreateDomainStmt:
address = DefineDomain((CreateDomainStmt *) parsetree);
address = DefineDomain(pstate, (CreateDomainStmt *) parsetree);
break;
case T_CreateConversionStmt:

View File

@ -23,7 +23,7 @@
extern ObjectAddress DefineType(ParseState *pstate, List *names, List *parameters);
extern void RemoveTypeById(Oid typeOid);
extern ObjectAddress DefineDomain(CreateDomainStmt *stmt);
extern ObjectAddress DefineDomain(ParseState *pstate, CreateDomainStmt *stmt);
extern ObjectAddress DefineEnum(CreateEnumStmt *stmt);
extern ObjectAddress DefineRange(ParseState *pstate, CreateRangeStmt *stmt);
extern ObjectAddress AlterEnum(AlterEnumStmt *stmt);

View File

@ -120,6 +120,8 @@ LINE 1: ...* FROM collate_test1 WHERE b COLLATE "C" >= 'bbc' COLLATE "e...
CREATE DOMAIN testdomain_sv AS text COLLATE "sv-x-icu";
CREATE DOMAIN testdomain_i AS int COLLATE "sv-x-icu"; -- fails
ERROR: collations are not supported by type integer
LINE 1: CREATE DOMAIN testdomain_i AS int COLLATE "sv-x-icu";
^
CREATE TABLE collate_test4 (
a int,
b testdomain_sv

View File

@ -122,6 +122,8 @@ LINE 1: ...* FROM collate_test1 WHERE b COLLATE "C" >= 'bbc' COLLATE "e...
CREATE DOMAIN testdomain_sv AS text COLLATE "sv_SE";
CREATE DOMAIN testdomain_i AS int COLLATE "sv_SE"; -- fails
ERROR: collations are not supported by type integer
LINE 1: CREATE DOMAIN testdomain_i AS int COLLATE "sv_SE";
^
CREATE TABLE collate_test4 (
a int,
b testdomain_sv

View File

@ -73,6 +73,8 @@ LINE 1: ...* FROM collate_test1 WHERE b COLLATE "C" >= 'bbc' COLLATE "P...
CREATE DOMAIN testdomain_p AS text COLLATE "POSIX";
CREATE DOMAIN testdomain_i AS int COLLATE "POSIX"; -- fail
ERROR: collations are not supported by type integer
LINE 1: CREATE DOMAIN testdomain_i AS int COLLATE "POSIX";
^
CREATE TABLE collate_test4 (
a int,
b testdomain_p

View File

@ -124,6 +124,8 @@ LINE 1: ...* FROM collate_test1 WHERE b COLLATE "C" >= 'bbc' COLLATE "e...
CREATE DOMAIN testdomain_sv AS text COLLATE "sv_SE";
CREATE DOMAIN testdomain_i AS int COLLATE "sv_SE"; -- fails
ERROR: collations are not supported by type integer
LINE 1: CREATE DOMAIN testdomain_i AS int COLLATE "sv_SE";
^
CREATE TABLE collate_test4 (
a int,
b testdomain_sv

View File

@ -18,30 +18,56 @@ ERROR: type "domaindroptest" does not exist
-- some error cases
create domain d_fail as no_such_type;
ERROR: type "no_such_type" does not exist
LINE 1: create domain d_fail as no_such_type;
^
create domain d_fail as int constraint cc REFERENCES this_table_not_exists(i);
ERROR: foreign key constraints not possible for domains
LINE 1: create domain d_fail as int constraint cc REFERENCES this_ta...
^
create domain d_fail as int4 not null no inherit;
ERROR: not-null constraints for domains cannot be marked NO INHERIT
LINE 1: create domain d_fail as int4 not null no inherit;
^
create domain d_fail as int4 not null null;
ERROR: conflicting NULL/NOT NULL constraints
LINE 1: create domain d_fail as int4 not null null;
^
create domain d_fail as int4 not null default 3 default 3;
ERROR: multiple default expressions
LINE 1: create domain d_fail as int4 not null default 3 default 3;
^
create domain d_fail int4 DEFAULT 3 + 'h';
ERROR: invalid input syntax for type integer: "h"
LINE 1: create domain d_fail int4 DEFAULT 3 + 'h';
^
create domain d_fail int4 collate "C";
ERROR: collations are not supported by type integer
LINE 1: create domain d_fail int4 collate "C";
^
create domain d_fail as anyelement;
ERROR: "anyelement" is not a valid base type for a domain
LINE 1: create domain d_fail as anyelement;
^
create domain d_fail as int4 unique;
ERROR: unique constraints not possible for domains
LINE 1: create domain d_fail as int4 unique;
^
create domain d_fail as int4 PRIMARY key;
ERROR: primary key constraints not possible for domains
LINE 1: create domain d_fail as int4 PRIMARY key;
^
create domain d_fail as int4 constraint cc generated by default as identity;
ERROR: specifying GENERATED not supported for domains
LINE 1: create domain d_fail as int4 constraint cc generated by defa...
^
create domain d_fail as int4 constraint cc check (values > 1) no inherit;
ERROR: check constraints for domains cannot be marked NO INHERIT
LINE 1: create domain d_fail as int4 constraint cc check (values > 1...
^
create domain d_fail as int4 constraint cc check (values > 1) deferrable;
ERROR: specifying constraint deferrability not supported for domains
LINE 1: ...n d_fail as int4 constraint cc check (values > 1) deferrable...
^
-- Test domain input.
-- Note: the point of checking both INSERT and COPY FROM is that INSERT
-- exercises CoerceToDomain while COPY exercises domain_in.