SQL: Preserve original source for cast/convert function (#40271)
Improve rule for pruning cast to preserve the original source Fix #40239 (cherry picked from commit 7591cb1a1577320b3aec2ec557b0f881b6af744f)
This commit is contained in:
parent
1e6941b138
commit
dd41ce0763
|
@ -85,8 +85,8 @@ SELECT SUM(salary) FROM test_emp;
|
||||||
aggregateWithCastPruned
|
aggregateWithCastPruned
|
||||||
SELECT CAST(SUM(salary) AS INTEGER) FROM test_emp;
|
SELECT CAST(SUM(salary) AS INTEGER) FROM test_emp;
|
||||||
|
|
||||||
SUM(salary)
|
CAST(SUM(salary) AS INTEGER)
|
||||||
-------------
|
-----------------------------
|
||||||
4824855
|
4824855
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
||||||
);
|
);
|
||||||
//new BalanceBooleanTrees());
|
//new BalanceBooleanTrees());
|
||||||
Batch label = new Batch("Set as Optimized", Limiter.ONCE,
|
Batch label = new Batch("Set as Optimized", Limiter.ONCE,
|
||||||
|
CleanAliases.INSTANCE,
|
||||||
new SetAsOptimized());
|
new SetAsOptimized());
|
||||||
|
|
||||||
return Arrays.asList(operators, aggregate, local, label);
|
return Arrays.asList(operators, aggregate, local, label);
|
||||||
|
@ -895,7 +896,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
||||||
// Check if the groupings (a, y) match the orderings (b, x) through the aggregates' aliases (x, y)
|
// Check if the groupings (a, y) match the orderings (b, x) through the aggregates' aliases (x, y)
|
||||||
// e.g. SELECT a AS x, b AS y ... GROUP BY a, y ORDER BY b, x
|
// e.g. SELECT a AS x, b AS y ... GROUP BY a, y ORDER BY b, x
|
||||||
if ((equalsAsAttribute(child, group)
|
if ((equalsAsAttribute(child, group)
|
||||||
&& (equalsAsAttribute(alias, fieldToOrder) || equalsAsAttribute(child, fieldToOrder)))
|
&& (equalsAsAttribute(alias, fieldToOrder) || equalsAsAttribute(child, fieldToOrder)))
|
||||||
|| (equalsAsAttribute(alias, group)
|
|| (equalsAsAttribute(alias, group)
|
||||||
&& (equalsAsAttribute(alias, fieldToOrder) || equalsAsAttribute(child, fieldToOrder)))) {
|
&& (equalsAsAttribute(alias, fieldToOrder) || equalsAsAttribute(child, fieldToOrder)))) {
|
||||||
isMatching.set(Boolean.TRUE);
|
isMatching.set(Boolean.TRUE);
|
||||||
|
@ -944,43 +945,22 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
||||||
protected LogicalPlan rule(LogicalPlan plan) {
|
protected LogicalPlan rule(LogicalPlan plan) {
|
||||||
final Map<Attribute, Attribute> replacedCast = new LinkedHashMap<>();
|
final Map<Attribute, Attribute> replacedCast = new LinkedHashMap<>();
|
||||||
|
|
||||||
// first eliminate casts inside Aliases
|
// eliminate redundant casts
|
||||||
LogicalPlan transformed = plan.transformExpressionsUp(e -> {
|
LogicalPlan transformed = plan.transformExpressionsUp(e -> {
|
||||||
// cast wrapped in an alias
|
|
||||||
if (e instanceof Alias) {
|
|
||||||
Alias as = (Alias) e;
|
|
||||||
if (as.child() instanceof Cast) {
|
|
||||||
Cast c = (Cast) as.child();
|
|
||||||
|
|
||||||
if (c.from() == c.to()) {
|
|
||||||
Alias newAs = new Alias(as.source(), as.name(), as.qualifier(), c.field(), as.id(), as.synthetic());
|
|
||||||
replacedCast.put(as.toAttribute(), newAs.toAttribute());
|
|
||||||
return newAs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
return e;
|
|
||||||
});
|
|
||||||
|
|
||||||
// then handle stand-alone casts (mixed together the cast rule will kick in before the alias)
|
|
||||||
transformed = transformed.transformExpressionsUp(e -> {
|
|
||||||
if (e instanceof Cast) {
|
if (e instanceof Cast) {
|
||||||
Cast c = (Cast) e;
|
Cast c = (Cast) e;
|
||||||
|
|
||||||
if (c.from() == c.to()) {
|
if (c.from() == c.to()) {
|
||||||
Expression argument = c.field();
|
Expression argument = c.field();
|
||||||
if (argument instanceof NamedExpression) {
|
Alias as = new Alias(c.source(), c.sourceText(), argument);
|
||||||
replacedCast.put(c.toAttribute(), ((NamedExpression) argument).toAttribute());
|
replacedCast.put(c.toAttribute(), as.toAttribute());
|
||||||
}
|
|
||||||
|
|
||||||
return argument;
|
return as;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return e;
|
return e;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// replace attributes from previous removed Casts
|
// replace attributes from previous removed Casts
|
||||||
if (!replacedCast.isEmpty()) {
|
if (!replacedCast.isEmpty()) {
|
||||||
return transformed.transformUp(p -> {
|
return transformed.transformUp(p -> {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.elasticsearch.xpack.sql.expression.Order;
|
||||||
import org.elasticsearch.xpack.sql.expression.UnresolvedAttribute;
|
import org.elasticsearch.xpack.sql.expression.UnresolvedAttribute;
|
||||||
import org.elasticsearch.xpack.sql.expression.UnresolvedStar;
|
import org.elasticsearch.xpack.sql.expression.UnresolvedStar;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.UnresolvedFunction;
|
import org.elasticsearch.xpack.sql.expression.function.UnresolvedFunction;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.Cast;
|
||||||
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.MatchQueryPredicate;
|
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.MatchQueryPredicate;
|
||||||
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.MultiMatchQueryPredicate;
|
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.MultiMatchQueryPredicate;
|
||||||
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.StringQueryPredicate;
|
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.StringQueryPredicate;
|
||||||
|
@ -65,6 +66,21 @@ public class SqlParserTests extends ESTestCase {
|
||||||
assertEquals("SCORE()", f.sourceText());
|
assertEquals("SCORE()", f.sourceText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testSelectCast() {
|
||||||
|
Cast f = singleProjection(project(parseStatement("SELECT CAST(POWER(languages, 2) AS DOUBLE) FROM foo")), Cast.class);
|
||||||
|
assertEquals("CAST(POWER(languages, 2) AS DOUBLE)", f.sourceText());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSelectCastOperator() {
|
||||||
|
Cast f = singleProjection(project(parseStatement("SELECT POWER(languages, 2)::DOUBLE FROM foo")), Cast.class);
|
||||||
|
assertEquals("POWER(languages, 2)::DOUBLE", f.sourceText());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSelectCastWithSQLOperator() {
|
||||||
|
Cast f = singleProjection(project(parseStatement("SELECT CONVERT(POWER(languages, 2), SQL_DOUBLE) FROM foo")), Cast.class);
|
||||||
|
assertEquals("CONVERT(POWER(languages, 2), SQL_DOUBLE)", f.sourceText());
|
||||||
|
}
|
||||||
|
|
||||||
public void testSelectAddWithParanthesis() {
|
public void testSelectAddWithParanthesis() {
|
||||||
Add f = singleProjection(project(parseStatement("SELECT (1 + 2)")), Add.class);
|
Add f = singleProjection(project(parseStatement("SELECT (1 + 2)")), Add.class);
|
||||||
assertEquals("1 + 2", f.sourceText());
|
assertEquals("1 + 2", f.sourceText());
|
||||||
|
|
Loading…
Reference in New Issue