blob: e1bc9d3b89da74cb1a1b787b0c976e756e5704f1 [file] [log] [blame]
// 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.planner;
import org.apache.doris.analysis.Analyzer;
import org.apache.doris.analysis.CreateDbStmt;
import org.apache.doris.analysis.CreateTableStmt;
import org.apache.doris.analysis.DropDbStmt;
import org.apache.doris.analysis.Expr;
import org.apache.doris.analysis.InformationFunction;
import org.apache.doris.analysis.LoadStmt;
import org.apache.doris.analysis.SelectStmt;
import org.apache.doris.analysis.ShowCreateDbStmt;
import org.apache.doris.analysis.StatementBase;
import org.apache.doris.catalog.Catalog;
import org.apache.doris.catalog.Database;
import org.apache.doris.catalog.MaterializedIndex;
import org.apache.doris.catalog.MaterializedIndex.IndexExtState;
import org.apache.doris.catalog.OlapTable;
import org.apache.doris.catalog.Partition;
import org.apache.doris.catalog.Replica;
import org.apache.doris.catalog.Tablet;
import org.apache.doris.catalog.Type;
import org.apache.doris.common.FeConstants;
import org.apache.doris.common.jmockit.Deencapsulation;
import org.apache.doris.load.EtlJobType;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.QueryState.MysqlStateType;
import org.apache.doris.utframe.UtFrameUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import com.google.common.collect.Lists;
import java.io.File;
import java.util.List;
import java.util.UUID;
public class QueryPlanTest {
// use a unique dir so that it won't be conflict with other unit test which
// may also start a Mocked Frontend
private static String runningDir = "fe/mocked/QueryPlanTest/" + UUID.randomUUID().toString() + "/";
private static ConnectContext connectContext;
@BeforeClass
public static void beforeClass() throws Exception {
UtFrameUtils.createMinDorisCluster(runningDir);
// create connect context
connectContext = UtFrameUtils.createDefaultCtx();
// disable bucket shuffle join
Deencapsulation.setField(connectContext.getSessionVariable(), "enableBucketShuffleJoin", false);
// create database
String createDbStmtStr = "create database test;";
CreateDbStmt createDbStmt = (CreateDbStmt) UtFrameUtils.parseAndAnalyzeStmt(createDbStmtStr, connectContext);
Catalog.getCurrentCatalog().createDb(createDbStmt);
createTable("create table test.test1\n" +
"(\n" +
" query_id varchar(48) comment \"Unique query id\",\n" +
" time datetime not null comment \"Query start time\",\n" +
" client_ip varchar(32) comment \"Client IP\",\n" +
" user varchar(64) comment \"User name\",\n" +
" db varchar(96) comment \"Database of this query\",\n" +
" state varchar(8) comment \"Query result state. EOF, ERR, OK\",\n" +
" query_time bigint comment \"Query execution time in millisecond\",\n" +
" scan_bytes bigint comment \"Total scan bytes of this query\",\n" +
" scan_rows bigint comment \"Total scan rows of this query\",\n" +
" return_rows bigint comment \"Returned rows of this query\",\n" +
" stmt_id int comment \"An incremental id of statement\",\n" +
" is_query tinyint comment \"Is this statemt a query. 1 or 0\",\n" +
" frontend_ip varchar(32) comment \"Frontend ip of executing this statement\",\n" +
" stmt varchar(2048) comment \"The original statement, trimed if longer than 2048 bytes\"\n" +
")\n" +
"partition by range(time) ()\n" +
"distributed by hash(query_id) buckets 1\n" +
"properties(\n" +
" \"dynamic_partition.time_unit\" = \"DAY\",\n" +
" \"dynamic_partition.start\" = \"-30\",\n" +
" \"dynamic_partition.end\" = \"3\",\n" +
" \"dynamic_partition.prefix\" = \"p\",\n" +
" \"dynamic_partition.buckets\" = \"1\",\n" +
" \"dynamic_partition.enable\" = \"true\",\n" +
" \"replication_num\" = \"1\"\n" +
");");
createTable("CREATE TABLE test.bitmap_table (\n" +
" `id` int(11) NULL COMMENT \"\",\n" +
" `id2` bitmap bitmap_union NULL\n" +
") ENGINE=OLAP\n" +
"AGGREGATE KEY(`id`)\n" +
"DISTRIBUTED BY HASH(`id`) BUCKETS 1\n" +
"PROPERTIES (\n" +
" \"replication_num\" = \"1\"\n" +
");");
createTable("CREATE TABLE test.join1 (\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" +
");");
createTable("CREATE TABLE test.join2 (\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" +
");");
createTable("CREATE TABLE test.bitmap_table_2 (\n" +
" `id` int(11) NULL COMMENT \"\",\n" +
" `id2` bitmap bitmap_union NULL,\n" +
" `id3` bitmap bitmap_union NULL\n" +
") ENGINE=OLAP\n" +
"AGGREGATE KEY(`id`)\n" +
"DISTRIBUTED BY HASH(`id`) BUCKETS 1\n" +
"PROPERTIES (\n" +
" \"replication_num\" = \"1\"\n" +
");");
createTable("CREATE TABLE test.hll_table (\n" +
" `id` int(11) NULL COMMENT \"\",\n" +
" `id2` hll hll_union NULL\n" +
") ENGINE=OLAP\n" +
"AGGREGATE KEY(`id`)\n" +
"DISTRIBUTED BY HASH(`id`) BUCKETS 1\n" +
"PROPERTIES (\n" +
" \"replication_num\" = \"1\"\n" +
");");
createTable("CREATE TABLE test.`bigtable` (\n" +
" `k1` tinyint(4) NULL COMMENT \"\",\n" +
" `k2` smallint(6) NULL COMMENT \"\",\n" +
" `k3` int(11) NULL COMMENT \"\",\n" +
" `k4` bigint(20) NULL COMMENT \"\",\n" +
" `k5` decimal(9, 3) NULL COMMENT \"\",\n" +
" `k6` char(5) NULL COMMENT \"\",\n" +
" `k10` date NULL COMMENT \"\",\n" +
" `k11` datetime NULL COMMENT \"\",\n" +
" `k7` varchar(20) NULL COMMENT \"\",\n" +
" `k8` double MAX NULL COMMENT \"\",\n" +
" `k9` float SUM NULL COMMENT \"\"\n" +
") ENGINE=OLAP\n" +
"AGGREGATE KEY(`k1`, `k2`, `k3`, `k4`, `k5`, `k6`, `k10`, `k11`, `k7`)\n" +
"COMMENT \"OLAP\"\n" +
"DISTRIBUTED BY HASH(`k1`) BUCKETS 5\n" +
"PROPERTIES (\n" +
"\"replication_num\" = \"1\"\n" +
");");
createTable("CREATE TABLE test.`baseall` (\n" +
" `k1` tinyint(4) NULL COMMENT \"\",\n" +
" `k2` smallint(6) NULL COMMENT \"\",\n" +
" `k3` int(11) NULL COMMENT \"\",\n" +
" `k4` bigint(20) NULL COMMENT \"\",\n" +
" `k5` decimal(9, 3) NULL COMMENT \"\",\n" +
" `k6` char(5) NULL COMMENT \"\",\n" +
" `k10` date NULL COMMENT \"\",\n" +
" `k11` datetime NULL COMMENT \"\",\n" +
" `k7` varchar(20) NULL COMMENT \"\",\n" +
" `k8` double MAX NULL COMMENT \"\",\n" +
" `k9` float SUM NULL COMMENT \"\"\n" +
") ENGINE=OLAP\n" +
"AGGREGATE KEY(`k1`, `k2`, `k3`, `k4`, `k5`, `k6`, `k10`, `k11`, `k7`)\n" +
"COMMENT \"OLAP\"\n" +
"DISTRIBUTED BY HASH(`k1`) BUCKETS 5\n" +
"PROPERTIES (\n" +
"\"replication_num\" = \"1\"\n" +
");");
createTable("CREATE TABLE test.`dynamic_partition` (\n" +
" `k1` date NULL COMMENT \"\",\n" +
" `k2` smallint(6) NULL COMMENT \"\",\n" +
" `k3` int(11) NULL COMMENT \"\",\n" +
" `k4` bigint(20) NULL COMMENT \"\",\n" +
" `k5` decimal(9, 3) NULL COMMENT \"\",\n" +
" `k6` char(5) NULL COMMENT \"\",\n" +
" `k10` date NULL COMMENT \"\",\n" +
" `k11` datetime NULL COMMENT \"\",\n" +
" `k7` varchar(20) NULL COMMENT \"\",\n" +
" `k8` double MAX NULL COMMENT \"\",\n" +
" `k9` float SUM NULL COMMENT \"\"\n" +
") ENGINE=OLAP\n" +
"AGGREGATE KEY(`k1`, `k2`, `k3`, `k4`, `k5`, `k6`, `k10`, `k11`, `k7`)\n" +
"COMMENT \"OLAP\"\n" +
"PARTITION BY RANGE (k1)\n" +
"(\n" +
"PARTITION p1 VALUES LESS THAN (\"2014-01-01\"),\n" +
"PARTITION p2 VALUES LESS THAN (\"2014-06-01\"),\n" +
"PARTITION p3 VALUES LESS THAN (\"2014-12-01\")\n" +
")\n" +
"DISTRIBUTED BY HASH(`k1`) BUCKETS 5\n" +
"PROPERTIES (\n" +
"\"replication_num\" = \"1\",\n" +
"\"dynamic_partition.enable\" = \"true\",\n" +
"\"dynamic_partition.start\" = \"-3\",\n" +
"\"dynamic_partition.end\" = \"3\",\n" +
"\"dynamic_partition.time_unit\" = \"day\",\n" +
"\"dynamic_partition.prefix\" = \"p\",\n" +
"\"dynamic_partition.buckets\" = \"1\"\n" +
");");
createTable("CREATE TABLE test.`app_profile` (\n" +
" `event_date` date NOT NULL COMMENT \"\",\n" +
" `app_name` varchar(64) NOT NULL COMMENT \"\",\n" +
" `package_name` varchar(64) NOT NULL COMMENT \"\",\n" +
" `age` varchar(32) NOT NULL COMMENT \"\",\n" +
" `gender` varchar(32) NOT NULL COMMENT \"\",\n" +
" `level` varchar(64) NOT NULL COMMENT \"\",\n" +
" `city` varchar(64) NOT NULL COMMENT \"\",\n" +
" `model` varchar(64) NOT NULL COMMENT \"\",\n" +
" `brand` varchar(64) NOT NULL COMMENT \"\",\n" +
" `hours` varchar(16) NOT NULL COMMENT \"\",\n" +
" `use_num` int(11) SUM NOT NULL COMMENT \"\",\n" +
" `use_time` double SUM NOT NULL COMMENT \"\",\n" +
" `start_times` bigint(20) SUM NOT NULL COMMENT \"\"\n" +
") ENGINE=OLAP\n" +
"AGGREGATE KEY(`event_date`, `app_name`, `package_name`, `age`, `gender`, `level`, `city`, `model`, `brand`, `hours`)\n"
+
"COMMENT \"OLAP\"\n" +
"PARTITION BY RANGE(`event_date`)\n" +
"(PARTITION p_20200301 VALUES [('2020-02-27'), ('2020-03-02')),\n" +
"PARTITION p_20200306 VALUES [('2020-03-02'), ('2020-03-07')))\n" +
"DISTRIBUTED BY HASH(`event_date`, `app_name`, `package_name`, `age`, `gender`, `level`, `city`, `model`, `brand`, `hours`) BUCKETS 1\n"
+
"PROPERTIES (\n" +
" \"replication_num\" = \"1\"\n" +
");");
createTable("CREATE TABLE test.`pushdown_test` (\n" +
" `k1` tinyint(4) NULL COMMENT \"\",\n" +
" `k2` smallint(6) NULL COMMENT \"\",\n" +
" `k3` int(11) NULL COMMENT \"\",\n" +
" `k4` bigint(20) NULL COMMENT \"\",\n" +
" `k5` decimal(9, 3) NULL COMMENT \"\",\n" +
" `k6` char(5) NULL COMMENT \"\",\n" +
" `k10` date NULL COMMENT \"\",\n" +
" `k11` datetime NULL COMMENT \"\",\n" +
" `k7` varchar(20) NULL COMMENT \"\",\n" +
" `k8` double MAX NULL COMMENT \"\",\n" +
" `k9` float SUM NULL COMMENT \"\"\n" +
") ENGINE=OLAP\n" +
"AGGREGATE KEY(`k1`, `k2`, `k3`, `k4`, `k5`, `k6`, `k10`, `k11`, `k7`)\n" +
"COMMENT \"OLAP\"\n" +
"PARTITION BY RANGE(`k1`)\n" +
"(PARTITION p1 VALUES [(\"-128\"), (\"-64\")),\n" +
"PARTITION p2 VALUES [(\"-64\"), (\"0\")),\n" +
"PARTITION p3 VALUES [(\"0\"), (\"64\")))\n" +
"DISTRIBUTED BY HASH(`k1`) BUCKETS 5\n" +
"PROPERTIES (\n" +
"\"replication_num\" = \"1\",\n" +
"\"in_memory\" = \"false\",\n" +
"\"storage_format\" = \"DEFAULT\"\n" +
");");
createTable("create table test.jointest\n" +
"(k1 int, k2 int) distributed by hash(k1) buckets 1\n" +
"properties(\"replication_num\" = \"1\");");
createTable("create table test.bucket_shuffle1\n" +
"(k1 int, k2 int, k3 int) distributed by hash(k1, k2) buckets 5\n" +
"properties(\"replication_num\" = \"1\"" +
");");
createTable("CREATE TABLE test.`bucket_shuffle2` (\n" +
" `k1` int NULL COMMENT \"\",\n" +
" `k2` smallint(6) NULL COMMENT \"\"\n" +
") ENGINE=OLAP\n" +
"COMMENT \"OLAP\"\n" +
"PARTITION BY RANGE(`k1`)\n" +
"(PARTITION p1 VALUES [(\"-128\"), (\"-64\")),\n" +
"PARTITION p2 VALUES [(\"-64\"), (\"0\")),\n" +
"PARTITION p3 VALUES [(\"0\"), (\"64\")))\n" +
"DISTRIBUTED BY HASH(k1, k2) BUCKETS 5\n" +
"PROPERTIES (\n" +
"\"replication_num\" = \"1\",\n" +
"\"in_memory\" = \"false\",\n" +
"\"storage_format\" = \"DEFAULT\"\n" +
");");
createTable("create table test.colocate1\n" +
"(k1 int, k2 int, k3 int) distributed by hash(k1, k2) buckets 1\n" +
"properties(\"replication_num\" = \"1\"," +
"\"colocate_with\" = \"group1\");");
createTable("create table test.colocate2\n" +
"(k1 int, k2 int, k3 int) distributed by hash(k1, k2) buckets 1\n" +
"properties(\"replication_num\" = \"1\"," +
"\"colocate_with\" = \"group1\");");
createTable("create external table test.mysql_table\n" +
"(k1 int, k2 int)\n" +
"ENGINE=MYSQL\n" +
"PROPERTIES (\n" +
"\"host\" = \"127.0.0.1\",\n" +
"\"port\" = \"3306\",\n" +
"\"user\" = \"root\",\n" +
"\"password\" = \"123\",\n" +
"\"database\" = \"db1\",\n" +
"\"table\" = \"tbl1\"\n" +
");");
createTable("CREATE TABLE test.`table_partitioned` (\n" +
" `dt` int(11) NOT NULL COMMENT \"\",\n" +
" `dis_key` varchar(20) NOT NULL COMMENT \"\"\n" +
") ENGINE=OLAP\n" +
"DUPLICATE KEY(`dt`, `dis_key`)\n" +
"PARTITION BY RANGE(`dt`)\n" +
"(PARTITION p20200101 VALUES [(\"-1\"), (\"20200101\")),\n" +
"PARTITION p20200201 VALUES [(\"20200101\"), (\"20200201\")))\n" +
"DISTRIBUTED BY HASH(`dt`, `dis_key`) BUCKETS 2\n" +
"PROPERTIES (\n" +
"\"replication_num\" = \"1\"\n" +
");");
createTable("CREATE TABLE test.`table_unpartitioned` (\n" +
" `dt` int(11) NOT NULL COMMENT \"\",\n" +
" `dis_key` varchar(20) NOT NULL COMMENT \"\"\n" +
") ENGINE=OLAP\n" +
"DUPLICATE KEY(`dt`, `dis_key`)\n" +
"COMMENT \"OLAP\"\n" +
"DISTRIBUTED BY HASH(`dt`, `dis_key`) BUCKETS 2\n" +
"PROPERTIES (\n" +
"\"replication_num\" = \"1\"\n" +
");");
createTable("create external table test.odbc_oracle\n" +
"(k1 float, k2 int)\n" +
"ENGINE=ODBC\n" +
"PROPERTIES (\n" +
"\"host\" = \"127.0.0.1\",\n" +
"\"port\" = \"3306\",\n" +
"\"user\" = \"root\",\n" +
"\"password\" = \"123\",\n" +
"\"database\" = \"db1\",\n" +
"\"table\" = \"tbl1\",\n" +
"\"driver\" = \"Oracle Driver\",\n" +
"\"odbc_type\" = \"oracle\"\n" +
");");
createTable("create external table test.odbc_mysql\n" +
"(k1 int, k2 int)\n" +
"ENGINE=ODBC\n" +
"PROPERTIES (\n" +
"\"host\" = \"127.0.0.1\",\n" +
"\"port\" = \"3306\",\n" +
"\"user\" = \"root\",\n" +
"\"password\" = \"123\",\n" +
"\"database\" = \"db1\",\n" +
"\"table\" = \"tbl1\",\n" +
"\"driver\" = \"Oracle Driver\",\n" +
"\"odbc_type\" = \"mysql\"\n" +
");");
createTable("create table test.tbl_int_date (" +
"`date` datetime NULL," +
"`day` date NULL," +
"`site_id` int(11) NULL )" +
" ENGINE=OLAP " +
"DUPLICATE KEY(`date`, `day`, `site_id`)" +
"DISTRIBUTED BY HASH(`site_id`) BUCKETS 10 " +
"PROPERTIES (\n" +
"\"replication_num\" = \"1\",\n" +
"\"in_memory\" = \"false\",\n" +
"\"storage_format\" = \"V2\"\n" +
");");
}
@AfterClass
public static void tearDown() {
File file = new File(runningDir);
file.delete();
}
private static void createTable(String sql) throws Exception {
CreateTableStmt createTableStmt = (CreateTableStmt) UtFrameUtils.parseAndAnalyzeStmt(sql, connectContext);
Catalog.getCurrentCatalog().createTable(createTableStmt);
}
@Test
public void testBitmapInsertInto() throws Exception {
String queryStr = "explain INSERT INTO test.bitmap_table (id, id2) VALUES (1001, to_bitmap(1000)), (1001, to_bitmap(2000));";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("OLAP TABLE SINK"));
queryStr = "explain insert into test.bitmap_table select id, bitmap_union(id2) from test.bitmap_table_2 group by id;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("OLAP TABLE SINK"));
Assert.assertTrue(explainString.contains("bitmap_union"));
Assert.assertTrue(explainString.contains("1:AGGREGATE"));
Assert.assertTrue(explainString.contains("0:OlapScanNode"));
queryStr = "explain insert into test.bitmap_table select id, 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` | `id2`"));
Assert.assertTrue(explainString.contains("0:OlapScanNode"));
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("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("0:OlapScanNode"));
queryStr = "explain insert into test.bitmap_table select id, id from test.bitmap_table_2;";
String errorMsg = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(errorMsg.contains("bitmap column id2 require the function return type is BITMAP"));
}
private static void testBitmapQueryPlan(String sql, String result) throws Exception {
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains(result));
}
@Test
public void testBitmapQuery() throws Exception {
testBitmapQueryPlan(
"select * from test.bitmap_table;",
"OUTPUT EXPRS:`default_cluster:test.bitmap_table`.`id` | `default_cluster:test.bitmap_table`.`id2`"
);
testBitmapQueryPlan(
"select count(id2) from test.bitmap_table;",
Type.OnlyMetricTypeErrorMsg
);
testBitmapQueryPlan(
"select group_concat(id2) from test.bitmap_table;",
"group_concat requires first parameter to be of type STRING: group_concat(`id2`)"
);
testBitmapQueryPlan(
"select sum(id2) from test.bitmap_table;",
"sum requires a numeric parameter: sum(`id2`)"
);
testBitmapQueryPlan(
"select avg(id2) from test.bitmap_table;",
"avg requires a numeric parameter: avg(`id2`)"
);
testBitmapQueryPlan(
"select max(id2) from test.bitmap_table;",
Type.OnlyMetricTypeErrorMsg
);
testBitmapQueryPlan(
"select min(id2) from test.bitmap_table;",
Type.OnlyMetricTypeErrorMsg
);
testBitmapQueryPlan(
"select count(*) from test.bitmap_table group by id2;",
Type.OnlyMetricTypeErrorMsg
);
testBitmapQueryPlan(
"select count(*) from test.bitmap_table where id2 = 1;",
"type not match, originType=BITMAP, targeType=DOUBLE"
);
}
private static void testHLLQueryPlan(String sql, String result) throws Exception {
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains(result));
}
@Test
public void testHLLTypeQuery() throws Exception {
testHLLQueryPlan(
"select * from test.hll_table;",
"OUTPUT EXPRS:`default_cluster:test.hll_table`.`id` | `default_cluster:test.hll_table`.`id2`"
);
testHLLQueryPlan(
"select count(id2) from test.hll_table;",
Type.OnlyMetricTypeErrorMsg
);
testHLLQueryPlan(
"select group_concat(id2) from test.hll_table;",
"group_concat requires first parameter to be of type STRING: group_concat(`id2`)"
);
testHLLQueryPlan(
"select sum(id2) from test.hll_table;",
"sum requires a numeric parameter: sum(`id2`)"
);
testHLLQueryPlan(
"select avg(id2) from test.hll_table;",
"avg requires a numeric parameter: avg(`id2`)"
);
testHLLQueryPlan(
"select max(id2) from test.hll_table;",
Type.OnlyMetricTypeErrorMsg
);
testHLLQueryPlan(
"select min(id2) from test.hll_table;",
Type.OnlyMetricTypeErrorMsg
);
testHLLQueryPlan(
"select min(id2) from test.hll_table;",
Type.OnlyMetricTypeErrorMsg
);
testHLLQueryPlan(
"select count(*) from test.hll_table group by id2;",
Type.OnlyMetricTypeErrorMsg
);
testHLLQueryPlan(
"select count(*) from test.hll_table where id2 = 1",
"type not match, originType=HLL, targeType=DOUBLE"
);
}
@Test
public void testTypeCast() throws Exception {
// cmy: this test may sometimes failed in our daily test env, so I add a case here.
String sql = "select * from test.baseall a where k1 in (select k1 from test.bigtable b where k2 > 0 and k1 = 1);";
UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertEquals(MysqlStateType.EOF, connectContext.getState().getStateType());
sql = "SHOW VARIABLES LIKE 'lower_case_%'; SHOW VARIABLES LIKE 'sql_mode'";
List<StatementBase> stmts = UtFrameUtils.parseAndAnalyzeStmts(sql, connectContext);
Assert.assertEquals(2, stmts.size());
}
@Test
public void testMultiStmts() throws Exception {
String sql = "SHOW VARIABLES LIKE 'lower_case_%'; SHOW VARIABLES LIKE 'sql_mode'";
List<StatementBase>stmts = UtFrameUtils.parseAndAnalyzeStmts(sql, connectContext);
Assert.assertEquals(2, stmts.size());
sql = "SHOW VARIABLES LIKE 'lower_case_%';;;";
stmts = UtFrameUtils.parseAndAnalyzeStmts(sql, connectContext);
Assert.assertEquals(1, stmts.size());
sql = "SHOW VARIABLES LIKE 'lower_case_%';;;SHOW VARIABLES LIKE 'lower_case_%';";
stmts = UtFrameUtils.parseAndAnalyzeStmts(sql, connectContext);
Assert.assertEquals(4, stmts.size());
sql = "SHOW VARIABLES LIKE 'lower_case_%'";
stmts = UtFrameUtils.parseAndAnalyzeStmts(sql, connectContext);
Assert.assertEquals(1, stmts.size());
}
@Test
public void testCountDistinctRewrite() throws Exception {
String sql = "select count(distinct id) from test.bitmap_table";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("output: count"));
sql = "select count(distinct id2) from test.bitmap_table";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("bitmap_union_count"));
sql = "select sum(id) / count(distinct id2) from test.bitmap_table";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("bitmap_union_count"));
sql = "select count(distinct id2) from test.hll_table";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("hll_union_agg"));
sql = "select sum(id) / count(distinct id2) from test.hll_table";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("hll_union_agg"));
sql = "select count(distinct id2) from test.bitmap_table group by id order by count(distinct id2)";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("bitmap_union_count"));
sql = "select count(distinct id2) from test.bitmap_table having count(distinct id2) > 0";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("bitmap_union_count"));
sql = "select count(distinct id2) from test.bitmap_table order by count(distinct id2)";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("bitmap_union_count"));
sql = "select count(distinct if(id = 1, id2, null)) from test.bitmap_table";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("bitmap_union_count"));
sql = "select count(distinct ifnull(id2, id3)) from test.bitmap_table_2";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("bitmap_union_count"));
sql = "select count(distinct coalesce(id2, id3)) from test.bitmap_table_2";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("bitmap_union_count"));
ConnectContext.get().getSessionVariable().setRewriteCountDistinct(false);
sql = "select count(distinct id2) from test.bitmap_table";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains(Type.OnlyMetricTypeErrorMsg));
}
@Test
public void testCreateDbQueryPlanWithSchemaSyntax() throws Exception {
String createSchemaSql = "create schema if not exists test";
String createDbSql = "create database if not exists test";
CreateDbStmt createSchemaStmt = (CreateDbStmt) UtFrameUtils.parseAndAnalyzeStmt(createSchemaSql, connectContext);
CreateDbStmt createDbStmt = (CreateDbStmt) UtFrameUtils.parseAndAnalyzeStmt(createDbSql, connectContext);
Assert.assertEquals(createDbStmt.toSql(), createSchemaStmt.toSql());
}
@Test
public void testDropDbQueryPlanWithSchemaSyntax() throws Exception {
String dropSchemaSql = "drop schema if exists test";
String dropDbSql = "drop database if exists test";
DropDbStmt dropSchemaStmt = (DropDbStmt) UtFrameUtils.parseAndAnalyzeStmt(dropSchemaSql, connectContext);
DropDbStmt dropDbStmt = (DropDbStmt) UtFrameUtils.parseAndAnalyzeStmt(dropDbSql, connectContext);
Assert.assertEquals(dropDbStmt.toSql(), dropSchemaStmt.toSql());
}
@Test
public void testShowCreateDbQueryPlanWithSchemaSyntax() throws Exception {
String showCreateSchemaSql = "show create schema test";
String showCreateDbSql = "show create database test";
ShowCreateDbStmt showCreateSchemaStmt = (ShowCreateDbStmt) UtFrameUtils.parseAndAnalyzeStmt(showCreateSchemaSql, connectContext);
ShowCreateDbStmt showCreateDbStmt = (ShowCreateDbStmt) UtFrameUtils.parseAndAnalyzeStmt(showCreateDbSql, connectContext);
Assert.assertEquals(showCreateDbStmt.toSql(), showCreateSchemaStmt.toSql());
}
@Test
public void testDateTypeCastSyntax() throws Exception {
String castSql = "select * from test.baseall where k11 < cast('2020-03-26' as date)";
SelectStmt selectStmt =
(SelectStmt) UtFrameUtils.parseAndAnalyzeStmt(castSql, connectContext);
Expr rightExpr = selectStmt.getWhereClause().getChildren().get(1);
Assert.assertTrue(rightExpr.getType().equals(Type.DATETIME));
String castSql2 = "select str_to_date('11/09/2011', '%m/%d/%Y');";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + castSql2);
Assert.assertTrue(explainString.contains("2011-11-09"));
Assert.assertFalse(explainString.contains("2011-11-09 00:00:00"));
}
@Test
public void testDateTypeEquality() throws Exception {
// related to Github issue #3309
String loadStr = "load label test.app_profile_20200306\n" +
"(DATA INFILE('filexxx')INTO TABLE app_profile partition (p_20200306)\n" +
"COLUMNS TERMINATED BY '\\t'\n" +
"(app_name,package_name,age,gender,level,city,model,brand,hours,use_num,use_time,start_times)\n" +
"SET\n" +
"(event_date = default_value('2020-03-06'))) \n" +
"PROPERTIES ( 'max_filter_ratio'='0.0001' );\n" +
"";
LoadStmt loadStmt = (LoadStmt) UtFrameUtils.parseAndAnalyzeStmt(loadStr, connectContext);
Catalog.getCurrentCatalog().getLoadManager().createLoadJobV1FromStmt(loadStmt, EtlJobType.HADOOP,
System.currentTimeMillis());
}
@Test
public void testJoinPredicateTransitivity() throws Exception {
connectContext.setDatabase("default_cluster:test");
// test left join : left table where binary predicate
String sql = "select join1.id\n" +
"from join1\n" +
"left join join2 on join1.id = join2.id\n" +
"where join1.id > 1;";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join2`.`id` > 1"));
Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` > 1"));
// test left join: left table where in predicate
sql = "select join1.id\n" +
"from join1\n" +
"left join join2 on join1.id = join2.id\n" +
"where join1.id in (2);";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join2`.`id` IN (2)"));
Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` IN (2)"));
// test left join: left table where between predicate
sql = "select join1.id\n" +
"from join1\n" +
"left join join2 on join1.id = join2.id\n" +
"where join1.id BETWEEN 1 AND 2;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` >= 1, `join1`.`id` <= 2"));
Assert.assertTrue(explainString.contains("PREDICATES: `join2`.`id` >= 1, `join2`.`id` <= 2"));
// test left join: left table join predicate, left table couldn't push down
sql = "select *\n from join1\n" +
"left join join2 on join1.id = join2.id\n" +
"and join1.id > 1;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("other join predicates: `join1`.`id` > 1"));
Assert.assertFalse(explainString.contains("PREDICATES: `join1`.`id` > 1"));
// test left join: right table where predicate.
// If we eliminate outer join, we could push predicate down to join1 and join2.
// Currently, we push predicate to join1 and keep join predicate for join2
sql = "select *\n from join1\n" +
"left join join2 on join1.id = join2.id\n" +
"where join2.id > 1;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` > 1"));
Assert.assertFalse(explainString.contains("other join predicates: `join2`.`id` > 1"));
// test left join: right table join predicate, only push down right table
sql = "select *\n from join1\n" +
"left join join2 on join1.id = join2.id\n" +
"and join2.id > 1;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join2`.`id` > 1"));
Assert.assertFalse(explainString.contains("PREDICATES: `join1`.`id` > 1"));
// test inner join: left table where predicate, both push down left table and right table
sql = "select *\n from join1\n" +
"join join2 on join1.id = join2.id\n" +
"where join1.id > 1;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` > 1"));
Assert.assertTrue(explainString.contains("PREDICATES: `join2`.`id` > 1"));
// test inner join: left table join predicate, both push down left table and right table
sql = "select *\n from join1\n" +
"join join2 on join1.id = join2.id\n" +
"and join1.id > 1;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` > 1"));
Assert.assertTrue(explainString.contains("PREDICATES: `join2`.`id` > 1"));
// test inner join: right table where predicate, both push down left table and right table
sql = "select *\n from join1\n" +
"join join2 on join1.id = join2.id\n" +
"where join2.id > 1;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` > 1"));
Assert.assertTrue(explainString.contains("PREDICATES: `join2`.`id` > 1"));
// test inner join: right table join predicate, both push down left table and right table
sql = "select *\n from join1\n" +
"join join2 on join1.id = join2.id\n" +
"and 1 < join2.id;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` > 1"));
Assert.assertTrue(explainString.contains("PREDICATES: `join2`.`id` > 1"));
sql = "select *\n from join1\n" +
"join join2 on join1.id = join2.value\n" +
"and join2.value in ('abc');";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertFalse(explainString.contains("'abc' is not a number"));
Assert.assertFalse(explainString.contains("`join1`.`value` IN ('abc')"));
// test anti join, right table join predicate, only push to right table
sql = "select *\n from join1\n" +
"left anti join join2 on join1.id = join2.id\n" +
"and join2.id > 1;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join2`.`id` > 1"));
Assert.assertFalse(explainString.contains("PREDICATES: `join1`.`id` > 1"));
// test semi join, right table join predicate, only push to right table
sql = "select *\n from join1\n" +
"left semi join join2 on join1.id = join2.id\n" +
"and join2.id > 1;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join2`.`id` > 1"));
Assert.assertFalse(explainString.contains("PREDICATES: `join1`.`id` > 1"));
// test anti join, left table join predicate, left table couldn't push down
sql = "select *\n from join1\n" +
"left anti join join2 on join1.id = join2.id\n" +
"and join1.id > 1;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("other join predicates: `join1`.`id` > 1"));
Assert.assertFalse(explainString.contains("PREDICATES: `join1`.`id` > 1"));
// test semi join, left table join predicate, only push to left table
sql = "select *\n from join1\n" +
"left semi join join2 on join1.id = join2.id\n" +
"and join1.id > 1;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` > 1"));
// test anti join, left table where predicate, only push to left table
sql = "select join1.id\n" +
"from join1\n" +
"left anti join join2 on join1.id = join2.id\n" +
"where join1.id > 1;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` > 1"));
Assert.assertFalse(explainString.contains("PREDICATES: `join2`.`id` > 1"));
// test semi join, left table where predicate, only push to left table
sql = "select join1.id\n" +
"from join1\n" +
"left semi join join2 on join1.id = join2.id\n" +
"where join1.id > 1;";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` > 1"));
Assert.assertFalse(explainString.contains("PREDICATES: `join2`.`id` > 1"));
}
@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 "
+ "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";
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;";
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";
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";
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 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";
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";
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";
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";
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";
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;";
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;";
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;";
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;";
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;";
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";
String a = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql23);
Assert.assertTrue(StringUtils.containsIgnoreCase(a,
"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";
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";
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;";
Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql31),
"constant exprs: \n CASE 100.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";
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";
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";
Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql421), "constant exprs: \n 'other'"));
// 5.1 test same type in then expr and else expr
String sql51 = "select case when 132 then k7 else 'all' end as col51 from test.baseall group by col51";
Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql51),
"OUTPUT EXPRS: CASE WHEN 132 THEN `k7` ELSE 'all' END"));
// 5.2 test same type in then expr and else expr
String sql52 = "select case when 2 < 1 then 'all' else k7 end as col52 from test.baseall group by col52";
Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql52),
"OUTPUT EXPRS: `k7`"));
// 5.3 test different type in then expr and else expr, and return CastExpr<SlotRef>
String sql53 = "select case when 2 < 1 then 'all' else k1 end as col53 from test.baseall group by col53";
Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql53),
"OUTPUT EXPRS: `k1`"));
// 5.4 test return CastExpr<SlotRef> with other SlotRef in selectListItem
String sql54 = "select k2, case when 2 < 1 then 'all' else k1 end as col54, k7 from test.baseall group by k2, col54, k7";
Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql54),
"OUTPUT EXPRS:<slot 3> `k2` | <slot 4> `k1` | <slot 5> `k7`"));
// 5.5 test return CastExpr<CastExpr<SlotRef>> with other SlotRef in selectListItem
String sql55 = "select case when 2 < 1 then 'all' else cast(k1 as int) end as col55, k7 from test.baseall group by col55, k7";
Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql55),
"OUTPUT EXPRS:<slot 2> CAST(`k1` AS INT) | <slot 3> `k7`"));
}
@Test
public void testJoinPredicateTransitivityWithSubqueryInWhereClause() throws Exception {
connectContext.setDatabase("default_cluster:test");
String sql = "SELECT *\n" +
"FROM test.pushdown_test\n" +
"WHERE 0 < (\n" +
" SELECT MAX(k9)\n" +
" FROM test.pushdown_test);";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PLAN FRAGMENT"));
Assert.assertTrue(explainString.contains("CROSS JOIN"));
Assert.assertTrue(!explainString.contains("PREDICATES"));
}
@Test
public void testDistinctPushDown() throws Exception {
connectContext.setDatabase("default_cluster:test");
String sql = "select distinct k1 from (select distinct k1 from test.pushdown_test) t where k1 > 1";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql);
Assert.assertTrue(explainString.contains("PLAN FRAGMENT"));
}
@Test
public void testConstInParitionPrune() throws Exception {
FeConstants.runningUnitTest = true;
String queryStr = "explain select * from (select 'aa' as kk1, sum(id) from test.join1 where dt = 9 group by kk1)tt where kk1 in ('aa');";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
FeConstants.runningUnitTest = false;
Assert.assertTrue(explainString.contains("partitions=1/1"));
}
@Test
public void testOrCompoundPredicateFold() throws Exception {
String queryStr = "explain select * from baseall where (k1 > 1) or (k1 > 1 and k2 < 1)";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("PREDICATES: (`k1` > 1)\n"));
queryStr = "explain select * from baseall where (k1 > 1 and k2 < 1) or (k1 > 1)";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("PREDICATES: `k1` > 1\n"));
queryStr = "explain select * from baseall where (k1 > 1) or (k1 > 1)";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("PREDICATES: (`k1` > 1)\n"));
}
@Test
public void testColocateJoin() throws Exception {
FeConstants.runningUnitTest = true;
String queryStr = "explain select * from test.colocate1 t1, test.colocate2 t2 where t1.k1 = t2.k1 and t1.k2 = t2.k2 and t1.k3 = t2.k3";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("colocate: true"));
queryStr = "explain select * from test.colocate1 t1 join [shuffle] test.colocate2 t2 on t1.k1 = t2.k1 and t1.k2 = t2.k2";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("colocate: false"));
// t1.k1 = t2.k2 not same order with distribute column
queryStr = "explain select * from test.colocate1 t1, test.colocate2 t2 where t1.k1 = t2.k2 and t1.k2 = t2.k1 and t1.k3 = t2.k3";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("colocate: false"));
queryStr = "explain select * from test.colocate1 t1, test.colocate2 t2 where t1.k2 = t2.k2";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("colocate: false"));
}
@Test
public void testSelfColocateJoin() throws Exception {
FeConstants.runningUnitTest = true;
// single partition
String queryStr = "explain select * from test.jointest t1, test.jointest t2 where t1.k1 = t2.k1";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("colocate: true"));
// multi partition, should not be colocate
queryStr = "explain select * from test.dynamic_partition t1, test.dynamic_partition t2 where t1.k1 = t2.k1";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("colocate: false"));
}
@Test
public void testBucketShuffleJoin() throws Exception {
FeConstants.runningUnitTest = true;
// enable bucket shuffle join
Deencapsulation.setField(connectContext.getSessionVariable(), "enableBucketShuffleJoin", true);
// set data size and row count for the olap table
Database db = Catalog.getCurrentCatalog().getDb("default_cluster:test");
OlapTable tbl = (OlapTable) db.getTable("bucket_shuffle1");
for (Partition partition : tbl.getPartitions()) {
partition.updateVisibleVersionAndVersionHash(2, 0);
for (MaterializedIndex mIndex : partition.getMaterializedIndices(IndexExtState.VISIBLE)) {
mIndex.setRowCount(10000);
for (Tablet tablet : mIndex.getTablets()) {
for (Replica replica : tablet.getReplicas()) {
replica.updateVersionInfo(2, 0, 200000, 10000);
}
}
}
}
db = Catalog.getCurrentCatalog().getDb("default_cluster:test");
tbl = (OlapTable) db.getTable("bucket_shuffle2");
for (Partition partition : tbl.getPartitions()) {
partition.updateVisibleVersionAndVersionHash(2, 0);
for (MaterializedIndex mIndex : partition.getMaterializedIndices(IndexExtState.VISIBLE)) {
mIndex.setRowCount(10000);
for (Tablet tablet : mIndex.getTablets()) {
for (Replica replica : tablet.getReplicas()) {
replica.updateVersionInfo(2, 0, 200000, 10000);
}
}
}
}
// single partition
String queryStr = "explain select * from test.jointest t1, test.bucket_shuffle1 t2 where t1.k1 = t2.k1 and t1.k1 = t2.k2";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("BUCKET_SHFFULE"));
Assert.assertTrue(explainString.contains("BUCKET_SHFFULE_HASH_PARTITIONED: `t1`.`k1`, `t1`.`k1`"));
// not bucket shuffle join do not support different type
queryStr = "explain select * from test.jointest t1, test.bucket_shuffle1 t2 where cast (t1.k1 as tinyint) = t2.k1 and t1.k1 = t2.k2";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(!explainString.contains("BUCKET_SHFFULE"));
// left table distribution column not match
queryStr = "explain select * from test.jointest t1, test.bucket_shuffle1 t2 where t1.k1 = t2.k1";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(!explainString.contains("BUCKET_SHFFULE"));
// multi partition, should not be bucket shuffle join
queryStr = "explain select * from test.jointest t1, test.bucket_shuffle2 t2 where t1.k1 = t2.k1 and t1.k1 = t2.k2";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(!explainString.contains("BUCKET_SHFFULE"));
// disable bucket shuffle join again
Deencapsulation.setField(connectContext.getSessionVariable(), "enableBucketShuffleJoin", false);
}
@Test
public void testJoinWithMysqlTable() throws Exception {
connectContext.setDatabase("default_cluster:test");
// set data size and row count for the olap table
Database db = Catalog.getCurrentCatalog().getDb("default_cluster:test");
OlapTable tbl = (OlapTable) db.getTable("jointest");
for (Partition partition : tbl.getPartitions()) {
partition.updateVisibleVersionAndVersionHash(2, 0);
for (MaterializedIndex mIndex : partition.getMaterializedIndices(IndexExtState.VISIBLE)) {
mIndex.setRowCount(10000);
for (Tablet tablet : mIndex.getTablets()) {
for (Replica replica : tablet.getReplicas()) {
replica.updateVersionInfo(2, 0, 200000, 10000);
}
}
}
}
String queryStr = "explain select * from mysql_table t2, jointest t1 where t1.k1 = t2.k1";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("INNER JOIN (BROADCAST)"));
Assert.assertTrue(explainString.contains("1:SCAN MYSQL"));
queryStr = "explain select * from jointest t1, mysql_table t2 where t1.k1 = t2.k1";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("INNER JOIN (BROADCAST)"));
Assert.assertTrue(explainString.contains("1:SCAN MYSQL"));
queryStr = "explain select * from jointest t1, mysql_table t2, mysql_table t3 where t1.k1 = t3.k1";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertFalse(explainString.contains("INNER JOIN (PARTITIONED)"));
// should clear the jointest table to make sure do not affect other test
for (Partition partition : tbl.getPartitions()) {
partition.updateVisibleVersionAndVersionHash(2, 0);
for (MaterializedIndex mIndex : partition.getMaterializedIndices(IndexExtState.VISIBLE)) {
mIndex.setRowCount(0);
for (Tablet tablet : mIndex.getTablets()) {
for (Replica replica : tablet.getReplicas()) {
replica.updateVersionInfo(2, 0, 0, 0);
}
}
}
}
}
@Test
public void testJoinWithOdbcTable() throws Exception {
connectContext.setDatabase("default_cluster:test");
// set data size and row count for the olap table
Database db = Catalog.getCurrentCatalog().getDb("default_cluster:test");
OlapTable tbl = (OlapTable) db.getTable("jointest");
for (Partition partition : tbl.getPartitions()) {
partition.updateVisibleVersionAndVersionHash(2, 0);
for (MaterializedIndex mIndex : partition.getMaterializedIndices(IndexExtState.VISIBLE)) {
mIndex.setRowCount(10000);
for (Tablet tablet : mIndex.getTablets()) {
for (Replica replica : tablet.getReplicas()) {
replica.updateVersionInfo(2, 0, 200000, 10000);
}
}
}
}
String queryStr = "explain select * from odbc_mysql t2, jointest t1 where t1.k1 = t2.k1";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("INNER JOIN (BROADCAST)"));
Assert.assertTrue(explainString.contains("1:SCAN ODBC"));
queryStr = "explain select * from jointest t1, odbc_mysql t2 where t1.k1 = t2.k1";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("INNER JOIN (BROADCAST)"));
Assert.assertTrue(explainString.contains("1:SCAN ODBC"));
queryStr = "explain select * from jointest t1, odbc_mysql t2, odbc_mysql t3 where t1.k1 = t3.k1";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertFalse(explainString.contains("INNER JOIN (PARTITIONED)"));
// should clear the jointest table to make sure do not affect other test
for (Partition partition : tbl.getPartitions()) {
partition.updateVisibleVersionAndVersionHash(2, 0);
for (MaterializedIndex mIndex : partition.getMaterializedIndices(IndexExtState.VISIBLE)) {
mIndex.setRowCount(0);
for (Tablet tablet : mIndex.getTablets()) {
for (Replica replica : tablet.getReplicas()) {
replica.updateVersionInfo(2, 0, 0, 0);
}
}
}
}
}
@Test
public void testPushDownOfOdbcTable() throws Exception {
connectContext.setDatabase("default_cluster:test");
// MySQL ODBC table can push down all filter
String queryStr = "explain select * from odbc_mysql where k1 > 10 and abs(k1) > 10";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("`k1` > 10"));
Assert.assertTrue(explainString.contains("abs(`k1`) > 10"));
// now we do not support odbc scan node push down function call, except MySQL ODBC table
// this table is Oracle ODBC table, so abs(k1) should not be pushed down
queryStr = "explain select * from odbc_oracle where k1 > 10 and abs(k1) > 10";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("k1 > 10"));
Assert.assertTrue(!explainString.contains("abs(k1) > 10"));
}
@Test
public void testLimitOfExternalTable() throws Exception {
connectContext.setDatabase("default_cluster:test");
// ODBC table (MySQL)
String queryStr = "explain select * from odbc_mysql where k1 > 10 and abs(k1) > 10 limit 10";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("LIMIT 10"));
// ODBC table (Oracle) not push down limit
queryStr = "explain select * from odbc_oracle where k1 > 10 and abs(k1) > 10 limit 10";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
// abs is function, so Doris do not push down function except MySQL Database
// so should not push down limit operation
Assert.assertTrue(!explainString.contains("ROWNUM <= 10"));
// ODBC table (Oracle) push down limit
queryStr = "explain select * from odbc_oracle where k1 > 10 limit 10";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("ROWNUM <= 10"));
// MySQL table
queryStr = "explain select * from mysql_table where k1 > 10 and abs(k1) > 10 limit 10";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("LIMIT 10"));
}
@Test
public void testOdbcSink() throws Exception {
connectContext.setDatabase("default_cluster:test");
// insert into odbc_oracle table
String queryStr = "explain insert into odbc_oracle select * from odbc_mysql";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("TABLENAME IN DORIS: odbc_oracle"));
Assert.assertTrue(explainString.contains("TABLE TYPE: ORACLE"));
Assert.assertTrue(explainString.contains("TABLENAME OF EXTERNAL TABLE: tbl1"));
// enable transaction of ODBC Sink
Deencapsulation.setField(connectContext.getSessionVariable(), "enableOdbcTransaction", true);
queryStr = "explain insert into odbc_oracle select * from odbc_mysql";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("EnableTransaction: true"));
}
@Test
public void testPreferBroadcastJoin() throws Exception {
connectContext.setDatabase("default_cluster:test");
String queryStr = "explain select * from (select k1 from jointest group by k1)t2, jointest t1 where t1.k1 = t2.k1";
// default set PreferBroadcastJoin true
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("INNER JOIN (BROADCAST)"));
connectContext.getSessionVariable().setPreferJoinMethod("shuffle");
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("INNER JOIN (PARTITIONED)"));
connectContext.getSessionVariable().setPreferJoinMethod("broadcast");
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("INNER JOIN (BROADCAST)"));
}
@Test
public void testEmptyNode() throws Exception {
connectContext.setDatabase("default_cluster:test");
String emptyNode = "EMPTYSET";
String denseRank = "dense_rank";
List<String> sqls = Lists.newArrayList();
sqls.add("explain select * from baseall limit 0");
sqls.add("explain select count(*) from baseall limit 0;");
sqls.add("explain select k3, dense_rank() OVER () AS rank FROM baseall limit 0;");
sqls.add("explain select rank from (select k3, dense_rank() OVER () AS rank FROM baseall) a limit 0;");
sqls.add("explain select * from baseall join bigtable as b limit 0");
sqls.add("explain select * from baseall where 1 = 2");
sqls.add("explain select count(*) from baseall where 1 = 2;");
sqls.add("explain select k3, dense_rank() OVER () AS rank FROM baseall where 1 =2;");
sqls.add("explain select rank from (select k3, dense_rank() OVER () AS rank FROM baseall) a where 1 =2;");
sqls.add("explain select * from baseall join bigtable as b where 1 = 2");
for(String sql: sqls) {
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, sql);
System.out.println(explainString);
Assert.assertTrue(explainString.contains(emptyNode));
Assert.assertFalse(explainString.contains(denseRank));
}
}
@Test
public void testInformationFunctions() throws Exception {
connectContext.setDatabase("default_cluster:test");
Analyzer analyzer = new Analyzer(connectContext.getCatalog(), connectContext);
InformationFunction infoFunc = new InformationFunction("database");
infoFunc.analyze(analyzer);
Assert.assertEquals("test", infoFunc.getStrValue());
infoFunc = new InformationFunction("user");
infoFunc.analyze(analyzer);
Assert.assertEquals("'root'@'127.0.0.1'", infoFunc.getStrValue());
infoFunc = new InformationFunction("current_user");
infoFunc.analyze(analyzer);
Assert.assertEquals("'root'@'%'", infoFunc.getStrValue());
}
@Test
public void testAggregateSatisfyOlapTableDistribution() throws Exception {
FeConstants.runningUnitTest = true;
connectContext.setDatabase("default_cluster:test");
String sql = "SELECT dt, dis_key, COUNT(1) FROM table_unpartitioned group by dt, dis_key";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql);
System.out.println(explainString);
Assert.assertTrue(explainString.contains("AGGREGATE (update finalize)"));
sql = "SELECT dt, dis_key, COUNT(1) FROM table_partitioned group by dt, dis_key";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql);
System.out.println(explainString);
Assert.assertTrue(explainString.contains("AGGREGATE (update finalize)"));
}
public void testLeadAndLagFunction() throws Exception {
connectContext.setDatabase("default_cluster:test");
String queryStr = "explain select time, lead(query_time, 1, NULL) over () as time2 from test.test1";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("lead(`query_time`, 1, NULL)"));
queryStr = "explain select time, lead(query_time, 1, 2) over () as time2 from test.test1";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("lead(`query_time`, 1, 2)"));
queryStr = "explain select time, lead(time, 1, '2020-01-01 00:00:00') over () as time2 from test.test1";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("lead(`time`, 1, '2020-01-01 00:00:00')"));
queryStr = "explain select time, lag(query_time, 1, 2) over () as time2 from test.test1";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr);
Assert.assertTrue(explainString.contains("lag(`query_time`, 1, 2)"));
}
@Test
public void testIntDateTime() throws Exception {
connectContext.setDatabase("default_cluster:test");
//valid date
String sql = "select day from tbl_int_date where day in ('2020-10-30')";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `day` IN ('2020-10-30 00:00:00')"));
//valid date
sql = "select day from tbl_int_date where day in ('2020-10-30','2020-10-29')";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `day` IN ('2020-10-30 00:00:00', '2020-10-29 00:00:00')"));
//valid datetime
sql = "select day from tbl_int_date where date in ('2020-10-30 12:12:30')";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `date` IN ('2020-10-30 12:12:30')"));
//valid datetime
sql = "select day from tbl_int_date where date in ('2020-10-30')";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `date` IN ('2020-10-30 00:00:00')"));
//int date
sql = "select day from tbl_int_date where day in (20201030)";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `day` IN ('2020-10-30 00:00:00')"));
//int datetime
sql = "select day from tbl_int_date where date in (20201030)";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql);
Assert.assertTrue(explainString.contains("PREDICATES: `date` IN ('2020-10-30 00:00:00')"));
}
@Test
public void testOutJoinSmapReplace() throws Exception {
connectContext.setDatabase("default_cluster:test");
//valid date
String sql = "SELECT a.aid, b.bid FROM (SELECT 3 AS aid) a right outer JOIN (SELECT 4 AS bid) b ON (a.aid=b.bid)";
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql);
Assert.assertTrue(explainString.contains("OUTPUT EXPRS:`a`.`aid` | 4"));
sql = "SELECT a.aid, b.bid FROM (SELECT 3 AS aid) a left outer JOIN (SELECT 4 AS bid) b ON (a.aid=b.bid)";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql);
Assert.assertTrue(explainString.contains("OUTPUT EXPRS:3 | `b`.`bid`"));
sql = "SELECT a.aid, b.bid FROM (SELECT 3 AS aid) a full outer JOIN (SELECT 4 AS bid) b ON (a.aid=b.bid)";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql);
Assert.assertTrue(explainString.contains("OUTPUT EXPRS:`a`.`aid` | `b`.`bid`"));
sql = "SELECT a.aid, b.bid FROM (SELECT 3 AS aid) a JOIN (SELECT 4 AS bid) b ON (a.aid=b.bid)";
explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql);
Assert.assertTrue(explainString.contains("OUTPUT EXPRS:3 | 4"));
}
}