From 8190a6c69817d192573e0a857e403ed737ee39da Mon Sep 17 00:00:00 2001 From: wangbo <506340561@qq.com> Date: Sat, 25 Apr 2020 15:17:46 +0800 Subject: [PATCH 1/7] (#3395)calculate 'case when expr' when possible --- .../java/org/apache/doris/rewrite/FoldConstantsRule.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fe/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java b/fe/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java index 1c4298e9ed3e25..29b6ad65e66389 100644 --- a/fe/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java +++ b/fe/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java @@ -19,6 +19,8 @@ import org.apache.doris.analysis.Analyzer; +import org.apache.doris.analysis.BoolLiteral; +import org.apache.doris.analysis.CaseExpr; import org.apache.doris.analysis.CastExpr; import org.apache.doris.analysis.Expr; import org.apache.doris.analysis.NullLiteral; @@ -48,6 +50,12 @@ public class FoldConstantsRule implements ExprRewriteRule { @Override public Expr apply(Expr expr, Analyzer analyzer) throws AnalysisException { + // evaluate case when expr + if (expr instanceof CaseExpr && expr.getChild(0) instanceof BoolLiteral) { + BoolLiteral boolLiteral = (BoolLiteral) expr.getChild(0); + return boolLiteral.getValue() ? expr.getChild(1) : expr.getChild(2); + } + // Avoid calling Expr.isConstant() because that would lead to repeated traversals // of the Expr tree. Assumes the bottom-up application of this rule. Constant // children should have been folded at this point. From 595b5d46980b6d9a522d68f7c599f8a7ec181aa5 Mon Sep 17 00:00:00 2001 From: wangbo <506340561@qq.com> Date: Sat, 25 Apr 2020 21:58:47 +0800 Subject: [PATCH 2/7] add ut --- .../apache/doris/planner/QueryPlanTest.java | 15 +++++++++ .../apache/doris/utframe/UtFrameUtils.java | 32 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java b/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java index 003637631bf52f..119d7976a1f98b 100644 --- a/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java +++ b/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java @@ -504,4 +504,19 @@ public void testDateTypeEquality() throws Exception { Catalog.getCurrentCatalog().getLoadManager().createLoadJobV1FromStmt(loadStmt, EtlJobType.HADOOP, System.currentTimeMillis()); } + + @Test + public void testConvertCaseWhenToConstant() throws Exception { + String caseWhenSql = "select " + + "case when date_format(now(),'%H%i') < 123 then 1 else 0 end as col_name " + + "from test.test1 " + + "where time = case when date_format(now(),'%H%i') < 123 then date_format(date_sub(now(),2),'%Y%m%d') else date_format(date_sub(now(),1),'%Y%m%d') end"; + SelectStmt selectStmt = + (SelectStmt) UtFrameUtils.parseAndAnalyzeStmt(caseWhenSql, connectContext); + selectStmt = (SelectStmt) UtFrameUtils.rewriteStmt(selectStmt, connectContext); + selectStmt = (SelectStmt) UtFrameUtils.reAnalyze(selectStmt, connectContext); + + Assert.assertTrue(!selectStmt.toSql().contains("CASE WHEN") && !selectStmt.toSql().contains("case when")); + + } } diff --git a/fe/src/test/java/org/apache/doris/utframe/UtFrameUtils.java b/fe/src/test/java/org/apache/doris/utframe/UtFrameUtils.java index ac538e7324b055..66f10aff261a69 100644 --- a/fe/src/test/java/org/apache/doris/utframe/UtFrameUtils.java +++ b/fe/src/test/java/org/apache/doris/utframe/UtFrameUtils.java @@ -18,21 +18,25 @@ package org.apache.doris.utframe; import org.apache.doris.analysis.Analyzer; +import org.apache.doris.analysis.Expr; import org.apache.doris.analysis.SqlParser; import org.apache.doris.analysis.SqlScanner; import org.apache.doris.analysis.StatementBase; import org.apache.doris.analysis.UserIdentity; import org.apache.doris.catalog.Catalog; +import org.apache.doris.catalog.Type; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.Config; import org.apache.doris.common.DdlException; import org.apache.doris.common.Pair; +import org.apache.doris.common.UserException; import org.apache.doris.common.util.SqlParserUtils; import org.apache.doris.mysql.privilege.PaloAuth; import org.apache.doris.planner.Planner; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.QueryState; import org.apache.doris.qe.StmtExecutor; +import org.apache.doris.rewrite.ExprRewriter; import org.apache.doris.system.SystemInfoService; import org.apache.doris.thrift.TExplainLevel; import org.apache.doris.thrift.TNetworkAddress; @@ -96,6 +100,34 @@ public static StatementBase parseAndAnalyzeStmt(String originStmt, ConnectContex return statementBase; } + public static StatementBase rewriteStmt(StatementBase stmt, ConnectContext ctx) throws AnalysisException { + Analyzer analyzer = new Analyzer(ctx.getCatalog(), ctx); + ExprRewriter rewriter = analyzer.getExprRewriter(); + rewriter.reset(); + stmt.rewriteExprs(rewriter); + return stmt; + } + + public static StatementBase reAnalyze(StatementBase stmt, ConnectContext ctx) throws UserException { + Analyzer analyzer = new Analyzer(ctx.getCatalog(), ctx); + List origResultTypes = Lists.newArrayList(); + for (Expr e: stmt.getResultExprs()) { + origResultTypes.add(e.getType()); + } + List origColLabels = + Lists.newArrayList(stmt.getColLabels()); + + // Re-analyze the stmt with a new analyzer. + // query re-analyze + stmt.reset(); + stmt.analyze(analyzer); + + // Restore the original result types and column labels. + stmt.castResultExprs(origResultTypes); + stmt.setColLabels(origColLabels); + return stmt; + } + // for analyzing multi statements public static List parseAndAnalyzeStmts(String originStmt, ConnectContext ctx) throws Exception { System.out.println("begin to parse stmts: " + originStmt); From 507bd161dbb30944a9fd3069b6e001e58c7274a3 Mon Sep 17 00:00:00 2001 From: wangbo <506340561@qq.com> Date: Wed, 29 Apr 2020 13:23:14 +0800 Subject: [PATCH 3/7] 1 support case when and case xxx when 2 add ut --- .../org/apache/doris/analysis/CaseExpr.java | 74 ++++++++++++++ .../doris/rewrite/FoldConstantsRule.java | 8 +- .../apache/doris/planner/QueryPlanTest.java | 99 +++++++++++++++++-- 3 files changed, 170 insertions(+), 11 deletions(-) diff --git a/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java b/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java index 602aabdf92a46c..5a5b13bc7aad9f 100644 --- a/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java +++ b/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java @@ -26,6 +26,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; +import java.util.ArrayList; import java.util.List; /** @@ -101,10 +102,15 @@ public boolean equals(Object obj) { CaseExpr expr = (CaseExpr) obj; return hasCaseExpr == expr.hasCaseExpr && hasElseExpr == expr.hasElseExpr; } + public boolean hasCaseExpr() { return hasCaseExpr; } + public boolean hasElseExpr() { + return hasCaseExpr; + } + @Override public String toSqlImpl() { StringBuilder output = new StringBuilder("CASE"); @@ -251,4 +257,72 @@ public List getReturnExprs() { } return exprs; } + + // this method just compare literal value and not completely consistent with be,for two cases + // 1 not deal float + // 2 just compare literal value with same type. for a example sql 'select case when 123 then '1' else '2' end as col' + // for be will return '1', because be only regard 0 as false + // but for current LiteralExpr.compareLiteral, `123`' won't be regard as true + // the case which two values has different type left to be + public static Expr computeCaseExpr(CaseExpr expr) { + LiteralExpr caseExpr; + int startIndex = 0; + int size = expr.getChildren().size() - 1; + if (expr.hasCaseExpr()) { + // just deal literal here + // and avoid `float compute` in java,float should be dealt in be + Expr caseChildExpr = expr.getChild(0); + if (!caseChildExpr.isLiteral() + || caseChildExpr instanceof DecimalLiteral || caseChildExpr instanceof FloatLiteral) { + return expr; + } + caseExpr = (LiteralExpr) expr.getChild(0); + startIndex++; + size--; + } else { + caseExpr = new BoolLiteral(true); + } + + if (expr.hasElseExpr) { + size--; + } + + //pre return when the `when expr` can't be converted to constants + Expr startExpr = expr.getChild(startIndex); + if ((!startExpr.isLiteral() || startExpr instanceof DecimalLiteral || startExpr instanceof FloatLiteral) + || !startExpr.getClass().toString().equals(caseExpr.getClass().toString())) { + return expr; + } + + for (int i = startIndex; i < size; i = i + 2) { + Expr currentWhenExpr = expr.getChild(i); + // stop convert in three cases + // 1 not literal + // 2 float + // 3 `case expr` and `when expr` don't have same type + if ((!currentWhenExpr.isLiteral() || currentWhenExpr instanceof DecimalLiteral || currentWhenExpr instanceof FloatLiteral) + || !currentWhenExpr.getClass().toString().equals(caseExpr.getClass().toString())) { + // remove the expr which has been evaluated + List exprLeft = new ArrayList<>(); + if (expr.hasCaseExpr()) { + exprLeft.add(caseExpr); + } + for (int j = i; j < expr.getChildren().size(); j++) { + exprLeft.add(expr.getChild(j)); + } + expr.getChildren().clear(); + expr.addChildren(exprLeft); + return expr; + } else if (caseExpr.compareLiteral((LiteralExpr) currentWhenExpr) == 0) { + return expr.getChild(i + 1); + } + } + + if (expr.hasElseExpr) { + return expr.getChild(expr.getChildren().size() - 1); + } else { + return new NullLiteral(); + } + } + } diff --git a/fe/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java b/fe/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java index 29b6ad65e66389..f697150400669e 100644 --- a/fe/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java +++ b/fe/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java @@ -19,7 +19,6 @@ import org.apache.doris.analysis.Analyzer; -import org.apache.doris.analysis.BoolLiteral; import org.apache.doris.analysis.CaseExpr; import org.apache.doris.analysis.CastExpr; import org.apache.doris.analysis.Expr; @@ -50,10 +49,9 @@ public class FoldConstantsRule implements ExprRewriteRule { @Override public Expr apply(Expr expr, Analyzer analyzer) throws AnalysisException { - // evaluate case when expr - if (expr instanceof CaseExpr && expr.getChild(0) instanceof BoolLiteral) { - BoolLiteral boolLiteral = (BoolLiteral) expr.getChild(0); - return boolLiteral.getValue() ? expr.getChild(1) : expr.getChild(2); + // evaluate `case when expr` when possible + if (expr instanceof CaseExpr) { + return CaseExpr.computeCaseExpr((CaseExpr) expr); } // Avoid calling Expr.isConstant() because that would lead to repeated traversals diff --git a/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java b/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java index 119d7976a1f98b..c6f62cd2e9b358 100644 --- a/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java +++ b/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java @@ -505,18 +505,105 @@ public void testDateTypeEquality() throws Exception { System.currentTimeMillis()); } + private SelectStmt getAnalyzedAndRewritedStmt(String sql) throws Exception { + SelectStmt selectStmt = + (SelectStmt) UtFrameUtils.parseAndAnalyzeStmt(sql, connectContext); + selectStmt = (SelectStmt) UtFrameUtils.rewriteStmt(selectStmt, connectContext); + selectStmt = (SelectStmt) UtFrameUtils.reAnalyze(selectStmt, connectContext); + return selectStmt; + } + @Test public void testConvertCaseWhenToConstant() throws Exception { + // basic test String caseWhenSql = "select " - + "case when date_format(now(),'%H%i') < 123 then 1 else 0 end as col_name " + + "case when date_format(now(),'%H%i') < 123 then 1 else 0 end as col " + "from test.test1 " + "where time = case when date_format(now(),'%H%i') < 123 then date_format(date_sub(now(),2),'%Y%m%d') else date_format(date_sub(now(),1),'%Y%m%d') end"; - SelectStmt selectStmt = - (SelectStmt) UtFrameUtils.parseAndAnalyzeStmt(caseWhenSql, connectContext); - selectStmt = (SelectStmt) UtFrameUtils.rewriteStmt(selectStmt, connectContext); - selectStmt = (SelectStmt) UtFrameUtils.reAnalyze(selectStmt, connectContext); - + SelectStmt selectStmt = getAnalyzedAndRewritedStmt(caseWhenSql); Assert.assertTrue(!selectStmt.toSql().contains("CASE WHEN") && !selectStmt.toSql().contains("case when")); + // test 1: case when then + // 1.1 multi when in on `case when` and can be converted to constants + String sql11 = "select case when false then 2 when true then 3 else 0 end as col11;"; + SelectStmt sql11Stmt = getAnalyzedAndRewritedStmt(sql11); + Assert.assertTrue(sql11Stmt.toSql().equals("SELECT 3 AS `col11`")); + + // 1.2 multi when in on `case when` ,when expr can not be converted to constants + String sql121 = "select case when false then 2 when substr(k7,2,1) then 3 else 0 end as col121 from test.baseall"; + SelectStmt sqlStmt121 = getAnalyzedAndRewritedStmt(sql121); + Assert.assertTrue(sqlStmt121.toSql().equals("SELECT CASE WHEN substr(`k7`, 2, 1) THEN 3 ELSE 0 END AS `col121` FROM `default_cluster:test`.`baseall`")); + + // 1.2.2 when expr which can not be converted to constants in the first + String sql122 = "select case when substr(k7,2,1) then 2 when false then 3 else 0 end as col122 from test.baseall"; + SelectStmt sqlStmt122 = getAnalyzedAndRewritedStmt(sql122); + Assert.assertTrue(sqlStmt122.toSql().equals("SELECT CASE WHEN substr(`k7`, 2, 1) THEN 2 WHEN FALSE THEN 3 ELSE 0 END AS `col122` FROM `default_cluster:test`.`baseall`")); + + // 1.2.3 when expr which can not be converted to constants in the middle + String sql123 = "select case when false then 2 when substr(k7,2,1) then 3 else 0 end as col123 from test.baseall"; + SelectStmt sqlStmt123 = getAnalyzedAndRewritedStmt(sql123); + Assert.assertTrue(sqlStmt123.toSql().equals("SELECT CASE WHEN substr(`k7`, 2, 1) THEN 3 ELSE 0 END AS `col123` FROM `default_cluster:test`.`baseall`")); + + // 1.3 test return null + String sql3 = "select case when false then 2 end as col3"; + SelectStmt sql3Stmt = getAnalyzedAndRewritedStmt(sql3); + Assert.assertTrue(sql3Stmt.toSql().equals("SELECT NULL AS `col3`")); + + // 1.3.1 test return else expr + String sql131 = "select case when false then 2 when false then 3 else 4 end as col131"; + SelectStmt sql131Stmt = getAnalyzedAndRewritedStmt(sql131); + Assert.assertTrue(sql131Stmt.toSql().equals("SELECT 4 AS `col131`")); + + // 1.4 nest `case when` and can be converted to constants + String sql14 = "select case when (case when true then true else false end) then 2 when false then 3 else 0 end as col"; + SelectStmt sql14Stmt = getAnalyzedAndRewritedStmt(sql14); + Assert.assertTrue(sql14Stmt.toSql().equals("SELECT 2 AS `col`")); + + // 1.5 nest `case when` and can not be converted to constants + String sql15 = "select case when case when substr(k7,2,1) then true else false end then 2 when false then 3 else 0 end as col from test.baseall"; + SelectStmt sql15Stmt = getAnalyzedAndRewritedStmt(sql15); + Assert.assertTrue(sql15Stmt.toSql().equals("SELECT CASE WHEN CASE WHEN substr(`k7`, 2, 1) THEN TRUE ELSE FALSE END THEN 2 WHEN FALSE THEN 3 ELSE 0 END AS `col` FROM `default_cluster:test`.`baseall`")); + + // test 2: case xxx when then + // 2.1 test equal + String sql2 = "select case 1 when 1 then 'a' when 2 then 'b' else 'other' end as col2;"; + SelectStmt sql2Stmt = getAnalyzedAndRewritedStmt(sql2); + Assert.assertTrue(sql2Stmt.toSql().equals("SELECT 'a' AS `col2`")); + + // 2.1.2 test not equal + String sql212 = "select case 'a' when 1 then 'a' when 'a' then 'b' else 'other' end as col212;"; + SelectStmt sql212Stmt = getAnalyzedAndRewritedStmt(sql212); + Assert.assertTrue(sql212Stmt.toSql().equals("SELECT 'other' AS `col212`")); + + // 2.2 test return null + String sql22 = "select case 'a' when 1 then 'a' when 'b' then 'b' end as col22;"; + SelectStmt sql22Stmt = getAnalyzedAndRewritedStmt(sql22); + Assert.assertTrue(sql22Stmt.toSql().equals("SELECT NULL AS `col22`")); + + // 2.2.2 test return else + String sql222 = "select case 1 when 2 then 'a' when 3 then 'b' else 'other' end as col222;"; + SelectStmt sql222Stmt = getAnalyzedAndRewritedStmt(sql222); + Assert.assertTrue(sql222Stmt.toSql().equals("SELECT 'other' AS `col222`")); + + // 2.3 test can not convert to constant,middle when expr is not constant + String sql23 = "select case 'a' when 1 then 'a' when substr(k7,2,1) then 2 when false then 3 else 0 end as col23 from test.baseall"; + SelectStmt sql23Stmt = getAnalyzedAndRewritedStmt(sql23); + Assert.assertTrue(sql23Stmt.toSql().equals("SELECT CASE'a' WHEN substr(`k7`, 2, 1) THEN '2' WHEN '0' THEN '3' ELSE '0' END AS `col23` FROM `default_cluster:test`.`baseall`")); + + // 2.3.1 first when expr is not constant + String sql231 = "select case 'a' when substr(k7,2,1) then 2 when 1 then 'a' when false then 3 else 0 end as col231 from test.baseall"; + SelectStmt sql231Stmt = getAnalyzedAndRewritedStmt(sql231); + Assert.assertTrue(sql231Stmt.toSql().equals("SELECT CASE'a' WHEN substr(`k7`, 2, 1) THEN '2' WHEN '1' THEN 'a' WHEN '0' THEN '3' ELSE '0' END AS `col231` FROM `default_cluster:test`.`baseall`")); + + // 2.3.2 case expr is not constant + String sql232 = "select case k1 when substr(k7,2,1) then 2 when 1 then 'a' when false then 3 else 0 end as col232 from test.baseall"; + SelectStmt sql232Stmt = getAnalyzedAndRewritedStmt(sql232); + Assert.assertTrue(sql232Stmt.toSql().equals("SELECT CASE`k1` WHEN substr(`k7`, 2, 1) THEN '2' WHEN '1' THEN 'a' WHEN '0' THEN '3' ELSE '0' END AS `col232` FROM `default_cluster:test`.`baseall`")); + + // 3.1 test float,float in case expr + String sql31 = "select case cast(100 as float) when 1 then 'a' when 2 then 'b' else 'other' end as col31;"; + SelectStmt sql31Stmt = getAnalyzedAndRewritedStmt(sql31); + Assert.assertTrue(sql31Stmt.toSql().equals("SELECT CASE100.0 WHEN 1.0 THEN 'a' WHEN 2.0 THEN 'b' ELSE 'other' END AS `col31`")); + } } From cd9bedd5801e10b039cddcaaa241900750764777 Mon Sep 17 00:00:00 2001 From: wangbo <506340561@qq.com> Date: Thu, 30 Apr 2020 13:31:00 +0800 Subject: [PATCH 4/7] 1 support skip null 2 add more ut 3 fix logic bug --- .../org/apache/doris/analysis/CaseExpr.java | 23 +++++-- .../apache/doris/planner/QueryPlanTest.java | 68 +++++++++++++------ 2 files changed, 65 insertions(+), 26 deletions(-) diff --git a/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java b/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java index 5a5b13bc7aad9f..27c4a438d88e16 100644 --- a/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java +++ b/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java @@ -267,7 +267,7 @@ public List getReturnExprs() { public static Expr computeCaseExpr(CaseExpr expr) { LiteralExpr caseExpr; int startIndex = 0; - int size = expr.getChildren().size() - 1; + int endIndex = expr.getChildren().size(); if (expr.hasCaseExpr()) { // just deal literal here // and avoid `float compute` in java,float should be dealt in be @@ -278,24 +278,35 @@ public static Expr computeCaseExpr(CaseExpr expr) { } caseExpr = (LiteralExpr) expr.getChild(0); startIndex++; - size--; } else { caseExpr = new BoolLiteral(true); } + if (caseExpr instanceof NullLiteral) { + if (expr.hasElseExpr) { + return expr.getChild(expr.getChildren().size() - 1); + } else { + return new NullLiteral(); + } + } + if (expr.hasElseExpr) { - size--; + endIndex--; } - //pre return when the `when expr` can't be converted to constants + // early return when the `when expr` can't be converted to constants Expr startExpr = expr.getChild(startIndex); if ((!startExpr.isLiteral() || startExpr instanceof DecimalLiteral || startExpr instanceof FloatLiteral) - || !startExpr.getClass().toString().equals(caseExpr.getClass().toString())) { + || (!(startExpr instanceof NullLiteral) && !startExpr.getClass().toString().equals(caseExpr.getClass().toString()))) { return expr; } - for (int i = startIndex; i < size; i = i + 2) { + for (int i = startIndex; i < endIndex; i = i + 2) { Expr currentWhenExpr = expr.getChild(i); + // skip null literal + if (currentWhenExpr instanceof NullLiteral) { + continue; + } // stop convert in three cases // 1 not literal // 2 float diff --git a/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java b/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java index c6f62cd2e9b358..cd767f56327163 100644 --- a/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java +++ b/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java @@ -17,6 +17,7 @@ package org.apache.doris.planner; +import org.apache.commons.lang3.StringUtils; import org.apache.doris.analysis.CreateDbStmt; import org.apache.doris.analysis.CreateTableStmt; import org.apache.doris.analysis.DropDbStmt; @@ -521,89 +522,116 @@ public void testConvertCaseWhenToConstant() throws Exception { + "from test.test1 " + "where time = case when date_format(now(),'%H%i') < 123 then date_format(date_sub(now(),2),'%Y%m%d') else date_format(date_sub(now(),1),'%Y%m%d') end"; SelectStmt selectStmt = getAnalyzedAndRewritedStmt(caseWhenSql); - Assert.assertTrue(!selectStmt.toSql().contains("CASE WHEN") && !selectStmt.toSql().contains("case when")); + Assert.assertTrue(!StringUtils.containsIgnoreCase(selectStmt.toSql(),"CASE WHEN") && !StringUtils.containsIgnoreCase(selectStmt.toSql(), "case when")); // test 1: case when then // 1.1 multi when in on `case when` and can be converted to constants String sql11 = "select case when false then 2 when true then 3 else 0 end as col11;"; SelectStmt sql11Stmt = getAnalyzedAndRewritedStmt(sql11); - Assert.assertTrue(sql11Stmt.toSql().equals("SELECT 3 AS `col11`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql11Stmt.toSql(), "SELECT 3 AS `col11`")); - // 1.2 multi when in on `case when` ,when expr can not be converted to constants + // 1.2 multi `when expr` in on `case when` ,`when expr` can not be converted to constants String sql121 = "select case when false then 2 when substr(k7,2,1) then 3 else 0 end as col121 from test.baseall"; SelectStmt sqlStmt121 = getAnalyzedAndRewritedStmt(sql121); - Assert.assertTrue(sqlStmt121.toSql().equals("SELECT CASE WHEN substr(`k7`, 2, 1) THEN 3 ELSE 0 END AS `col121` FROM `default_cluster:test`.`baseall`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sqlStmt121.toSql(),"SELECT CASE WHEN substr(`k7`, 2, 1) THEN 3 ELSE 0 END AS `col121` FROM `default_cluster:test`.`baseall`")); // 1.2.2 when expr which can not be converted to constants in the first String sql122 = "select case when substr(k7,2,1) then 2 when false then 3 else 0 end as col122 from test.baseall"; SelectStmt sqlStmt122 = getAnalyzedAndRewritedStmt(sql122); - Assert.assertTrue(sqlStmt122.toSql().equals("SELECT CASE WHEN substr(`k7`, 2, 1) THEN 2 WHEN FALSE THEN 3 ELSE 0 END AS `col122` FROM `default_cluster:test`.`baseall`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sqlStmt122.toSql(), "SELECT CASE WHEN substr(`k7`, 2, 1) THEN 2 WHEN FALSE THEN 3 ELSE 0 END AS `col122` FROM `default_cluster:test`.`baseall`")); // 1.2.3 when expr which can not be converted to constants in the middle String sql123 = "select case when false then 2 when substr(k7,2,1) then 3 else 0 end as col123 from test.baseall"; SelectStmt sqlStmt123 = getAnalyzedAndRewritedStmt(sql123); - Assert.assertTrue(sqlStmt123.toSql().equals("SELECT CASE WHEN substr(`k7`, 2, 1) THEN 3 ELSE 0 END AS `col123` FROM `default_cluster:test`.`baseall`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sqlStmt123.toSql(), "SELECT CASE WHEN substr(`k7`, 2, 1) THEN 3 ELSE 0 END AS `col123` FROM `default_cluster:test`.`baseall`")); + + // 1.2.4 test return `then expr` in the middle + String sql124 = "select case when false then 1 when true then 2 when false then 3 else 'other' end as col124"; + SelectStmt sql124Stmt = getAnalyzedAndRewritedStmt(sql124); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql124Stmt.toSql(), "SELECT '2' AS `col124`")); // 1.3 test return null String sql3 = "select case when false then 2 end as col3"; SelectStmt sql3Stmt = getAnalyzedAndRewritedStmt(sql3); - Assert.assertTrue(sql3Stmt.toSql().equals("SELECT NULL AS `col3`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql3Stmt.toSql(), "SELECT NULL AS `col3`")); // 1.3.1 test return else expr String sql131 = "select case when false then 2 when false then 3 else 4 end as col131"; SelectStmt sql131Stmt = getAnalyzedAndRewritedStmt(sql131); - Assert.assertTrue(sql131Stmt.toSql().equals("SELECT 4 AS `col131`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql131Stmt.toSql(), "SELECT 4 AS `col131`")); // 1.4 nest `case when` and can be converted to constants String sql14 = "select case when (case when true then true else false end) then 2 when false then 3 else 0 end as col"; SelectStmt sql14Stmt = getAnalyzedAndRewritedStmt(sql14); - Assert.assertTrue(sql14Stmt.toSql().equals("SELECT 2 AS `col`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql14Stmt.toSql(), "SELECT 2 AS `col`")); // 1.5 nest `case when` and can not be converted to constants String sql15 = "select case when case when substr(k7,2,1) then true else false end then 2 when false then 3 else 0 end as col from test.baseall"; SelectStmt sql15Stmt = getAnalyzedAndRewritedStmt(sql15); - Assert.assertTrue(sql15Stmt.toSql().equals("SELECT CASE WHEN CASE WHEN substr(`k7`, 2, 1) THEN TRUE ELSE FALSE END THEN 2 WHEN FALSE THEN 3 ELSE 0 END AS `col` FROM `default_cluster:test`.`baseall`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql15Stmt.toSql(), "SELECT CASE WHEN CASE WHEN substr(`k7`, 2, 1) THEN TRUE ELSE FALSE END THEN 2 WHEN FALSE THEN 3 ELSE 0 END AS `col` FROM `default_cluster:test`.`baseall`")); + + // 1.6 test when expr is null + String sql16 = "select case when null then 1 else 2 end as col16;"; + SelectStmt sql16Stmt = getAnalyzedAndRewritedStmt(sql16); + System.out.println(sql16Stmt.toSql()); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql16Stmt.toSql(), "select 2 AS `col16`")); // test 2: case xxx when then // 2.1 test equal String sql2 = "select case 1 when 1 then 'a' when 2 then 'b' else 'other' end as col2;"; SelectStmt sql2Stmt = getAnalyzedAndRewritedStmt(sql2); - Assert.assertTrue(sql2Stmt.toSql().equals("SELECT 'a' AS `col2`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql2Stmt.toSql(), ("SELECT 'a' AS `col2`"))); // 2.1.2 test not equal String sql212 = "select case 'a' when 1 then 'a' when 'a' then 'b' else 'other' end as col212;"; SelectStmt sql212Stmt = getAnalyzedAndRewritedStmt(sql212); - Assert.assertTrue(sql212Stmt.toSql().equals("SELECT 'other' AS `col212`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql212Stmt.toSql(), "SELECT 'b' AS `col212`")); // 2.2 test return null String sql22 = "select case 'a' when 1 then 'a' when 'b' then 'b' end as col22;"; SelectStmt sql22Stmt = getAnalyzedAndRewritedStmt(sql22); - Assert.assertTrue(sql22Stmt.toSql().equals("SELECT NULL AS `col22`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql22Stmt.toSql(), "SELECT NULL AS `col22`")); // 2.2.2 test return else String sql222 = "select case 1 when 2 then 'a' when 3 then 'b' else 'other' end as col222;"; SelectStmt sql222Stmt = getAnalyzedAndRewritedStmt(sql222); - Assert.assertTrue(sql222Stmt.toSql().equals("SELECT 'other' AS `col222`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql222Stmt.toSql(), "SELECT 'other' AS `col222`")); // 2.3 test can not convert to constant,middle when expr is not constant - String sql23 = "select case 'a' when 1 then 'a' when substr(k7,2,1) then 2 when false then 3 else 0 end as col23 from test.baseall"; + String sql23 = "select case 'a' when 'b' then 'a' when substr(k7,2,1) then 2 when false then 3 else 0 end as col23 from test.baseall"; SelectStmt sql23Stmt = getAnalyzedAndRewritedStmt(sql23); - Assert.assertTrue(sql23Stmt.toSql().equals("SELECT CASE'a' WHEN substr(`k7`, 2, 1) THEN '2' WHEN '0' THEN '3' ELSE '0' END AS `col23` FROM `default_cluster:test`.`baseall`")); + // here 1 is casted to string ,so 1 is evaluated + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql23Stmt.toSql(), "SELECT CASE'a' WHEN substr(`k7`, 2, 1) THEN '2' WHEN '0' THEN '3' ELSE '0' END AS `col23` FROM `default_cluster:test`.`baseall`")); // 2.3.1 first when expr is not constant String sql231 = "select case 'a' when substr(k7,2,1) then 2 when 1 then 'a' when false then 3 else 0 end as col231 from test.baseall"; SelectStmt sql231Stmt = getAnalyzedAndRewritedStmt(sql231); - Assert.assertTrue(sql231Stmt.toSql().equals("SELECT CASE'a' WHEN substr(`k7`, 2, 1) THEN '2' WHEN '1' THEN 'a' WHEN '0' THEN '3' ELSE '0' END AS `col231` FROM `default_cluster:test`.`baseall`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql231Stmt.toSql(), "SELECT CASE'a' WHEN substr(`k7`, 2, 1) THEN '2' WHEN '1' THEN 'a' WHEN '0' THEN '3' ELSE '0' END AS `col231` FROM `default_cluster:test`.`baseall`")); // 2.3.2 case expr is not constant String sql232 = "select case k1 when substr(k7,2,1) then 2 when 1 then 'a' when false then 3 else 0 end as col232 from test.baseall"; SelectStmt sql232Stmt = getAnalyzedAndRewritedStmt(sql232); - Assert.assertTrue(sql232Stmt.toSql().equals("SELECT CASE`k1` WHEN substr(`k7`, 2, 1) THEN '2' WHEN '1' THEN 'a' WHEN '0' THEN '3' ELSE '0' END AS `col232` FROM `default_cluster:test`.`baseall`")); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql232Stmt.toSql(), "SELECT CASE`k1` WHEN substr(`k7`, 2, 1) THEN '2' WHEN '1' THEN 'a' WHEN '0' THEN '3' ELSE '0' END AS `col232` FROM `default_cluster:test`.`baseall`")); // 3.1 test float,float in case expr String sql31 = "select case cast(100 as float) when 1 then 'a' when 2 then 'b' else 'other' end as col31;"; SelectStmt sql31Stmt = getAnalyzedAndRewritedStmt(sql31); - Assert.assertTrue(sql31Stmt.toSql().equals("SELECT CASE100.0 WHEN 1.0 THEN 'a' WHEN 2.0 THEN 'b' ELSE 'other' END AS `col31`")); - + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql31Stmt.toSql(), "SELECT CASE100.0 WHEN 1.0 THEN 'a' WHEN 2.0 THEN 'b' ELSE 'other' END AS `col31`")); + + // 4.1 test null in case expr return else + String sql41 = "select case null when 1 then 'a' when 2 then 'b' else 'other' end as col41"; + SelectStmt sql41Stmt = getAnalyzedAndRewritedStmt(sql41); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql41Stmt.toSql(), "SELECT 'other' AS `col41`")); + + // 4.1.2 test null in case expr return null + String sql412 = "select case null when 1 then 'a' when 2 then 'b' end as col41"; + SelectStmt sql412Stmt = getAnalyzedAndRewritedStmt(sql412); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql412Stmt.toSql(), "SELECT NULL AS `col41`")); + + // 4.2.1 test null in when expr + String sql421 = "select case 'a' when null then 'a' else 'other' end as col421"; + SelectStmt sql421Stmt = getAnalyzedAndRewritedStmt(sql421); + Assert.assertTrue(StringUtils.equalsIgnoreCase(sql421Stmt.toSql(), "SELECT 'other' as `col421`")); } + } From 1d18a2f6c6248ef6c0282bb60a3daab3e113599a Mon Sep 17 00:00:00 2001 From: wangbo <506340561@qq.com> Date: Sat, 2 May 2020 16:10:43 +0800 Subject: [PATCH 5/7] 1 use UtFrameUtils.getSQLPlanOrErrorMsg to check plan 2 clone a new expr when return CaseExpr which has been changed --- .../org/apache/doris/analysis/CaseExpr.java | 7 +- .../apache/doris/planner/QueryPlanTest.java | 88 +++++++------------ 2 files changed, 34 insertions(+), 61 deletions(-) diff --git a/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java b/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java index 27c4a438d88e16..b3dab983e3c948 100644 --- a/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java +++ b/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java @@ -321,9 +321,10 @@ public static Expr computeCaseExpr(CaseExpr expr) { for (int j = i; j < expr.getChildren().size(); j++) { exprLeft.add(expr.getChild(j)); } - expr.getChildren().clear(); - expr.addChildren(exprLeft); - return expr; + Expr retCaseExpr = expr.clone(); + retCaseExpr.getChildren().clear(); + retCaseExpr.addChildren(exprLeft); + return retCaseExpr; } else if (caseExpr.compareLiteral((LiteralExpr) currentWhenExpr) == 0) { return expr.getChild(i + 1); } diff --git a/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java b/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java index cd767f56327163..fc6b8b06a962dc 100644 --- a/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java +++ b/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java @@ -506,14 +506,6 @@ public void testDateTypeEquality() throws Exception { System.currentTimeMillis()); } - private SelectStmt getAnalyzedAndRewritedStmt(String sql) throws Exception { - SelectStmt selectStmt = - (SelectStmt) UtFrameUtils.parseAndAnalyzeStmt(sql, connectContext); - selectStmt = (SelectStmt) UtFrameUtils.rewriteStmt(selectStmt, connectContext); - selectStmt = (SelectStmt) UtFrameUtils.reAnalyze(selectStmt, connectContext); - return selectStmt; - } - @Test public void testConvertCaseWhenToConstant() throws Exception { // basic test @@ -521,117 +513,97 @@ public void testConvertCaseWhenToConstant() throws Exception { + "case when date_format(now(),'%H%i') < 123 then 1 else 0 end as col " + "from test.test1 " + "where time = case when date_format(now(),'%H%i') < 123 then date_format(date_sub(now(),2),'%Y%m%d') else date_format(date_sub(now(),1),'%Y%m%d') end"; - SelectStmt selectStmt = getAnalyzedAndRewritedStmt(caseWhenSql); - Assert.assertTrue(!StringUtils.containsIgnoreCase(selectStmt.toSql(),"CASE WHEN") && !StringUtils.containsIgnoreCase(selectStmt.toSql(), "case when")); + Assert.assertTrue(!StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + caseWhenSql), "CASE WHEN")); // test 1: case when then // 1.1 multi when in on `case when` and can be converted to constants String sql11 = "select case when false then 2 when true then 3 else 0 end as col11;"; - SelectStmt sql11Stmt = getAnalyzedAndRewritedStmt(sql11); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql11Stmt.toSql(), "SELECT 3 AS `col11`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql11), "constant exprs: \n 3")); // 1.2 multi `when expr` in on `case when` ,`when expr` can not be converted to constants String sql121 = "select case when false then 2 when substr(k7,2,1) then 3 else 0 end as col121 from test.baseall"; - SelectStmt sqlStmt121 = getAnalyzedAndRewritedStmt(sql121); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sqlStmt121.toSql(),"SELECT CASE WHEN substr(`k7`, 2, 1) THEN 3 ELSE 0 END AS `col121` FROM `default_cluster:test`.`baseall`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql121), + "OUTPUT EXPRS:CASE WHEN substr(`k7`, 2, 1) THEN 3 ELSE 0 END")); // 1.2.2 when expr which can not be converted to constants in the first String sql122 = "select case when substr(k7,2,1) then 2 when false then 3 else 0 end as col122 from test.baseall"; - SelectStmt sqlStmt122 = getAnalyzedAndRewritedStmt(sql122); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sqlStmt122.toSql(), "SELECT CASE WHEN substr(`k7`, 2, 1) THEN 2 WHEN FALSE THEN 3 ELSE 0 END AS `col122` FROM `default_cluster:test`.`baseall`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql122), + "OUTPUT EXPRS:CASE WHEN substr(`k7`, 2, 1) THEN 2 WHEN FALSE THEN 3 ELSE 0 END")); - // 1.2.3 when expr which can not be converted to constants in the middle - String sql123 = "select case when false then 2 when substr(k7,2,1) then 3 else 0 end as col123 from test.baseall"; - SelectStmt sqlStmt123 = getAnalyzedAndRewritedStmt(sql123); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sqlStmt123.toSql(), "SELECT CASE WHEN substr(`k7`, 2, 1) THEN 3 ELSE 0 END AS `col123` FROM `default_cluster:test`.`baseall`")); - - // 1.2.4 test return `then expr` in the middle + // 1.2.3 test return `then expr` in the middle String sql124 = "select case when false then 1 when true then 2 when false then 3 else 'other' end as col124"; - SelectStmt sql124Stmt = getAnalyzedAndRewritedStmt(sql124); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql124Stmt.toSql(), "SELECT '2' AS `col124`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql124), "constant exprs: \n '2'")); // 1.3 test return null String sql3 = "select case when false then 2 end as col3"; - SelectStmt sql3Stmt = getAnalyzedAndRewritedStmt(sql3); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql3Stmt.toSql(), "SELECT NULL AS `col3`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql3), "constant exprs: \n NULL")); // 1.3.1 test return else expr String sql131 = "select case when false then 2 when false then 3 else 4 end as col131"; - SelectStmt sql131Stmt = getAnalyzedAndRewritedStmt(sql131); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql131Stmt.toSql(), "SELECT 4 AS `col131`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql131), "constant exprs: \n 4")); // 1.4 nest `case when` and can be converted to constants String sql14 = "select case when (case when true then true else false end) then 2 when false then 3 else 0 end as col"; - SelectStmt sql14Stmt = getAnalyzedAndRewritedStmt(sql14); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql14Stmt.toSql(), "SELECT 2 AS `col`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql14), "constant exprs: \n 2")); // 1.5 nest `case when` and can not be converted to constants String sql15 = "select case when case when substr(k7,2,1) then true else false end then 2 when false then 3 else 0 end as col from test.baseall"; - SelectStmt sql15Stmt = getAnalyzedAndRewritedStmt(sql15); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql15Stmt.toSql(), "SELECT CASE WHEN CASE WHEN substr(`k7`, 2, 1) THEN TRUE ELSE FALSE END THEN 2 WHEN FALSE THEN 3 ELSE 0 END AS `col` FROM `default_cluster:test`.`baseall`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql15), + "OUTPUT EXPRS:CASE WHEN CASE WHEN substr(`k7`, 2, 1) THEN TRUE ELSE FALSE END THEN 2 WHEN FALSE THEN 3 ELSE 0 END")); // 1.6 test when expr is null String sql16 = "select case when null then 1 else 2 end as col16;"; - SelectStmt sql16Stmt = getAnalyzedAndRewritedStmt(sql16); - System.out.println(sql16Stmt.toSql()); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql16Stmt.toSql(), "select 2 AS `col16`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql16), "constant exprs: \n 2")); // test 2: case xxx when then // 2.1 test equal String sql2 = "select case 1 when 1 then 'a' when 2 then 'b' else 'other' end as col2;"; - SelectStmt sql2Stmt = getAnalyzedAndRewritedStmt(sql2); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql2Stmt.toSql(), ("SELECT 'a' AS `col2`"))); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql2), "constant exprs: \n 'a'")); // 2.1.2 test not equal String sql212 = "select case 'a' when 1 then 'a' when 'a' then 'b' else 'other' end as col212;"; - SelectStmt sql212Stmt = getAnalyzedAndRewritedStmt(sql212); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql212Stmt.toSql(), "SELECT 'b' AS `col212`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql212), "constant exprs: \n 'b'")); // 2.2 test return null String sql22 = "select case 'a' when 1 then 'a' when 'b' then 'b' end as col22;"; - SelectStmt sql22Stmt = getAnalyzedAndRewritedStmt(sql22); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql22Stmt.toSql(), "SELECT NULL AS `col22`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql22), "constant exprs: \n NULL")); // 2.2.2 test return else String sql222 = "select case 1 when 2 then 'a' when 3 then 'b' else 'other' end as col222;"; - SelectStmt sql222Stmt = getAnalyzedAndRewritedStmt(sql222); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql222Stmt.toSql(), "SELECT 'other' AS `col222`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql222), "constant exprs: \n 'other'")); // 2.3 test can not convert to constant,middle when expr is not constant String sql23 = "select case 'a' when 'b' then 'a' when substr(k7,2,1) then 2 when false then 3 else 0 end as col23 from test.baseall"; - SelectStmt sql23Stmt = getAnalyzedAndRewritedStmt(sql23); - // here 1 is casted to string ,so 1 is evaluated - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql23Stmt.toSql(), "SELECT CASE'a' WHEN substr(`k7`, 2, 1) THEN '2' WHEN '0' THEN '3' ELSE '0' END AS `col23` FROM `default_cluster:test`.`baseall`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql23), + "OUTPUT EXPRS:CASE'a' WHEN substr(`k7`, 2, 1) THEN '2' WHEN '0' THEN '3' ELSE '0' END")); // 2.3.1 first when expr is not constant String sql231 = "select case 'a' when substr(k7,2,1) then 2 when 1 then 'a' when false then 3 else 0 end as col231 from test.baseall"; - SelectStmt sql231Stmt = getAnalyzedAndRewritedStmt(sql231); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql231Stmt.toSql(), "SELECT CASE'a' WHEN substr(`k7`, 2, 1) THEN '2' WHEN '1' THEN 'a' WHEN '0' THEN '3' ELSE '0' END AS `col231` FROM `default_cluster:test`.`baseall`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql231), + "OUTPUT EXPRS:CASE'a' WHEN substr(`k7`, 2, 1) THEN '2' WHEN '1' THEN 'a' WHEN '0' THEN '3' ELSE '0' END")); // 2.3.2 case expr is not constant String sql232 = "select case k1 when substr(k7,2,1) then 2 when 1 then 'a' when false then 3 else 0 end as col232 from test.baseall"; - SelectStmt sql232Stmt = getAnalyzedAndRewritedStmt(sql232); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql232Stmt.toSql(), "SELECT CASE`k1` WHEN substr(`k7`, 2, 1) THEN '2' WHEN '1' THEN 'a' WHEN '0' THEN '3' ELSE '0' END AS `col232` FROM `default_cluster:test`.`baseall`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql232), + "OUTPUT EXPRS:CASE`k1` WHEN substr(`k7`, 2, 1) THEN '2' WHEN '1' THEN 'a' WHEN '0' THEN '3' ELSE '0' END")); // 3.1 test float,float in case expr String sql31 = "select case cast(100 as float) when 1 then 'a' when 2 then 'b' else 'other' end as col31;"; - SelectStmt sql31Stmt = getAnalyzedAndRewritedStmt(sql31); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql31Stmt.toSql(), "SELECT CASE100.0 WHEN 1.0 THEN 'a' WHEN 2.0 THEN 'b' ELSE 'other' END AS `col31`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql31), + "constant exprs: \n CASE100.0 WHEN 1.0 THEN 'a' WHEN 2.0 THEN 'b' ELSE 'other' END")); // 4.1 test null in case expr return else String sql41 = "select case null when 1 then 'a' when 2 then 'b' else 'other' end as col41"; - SelectStmt sql41Stmt = getAnalyzedAndRewritedStmt(sql41); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql41Stmt.toSql(), "SELECT 'other' AS `col41`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql41), "constant exprs: \n 'other'")); // 4.1.2 test null in case expr return null String sql412 = "select case null when 1 then 'a' when 2 then 'b' end as col41"; - SelectStmt sql412Stmt = getAnalyzedAndRewritedStmt(sql412); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql412Stmt.toSql(), "SELECT NULL AS `col41`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql412), "constant exprs: \n NULL")); // 4.2.1 test null in when expr String sql421 = "select case 'a' when null then 'a' else 'other' end as col421"; - SelectStmt sql421Stmt = getAnalyzedAndRewritedStmt(sql421); - Assert.assertTrue(StringUtils.equalsIgnoreCase(sql421Stmt.toSql(), "SELECT 'other' as `col421`")); + Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql421), "constant exprs: \n 'other'")); } + } From 4d3c68150326899cbe562a45ccb33b65ff6bbb05 Mon Sep 17 00:00:00 2001 From: wangbo <506340561@qq.com> Date: Sun, 3 May 2020 13:34:09 +0800 Subject: [PATCH 6/7] remove useless method --- .../org/apache/doris/analysis/CaseExpr.java | 4 --- .../apache/doris/utframe/UtFrameUtils.java | 32 ------------------- 2 files changed, 36 deletions(-) diff --git a/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java b/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java index b3dab983e3c948..ffe0d880e5f7a2 100644 --- a/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java +++ b/fe/src/main/java/org/apache/doris/analysis/CaseExpr.java @@ -107,10 +107,6 @@ public boolean hasCaseExpr() { return hasCaseExpr; } - public boolean hasElseExpr() { - return hasCaseExpr; - } - @Override public String toSqlImpl() { StringBuilder output = new StringBuilder("CASE"); diff --git a/fe/src/test/java/org/apache/doris/utframe/UtFrameUtils.java b/fe/src/test/java/org/apache/doris/utframe/UtFrameUtils.java index 66f10aff261a69..ac538e7324b055 100644 --- a/fe/src/test/java/org/apache/doris/utframe/UtFrameUtils.java +++ b/fe/src/test/java/org/apache/doris/utframe/UtFrameUtils.java @@ -18,25 +18,21 @@ package org.apache.doris.utframe; import org.apache.doris.analysis.Analyzer; -import org.apache.doris.analysis.Expr; import org.apache.doris.analysis.SqlParser; import org.apache.doris.analysis.SqlScanner; import org.apache.doris.analysis.StatementBase; import org.apache.doris.analysis.UserIdentity; import org.apache.doris.catalog.Catalog; -import org.apache.doris.catalog.Type; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.Config; import org.apache.doris.common.DdlException; import org.apache.doris.common.Pair; -import org.apache.doris.common.UserException; import org.apache.doris.common.util.SqlParserUtils; import org.apache.doris.mysql.privilege.PaloAuth; import org.apache.doris.planner.Planner; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.QueryState; import org.apache.doris.qe.StmtExecutor; -import org.apache.doris.rewrite.ExprRewriter; import org.apache.doris.system.SystemInfoService; import org.apache.doris.thrift.TExplainLevel; import org.apache.doris.thrift.TNetworkAddress; @@ -100,34 +96,6 @@ public static StatementBase parseAndAnalyzeStmt(String originStmt, ConnectContex return statementBase; } - public static StatementBase rewriteStmt(StatementBase stmt, ConnectContext ctx) throws AnalysisException { - Analyzer analyzer = new Analyzer(ctx.getCatalog(), ctx); - ExprRewriter rewriter = analyzer.getExprRewriter(); - rewriter.reset(); - stmt.rewriteExprs(rewriter); - return stmt; - } - - public static StatementBase reAnalyze(StatementBase stmt, ConnectContext ctx) throws UserException { - Analyzer analyzer = new Analyzer(ctx.getCatalog(), ctx); - List origResultTypes = Lists.newArrayList(); - for (Expr e: stmt.getResultExprs()) { - origResultTypes.add(e.getType()); - } - List origColLabels = - Lists.newArrayList(stmt.getColLabels()); - - // Re-analyze the stmt with a new analyzer. - // query re-analyze - stmt.reset(); - stmt.analyze(analyzer); - - // Restore the original result types and column labels. - stmt.castResultExprs(origResultTypes); - stmt.setColLabels(origColLabels); - return stmt; - } - // for analyzing multi statements public static List parseAndAnalyzeStmts(String originStmt, ConnectContext ctx) throws Exception { System.out.println("begin to parse stmts: " + originStmt); From 44b7602417d3cd825caa356767f266352060339c Mon Sep 17 00:00:00 2001 From: wangbo <506340561@qq.com> Date: Sun, 3 May 2020 16:24:08 +0800 Subject: [PATCH 7/7] [UT] Fix UT bug (#3456) SSD cool downtime shouldn't be fix time in UT; --- .../java/org/apache/doris/common/PropertyAnalyzerTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fe/src/test/java/org/apache/doris/common/PropertyAnalyzerTest.java b/fe/src/test/java/org/apache/doris/common/PropertyAnalyzerTest.java index 9ff9e6fc05c415..48e0d7b44b19aa 100644 --- a/fe/src/test/java/org/apache/doris/common/PropertyAnalyzerTest.java +++ b/fe/src/test/java/org/apache/doris/common/PropertyAnalyzerTest.java @@ -32,6 +32,7 @@ import org.junit.Assert; import org.junit.Test; +import java.text.SimpleDateFormat; import java.util.List; import java.util.Map; import java.util.Set; @@ -120,10 +121,12 @@ public void testBfFpp() throws AnalysisException { @Test public void testStorageMedium() throws AnalysisException { + long tomorrowTs = System.currentTimeMillis() / 1000 + 86400; + Map properties = Maps.newHashMap(); properties.put(PropertyAnalyzer.PROPERTIES_STORAGE_MEDIUM, "SSD"); - properties.put(PropertyAnalyzer.PROPERTIES_STORAGE_COLDOWN_TIME, "2020-05-01 00:00:00"); + properties.put(PropertyAnalyzer.PROPERTIES_STORAGE_COLDOWN_TIME, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(tomorrowTs * 1000)); DataProperty dataProperty = PropertyAnalyzer.analyzeDataProperty(properties, new DataProperty(TStorageMedium.SSD)); - Assert.assertEquals(1588262400, dataProperty.getCooldownTimeMs() / 1000); + Assert.assertEquals(tomorrowTs, dataProperty.getCooldownTimeMs() / 1000); } }