diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index f7d49ab5115..7b4ba112c48 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -242,7 +242,7 @@ static bool QueryTreeHasImproperForDeparseNodes(Node *inputNode, void *context); static Node * AdjustImproperForDeparseNodes(Node *inputNode, void *context); static bool IsImproperForDeparseRelabelTypeNode(Node *inputNode); static bool IsImproperForDeparseCoerceViaIONode(Node *inputNode); -static CollateExpr * RelabelTypeToCollateExpr(RelabelType *relabelType); +static Node * RelabelTypeToCollateExpr(RelabelType *relabelType); /* @@ -2878,7 +2878,7 @@ SqlTaskList(Job *job) * RelabelTypeToCollateExpr converts RelabelType's into CollationExpr's. * With that, we will be able to pushdown COLLATE's. */ -static CollateExpr * +static Node * RelabelTypeToCollateExpr(RelabelType *relabelType) { Assert(OidIsValid(relabelType->resultcollid)); @@ -2888,7 +2888,21 @@ RelabelTypeToCollateExpr(RelabelType *relabelType) collateExpr->collOid = relabelType->resultcollid; collateExpr->location = relabelType->location; - return collateExpr; + Oid argType = exprType((Node *) relabelType->arg); + if (relabelType->resulttype != argType) + { + RelabelType *castRelabel = makeNode(RelabelType); + castRelabel->arg = (Expr *) collateExpr; + castRelabel->resulttype = relabelType->resulttype; + castRelabel->resulttypmod = relabelType->resulttypmod; + castRelabel->resultcollid = DEFAULT_COLLATION_OID; + castRelabel->relabelformat = relabelType->relabelformat; + castRelabel->location = relabelType->location; + + return (Node *) castRelabel; + } + + return (Node *) collateExpr; } diff --git a/src/test/regress/expected/distributed_collations.out b/src/test/regress/expected/distributed_collations.out index 5e7247b0a23..85d522028b5 100644 --- a/src/test/regress/expected/distributed_collations.out +++ b/src/test/regress/expected/distributed_collations.out @@ -85,6 +85,35 @@ DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx (1 row) RESET citus.log_remote_commands; +-- Test COLLATE with type cast does not cause type mismatch (issue #8469) +-- When a GROUP BY expression uses both ::VARCHAR and COLLATE, the type cast +-- must be preserved in the query sent to workers. +SET citus.next_shard_id TO 20070000; +CREATE TABLE test_collate_cast (c0 inet, c1 inet); +SELECT create_distributed_table('test_collate_cast', 'c0'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO test_collate_cast(c1, c0) VALUES + ('144.150.228.243', '230.194.119.117'), + ('22.171.214.19', '138.53.199.60'), + ('14.25.58.22', '103.167.89.59'); +-- This used to fail with: "attribute 2 of type record has wrong type" +-- "Table has type text, but query expects character varying" +SELECT SUM(agg0) +FROM ( + SELECT ALL SUM(0.5) as agg0 + FROM ONLY test_collate_cast + GROUP BY + (((('fooText')||(test_collate_cast.c1)))::VARCHAR COLLATE "C") +) as asdf; + sum +--------------------------------------------------------------------- + 1.5 +(1 row) + -- Test range table with collated distribution column CREATE TABLE test_range(key text COLLATE german_phonebook, val int); SELECT create_distributed_table('test_range', 'key', 'range'); diff --git a/src/test/regress/sql/distributed_collations.sql b/src/test/regress/sql/distributed_collations.sql index 31464443d3d..4e254a97735 100644 --- a/src/test/regress/sql/distributed_collations.sql +++ b/src/test/regress/sql/distributed_collations.sql @@ -45,6 +45,27 @@ SELECT ALL MIN((lower(CAST(test_collate_pushed_down_aggregate.a AS VARCHAR)) COL FROM ONLY test_collate_pushed_down_aggregate; RESET citus.log_remote_commands; +-- Test COLLATE with type cast does not cause type mismatch (issue #8469) +-- When a GROUP BY expression uses both ::VARCHAR and COLLATE, the type cast +-- must be preserved in the query sent to workers. +SET citus.next_shard_id TO 20070000; +CREATE TABLE test_collate_cast (c0 inet, c1 inet); +SELECT create_distributed_table('test_collate_cast', 'c0'); +INSERT INTO test_collate_cast(c1, c0) VALUES + ('144.150.228.243', '230.194.119.117'), + ('22.171.214.19', '138.53.199.60'), + ('14.25.58.22', '103.167.89.59'); + +-- This used to fail with: "attribute 2 of type record has wrong type" +-- "Table has type text, but query expects character varying" +SELECT SUM(agg0) +FROM ( + SELECT ALL SUM(0.5) as agg0 + FROM ONLY test_collate_cast + GROUP BY + (((('fooText')||(test_collate_cast.c1)))::VARCHAR COLLATE "C") +) as asdf; + -- Test range table with collated distribution column CREATE TABLE test_range(key text COLLATE german_phonebook, val int); SELECT create_distributed_table('test_range', 'key', 'range');