From dee79d98a82cb29adac066a173c6cb8808c2dfbe Mon Sep 17 00:00:00 2001 From: zhengshiJ <32082872+zhengshiJ@users.noreply.github.com> Date: Thu, 27 Jan 2022 10:37:38 +0800 Subject: [PATCH] [improvement](explain) Displays cast information with implicit conversions in verbose (#7851) Displays cast information with implicit conversions in verbose. --- .../org/apache/doris/analysis/CastExpr.java | 16 +++ .../org/apache/doris/qe/StmtExecutor.java | 8 ++ .../apache/doris/analysis/ExplainTest.java | 120 ++++++++++++++++++ .../apache/doris/planner/QueryPlanTest.java | 4 +- .../apache/doris/utframe/UtFrameUtils.java | 2 + 5 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 fe/fe-core/src/test/java/org/apache/doris/analysis/ExplainTest.java diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CastExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CastExpr.java index 2a629f9f69..0f18a02269 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CastExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CastExpr.java @@ -33,6 +33,7 @@ import org.apache.doris.catalog.ScalarType; import org.apache.doris.catalog.Type; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.Pair; +import org.apache.doris.qe.ConnectContext; import org.apache.doris.thrift.TExpr; import org.apache.doris.thrift.TExprNode; import org.apache.doris.thrift.TExprNodeType; @@ -177,6 +178,21 @@ public class CastExpr extends Expr { @Override public String toSqlImpl() { + if (ConnectContext.get() != null && + ConnectContext.get().getExecutor() != null && + ConnectContext.get().getExecutor().getParsedStmt() != null && + ConnectContext.get().getExecutor().getParsedStmt().getExplainOptions() != null && + ConnectContext.get().getExecutor().getParsedStmt().getExplainOptions().isVerbose()) { + if (isAnalyzed) { + if (type.isStringType()) { + return "CAST(" + getChild(0).toSql() + " AS " + "CHARACTER" + ")"; + } else { + return "CAST(" + getChild(0).toSql() + " AS " + type.toString() + ")"; + } + } else { + return "CAST(" + getChild(0).toSql() + " AS " + targetTypeDef.toSql() + ")"; + } + } if (isImplicit) { return getChild(0).toSql(); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java index 37c188377e..fce94aa8ba 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java @@ -676,6 +676,14 @@ public class StmtExecutor implements ProfileWriter { } if (explainOptions != null) parsedStmt.setIsExplain(explainOptions); } + + if (parsedStmt instanceof InsertStmt && parsedStmt.isExplain()) { + if (ConnectContext.get() != null && + ConnectContext.get().getExecutor() != null && + ConnectContext.get().getExecutor().getParsedStmt() != null) { + ConnectContext.get().getExecutor().getParsedStmt().setIsExplain(new ExplainOptions(true, false)); + } + } } plannerProfile.setQueryAnalysisFinishTime(); diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/ExplainTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/ExplainTest.java new file mode 100644 index 0000000000..a78cfd7152 --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/ExplainTest.java @@ -0,0 +1,120 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.analysis; + +import org.apache.doris.catalog.Catalog; +import org.apache.doris.qe.ConnectContext; +import org.apache.doris.utframe.UtFrameUtils; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.UUID; + + +public class ExplainTest { + private static String runningDir = "fe/mocked/TableFunctionPlanTest/" + UUID.randomUUID().toString() + "/"; + private static ConnectContext ctx; + + + @BeforeClass + public static void beforeClass() throws Exception { + UtFrameUtils.createDorisCluster(runningDir); + ctx = UtFrameUtils.createDefaultCtx(); + String createDbStmtStr = "create database test;"; + CreateDbStmt createDbStmt = (CreateDbStmt) UtFrameUtils.parseAndAnalyzeStmt(createDbStmtStr, ctx); + Catalog.getCurrentCatalog().createDb(createDbStmt); + + String t1 =("CREATE TABLE test.t1 (\n" + + " `dt` int(11) COMMENT \"\",\n" + + " `id` int(11) COMMENT \"\",\n" + + " `value` varchar(8) COMMENT \"\"\n" + + ") ENGINE=OLAP\n" + + "DUPLICATE KEY(`dt`, `id`)\n" + + "PARTITION BY RANGE(`dt`)\n" + + "(PARTITION p1 VALUES LESS THAN (\"10\"))\n" + + "DISTRIBUTED BY HASH(`id`) BUCKETS 10\n" + + "PROPERTIES (\n" + + " \"replication_num\" = \"1\"\n" + + ");"); + CreateTableStmt createTableStmt = (CreateTableStmt) UtFrameUtils.parseAndAnalyzeStmt(t1, ctx); + Catalog.getCurrentCatalog().createTable(createTableStmt); + + String t2 =("CREATE TABLE test.t2 (\n" + + " `dt` bigint(11) COMMENT \"\",\n" + + " `id` bigint(11) COMMENT \"\",\n" + + " `value` bigint(8) COMMENT \"\"\n" + + ") ENGINE=OLAP\n" + + "DUPLICATE KEY(`dt`, `id`)\n" + + "PARTITION BY RANGE(`dt`)\n" + + "(PARTITION p1 VALUES LESS THAN (\"10\"))\n" + + "DISTRIBUTED BY HASH(`id`) BUCKETS 10\n" + + "PROPERTIES (\n" + + " \"replication_num\" = \"1\"\n" + + ");"); + createTableStmt = (CreateTableStmt) UtFrameUtils.parseAndAnalyzeStmt(t2, ctx); + Catalog.getCurrentCatalog().createTable(createTableStmt); + + } + + @AfterClass + public static void tearDown() { + UtFrameUtils.cleanDorisFeDir(runningDir); + } + + @Test + public void testExplainInsertInto() throws Exception { + String sql = "explain insert into test.t1 select * from test.t2"; + String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(ctx, sql, true); + System.out.println(explainString); + Assert.assertTrue(explainString.contains("CAST")); + } + + @Test + public void testExplainSelect() throws Exception { + String sql = "explain select * from test.t1 where dt = '1001';"; + String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(ctx, sql, false); + System.out.println(explainString); + Assert.assertFalse(explainString.contains("CAST")); + } + + @Test + public void testExplainVerboseSelect() throws Exception { + String queryStr = "explain verbose select * from test.t1 where dt = '1001';"; + String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(ctx, queryStr, true); + System.out.println(explainString); + Assert.assertTrue(explainString.contains("CAST")); + } + + @Test + public void testExplainConcatSelect() throws Exception { + String sql = "explain select concat(dt, id) from test.t1;"; + String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(ctx, sql, false); + System.out.println(explainString); + Assert.assertFalse(explainString.contains("CAST")); + } + + @Test + public void testExplainVerboseConcatSelect() throws Exception { + String sql = "explain verbose select concat(dt, id) from test.t1;"; + String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(ctx, sql, true); + System.out.println(explainString); + Assert.assertTrue(explainString.contains("CAST")); + } +} diff --git a/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java b/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java index 6323f6ee5e..5df684bea1 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java @@ -453,13 +453,13 @@ public class QueryPlanTest { queryStr = "explain insert into test.bitmap_table select id, to_bitmap(id2) from test.bitmap_table_2;"; explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr); Assert.assertTrue(explainString.contains("OLAP TABLE SINK")); - Assert.assertTrue(explainString.contains("OUTPUT EXPRS:`id` | to_bitmap(`id2`)")); + Assert.assertTrue(explainString.contains("OUTPUT EXPRS:`id` | to_bitmap(CAST(`id2` AS CHARACTER))")); Assert.assertTrue(explainString.contains("0:OlapScanNode")); queryStr = "explain insert into test.bitmap_table select id, bitmap_hash(id2) from test.bitmap_table_2;"; explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr); Assert.assertTrue(explainString.contains("OLAP TABLE SINK")); - Assert.assertTrue(explainString.contains("OUTPUT EXPRS:`id` | bitmap_hash(`id2`)")); + Assert.assertTrue(explainString.contains("OUTPUT EXPRS:`id` | bitmap_hash(CAST(`id2` AS CHARACTER))")); Assert.assertTrue(explainString.contains("0:OlapScanNode")); queryStr = "explain insert into test.bitmap_table select id, id from test.bitmap_table_2;"; diff --git a/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java b/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java index 52c2d7345b..fc20d571bc 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java +++ b/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java @@ -252,6 +252,8 @@ public class UtFrameUtils { public static String getSQLPlanOrErrorMsg(ConnectContext ctx, String queryStr, boolean isVerbose) throws Exception { ctx.getState().reset(); StmtExecutor stmtExecutor = new StmtExecutor(ctx, queryStr); + ctx.setExecutor(stmtExecutor); + ConnectContext.get().setExecutor(stmtExecutor); stmtExecutor.execute(); if (ctx.getState().getStateType() != QueryState.MysqlStateType.ERR) { Planner planner = stmtExecutor.planner();