diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 164312d..68a8a03 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -4172,6 +4172,7 @@ transformPartitionBoundValue(ParseState *pstate, Node *val, Oid partCollation) { Node *value; + Oid exprCollOid; /* Transform raw parsetree */ value = transformExpr(pstate, val, EXPR_KIND_PARTITION_BOUND); @@ -4184,50 +4185,6 @@ transformPartitionBoundValue(ParseState *pstate, Node *val, Assert(!contain_var_clause(value)); /* - * Check that the input expression's collation is compatible with one - * specified for the parent's partition key (partcollation). Don't throw - * an error if it's the default collation which we'll replace with the - * parent's collation anyway. - */ - if (IsA(value, CollateExpr)) - { - Oid exprCollOid = exprCollation(value); - - /* - * Check we have a collation iff it is a collatable type. The only - * expected failures here are (1) COLLATE applied to a noncollatable - * type, or (2) partition bound expression had an unresolved - * collation. But we might as well code this to be a complete - * consistency check. - */ - if (type_is_collatable(colType)) - { - if (!OidIsValid(exprCollOid)) - ereport(ERROR, - (errcode(ERRCODE_INDETERMINATE_COLLATION), - errmsg("could not determine which collation to use for partition bound expression"), - errhint("Use the COLLATE clause to set the collation explicitly."))); - } - else - { - if (OidIsValid(exprCollOid)) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("collations are not supported by type %s", - format_type_be(colType)))); - } - - if (OidIsValid(exprCollOid) && - exprCollOid != DEFAULT_COLLATION_OID && - exprCollOid != partCollation) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("collation of partition bound value for column \"%s\" does not match partition key collation \"%s\"", - colName, get_collation_name(partCollation)), - parser_errposition(pstate, exprLocation(value)))); - } - - /* * Coerce to the correct type. This might cause an explicit coercion step * to be added on top of the expression, which must be evaluated before * returning the result to the caller. @@ -4247,6 +4204,35 @@ transformPartitionBoundValue(ParseState *pstate, Node *val, format_type_be(colType), colName), parser_errposition(pstate, exprLocation(val)))); + /* Fix up collation information */ + assign_expr_collations(pstate, value); + + /* + * Check that the input expression's assigned collation is compatible with + * one specified for the parent's partition key (partcollation). Don't + * throw an error if it's the default collation which we'll replace with + * the parent's collation anyway. + */ + exprCollOid = exprCollation(value); + + /* Complain if COLLATE seems to be applied to an uncollatable type. */ + if (!type_is_collatable(colType) && OidIsValid(exprCollOid)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("collations are not supported by type %s", + format_type_be(colType)))); + + if (OidIsValid(exprCollOid) && + exprCollOid != DEFAULT_COLLATION_OID && + exprCollOid != partCollation) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("collation of partition bound value for column \"%s\" does not match partition key collation \"%s\"", + colName, get_collation_name(partCollation)), + parser_errposition(pstate, exprLocation(value)), + errdetail("The collation of partition bound value is \"%s\".", + get_collation_name(exprCollOid)))); + /* * Evaluate the expression, if needed, assigning the partition key's data * type and collation to the resulting Const node. diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index 41dce69..ec900ac 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -1034,6 +1034,7 @@ create table test_part_coll partition of test_part_coll_posix for values from (' ERROR: collation of partition bound value for column "a" does not match partition key collation "POSIX" LINE 1: ...artition of test_part_coll_posix for values from ('a' collat... ^ +DETAIL: The collation of partition bound value is "C". -- ok create table test_part_coll partition of test_part_coll_posix for values from ('a' collate "POSIX") to ('g'); -- ok @@ -1044,10 +1045,15 @@ create table test_part_coll_cast partition of test_part_coll_posix for values fr ERROR: collation of partition bound value for column "a" does not match partition key collation "POSIX" LINE 1: ...ion of test_part_coll_posix for values from (name 'm' collat... ^ +DETAIL: The collation of partition bound value is "C". -- ok create table test_part_coll_cast partition of test_part_coll_posix for values from (name 'm' collate "POSIX") to ('s'); -- ok; partition collation silently overrides the default collation of type 'name' create table test_part_coll_cast2 partition of test_part_coll_posix for values from (name 's') to ('z'); +ERROR: collation of partition bound value for column "a" does not match partition key collation "POSIX" +LINE 1: ...ion of test_part_coll_posix for values from (name 's') to ('... + ^ +DETAIL: The collation of partition bound value is "C". drop table test_part_coll_posix; -- Partition bound in describe output \d+ part_b