partition-bound-collation-check.patch
application/octet-stream
Filename: partition-bound-collation-check.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/parser/parse_utilcmd.c | 30 | 44 |
| src/test/regress/expected/create_table.out | 6 | 0 |
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