From 5dd2a3da0341c8409d5791bde5fe0e7e43fa76cd Mon Sep 17 00:00:00 2001 From: Ahmet Gedemenli Date: Wed, 14 Oct 2020 16:29:42 +0300 Subject: [PATCH] Convert RelabelTypes into CollateExprs in get_rule_expr function --- .../distributed/deparser/ruleutils_11.c | 40 ++++++++++++++----- .../distributed/deparser/ruleutils_12.c | 40 ++++++++++++++----- .../distributed/deparser/ruleutils_13.c | 40 ++++++++++++++----- .../planner/multi_physical_planner.c | 18 +++++++++ .../distributed/multi_physical_planner.h | 1 + .../expected/distributed_collations.out | 38 ++++++++++++++++++ .../regress/sql/distributed_collations.sql | 11 +++++ 7 files changed, 161 insertions(+), 27 deletions(-) diff --git a/src/backend/distributed/deparser/ruleutils_11.c b/src/backend/distributed/deparser/ruleutils_11.c index 2c947b467..b11c71749 100644 --- a/src/backend/distributed/deparser/ruleutils_11.c +++ b/src/backend/distributed/deparser/ruleutils_11.c @@ -5166,20 +5166,42 @@ get_rule_expr(Node *node, deparse_context *context, case T_RelabelType: { RelabelType *relabel = (RelabelType *) node; - Node *arg = (Node *) relabel->arg; - if (relabel->relabelformat == COERCE_IMPLICIT_CAST && - !showimplicit) + /* + * This is a Citus specific modification + * The planner converts CollateExpr to RelabelType + * and here we convert back. + */ + if (relabel->resultcollid != InvalidOid) { - /* don't show the implicit cast */ - get_rule_expr_paren(arg, context, false, node); + CollateExpr *collate = RelabelTypeToCollateExpr(relabel); + Node *arg = (Node *) collate->arg; + + if (!PRETTY_PAREN(context)) + appendStringInfoChar(buf, '('); + get_rule_expr_paren(arg, context, showimplicit, node); + appendStringInfo(buf, " COLLATE %s", + generate_collation_name(collate->collOid)); + if (!PRETTY_PAREN(context)) + appendStringInfoChar(buf, ')'); } else { - get_coercion_expr(arg, context, - relabel->resulttype, - relabel->resulttypmod, - node); + Node *arg = (Node *) relabel->arg; + + if (relabel->relabelformat == COERCE_IMPLICIT_CAST && + !showimplicit) + { + /* don't show the implicit cast */ + get_rule_expr_paren(arg, context, false, node); + } + else + { + get_coercion_expr(arg, context, + relabel->resulttype, + relabel->resulttypmod, + node); + } } } break; diff --git a/src/backend/distributed/deparser/ruleutils_12.c b/src/backend/distributed/deparser/ruleutils_12.c index 2d13e36d2..173dd6aa2 100644 --- a/src/backend/distributed/deparser/ruleutils_12.c +++ b/src/backend/distributed/deparser/ruleutils_12.c @@ -5181,20 +5181,42 @@ get_rule_expr(Node *node, deparse_context *context, case T_RelabelType: { RelabelType *relabel = (RelabelType *) node; - Node *arg = (Node *) relabel->arg; - if (relabel->relabelformat == COERCE_IMPLICIT_CAST && - !showimplicit) + /* + * This is a Citus specific modification + * The planner converts CollateExpr to RelabelType + * and here we convert back. + */ + if (relabel->resultcollid != InvalidOid) { - /* don't show the implicit cast */ - get_rule_expr_paren(arg, context, false, node); + CollateExpr *collate = RelabelTypeToCollateExpr(relabel); + Node *arg = (Node *) collate->arg; + + if (!PRETTY_PAREN(context)) + appendStringInfoChar(buf, '('); + get_rule_expr_paren(arg, context, showimplicit, node); + appendStringInfo(buf, " COLLATE %s", + generate_collation_name(collate->collOid)); + if (!PRETTY_PAREN(context)) + appendStringInfoChar(buf, ')'); } else { - get_coercion_expr(arg, context, - relabel->resulttype, - relabel->resulttypmod, - node); + Node *arg = (Node *) relabel->arg; + + if (relabel->relabelformat == COERCE_IMPLICIT_CAST && + !showimplicit) + { + /* don't show the implicit cast */ + get_rule_expr_paren(arg, context, false, node); + } + else + { + get_coercion_expr(arg, context, + relabel->resulttype, + relabel->resulttypmod, + node); + } } } break; diff --git a/src/backend/distributed/deparser/ruleutils_13.c b/src/backend/distributed/deparser/ruleutils_13.c index e321d149b..484fd524f 100644 --- a/src/backend/distributed/deparser/ruleutils_13.c +++ b/src/backend/distributed/deparser/ruleutils_13.c @@ -5237,20 +5237,42 @@ get_rule_expr(Node *node, deparse_context *context, case T_RelabelType: { RelabelType *relabel = (RelabelType *) node; - Node *arg = (Node *) relabel->arg; - if (relabel->relabelformat == COERCE_IMPLICIT_CAST && - !showimplicit) + /* + * This is a Citus specific modification + * The planner converts CollateExpr to RelabelType + * and here we convert back. + */ + if (relabel->resultcollid != InvalidOid) { - /* don't show the implicit cast */ - get_rule_expr_paren(arg, context, false, node); + CollateExpr *collate = RelabelTypeToCollateExpr(relabel); + Node *arg = (Node *) collate->arg; + + if (!PRETTY_PAREN(context)) + appendStringInfoChar(buf, '('); + get_rule_expr_paren(arg, context, showimplicit, node); + appendStringInfo(buf, " COLLATE %s", + generate_collation_name(collate->collOid)); + if (!PRETTY_PAREN(context)) + appendStringInfoChar(buf, ')'); } else { - get_coercion_expr(arg, context, - relabel->resulttype, - relabel->resulttypmod, - node); + Node *arg = (Node *) relabel->arg; + + if (relabel->relabelformat == COERCE_IMPLICIT_CAST && + !showimplicit) + { + /* don't show the implicit cast */ + get_rule_expr_paren(arg, context, false, node); + } + else + { + get_coercion_expr(arg, context, + relabel->resulttype, + relabel->resulttypmod, + node); + } } } break; diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index 2a12a8b8a..0f699f24e 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -2937,6 +2937,24 @@ SqlTaskList(Job *job) } +/* + * RelabelTypeToCollateExpr converts RelabelType's into CollationExpr's. + * With that, we will be able to pushdown COLLATE's. + */ +CollateExpr * +RelabelTypeToCollateExpr(RelabelType *relabelType) +{ + Assert(OidIsValid(relabelType->resultcollid)); + + CollateExpr *collateExpr = makeNode(CollateExpr); + collateExpr->arg = relabelType->arg; + collateExpr->collOid = relabelType->resultcollid; + collateExpr->location = relabelType->location; + + return collateExpr; +} + + /* * DependsOnHashPartitionJob checks if the given job depends on a hash * partitioning job. diff --git a/src/include/distributed/multi_physical_planner.h b/src/include/distributed/multi_physical_planner.h index 6dd9153b8..8acc4b3a4 100644 --- a/src/include/distributed/multi_physical_planner.h +++ b/src/include/distributed/multi_physical_planner.h @@ -540,6 +540,7 @@ extern Node * WrapUngroupedVarsInAnyValueAggregate(Node *expression, List *groupClauseList, List *targetList, bool checkExpressionEquality); +extern CollateExpr * RelabelTypeToCollateExpr(RelabelType *relabelType); /* * Function declarations for building, updating constraints and simple operator diff --git a/src/test/regress/expected/distributed_collations.out b/src/test/regress/expected/distributed_collations.out index 526d6f9f9..b2b597035 100644 --- a/src/test/regress/expected/distributed_collations.out +++ b/src/test/regress/expected/distributed_collations.out @@ -56,6 +56,44 @@ SELECT * FROM collation_tests.test_propagate WHERE t2 < 'b' COLLATE "C"; 2 | Voẞr | Vossr (1 row) +SELECT * FROM collation_tests.test_propagate WHERE t2 COLLATE "C" < 'b'; + id | t1 | t2 +--------------------------------------------------------------------- + 2 | Voẞr | Vossr +(1 row) + +-- Test COLLATE is pushed down with aggregate function +SET citus.next_shard_id TO 20060000; +CREATE TABLE test_collate_pushed_down_aggregate (a int, b int); +SELECT create_distributed_table('test_collate_pushed_down_aggregate', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT alter_distributed_table('test_collate_pushed_down_aggregate', shard_count := 2, cascade_to_colocated:=false); +NOTICE: creating a new table for collation_tests.test_collate_pushed_down_aggregate +NOTICE: Moving the data of collation_tests.test_collate_pushed_down_aggregate +NOTICE: Dropping the old collation_tests.test_collate_pushed_down_aggregate +NOTICE: Renaming the new table to collation_tests.test_collate_pushed_down_aggregate + alter_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SET citus.log_remote_commands TO true; +SELECT ALL MIN((lower(CAST(test_collate_pushed_down_aggregate.a AS VARCHAR)) COLLATE "C")) + FROM ONLY test_collate_pushed_down_aggregate; +NOTICE: issuing SELECT min((lower(((a)::character varying COLLATE "default")) COLLATE "C")) AS min FROM collation_tests.test_collate_pushed_down_aggregate_20060004 test_collate_pushed_down_aggregate WHERE true +DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx +NOTICE: issuing SELECT min((lower(((a)::character varying COLLATE "default")) COLLATE "C")) AS min FROM collation_tests.test_collate_pushed_down_aggregate_20060005 test_collate_pushed_down_aggregate WHERE true +DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx + min +--------------------------------------------------------------------- + +(1 row) + +RESET citus.log_remote_commands; -- 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 c32100e5c..2bf85448a 100644 --- a/src/test/regress/sql/distributed_collations.sql +++ b/src/test/regress/sql/distributed_collations.sql @@ -34,6 +34,17 @@ SELECT create_distributed_table('test_propagate', 'id'); -- Test COLLATE is pushed down SELECT * FROM collation_tests.test_propagate WHERE t2 < 'b'; SELECT * FROM collation_tests.test_propagate WHERE t2 < 'b' COLLATE "C"; +SELECT * FROM collation_tests.test_propagate WHERE t2 COLLATE "C" < 'b'; + +-- Test COLLATE is pushed down with aggregate function +SET citus.next_shard_id TO 20060000; +CREATE TABLE test_collate_pushed_down_aggregate (a int, b int); +SELECT create_distributed_table('test_collate_pushed_down_aggregate', 'a'); +SELECT alter_distributed_table('test_collate_pushed_down_aggregate', shard_count := 2, cascade_to_colocated:=false); +SET citus.log_remote_commands TO true; +SELECT ALL MIN((lower(CAST(test_collate_pushed_down_aggregate.a AS VARCHAR)) COLLATE "C")) + FROM ONLY test_collate_pushed_down_aggregate; +RESET citus.log_remote_commands; -- Test range table with collated distribution column CREATE TABLE test_range(key text COLLATE german_phonebook, val int);