From 473a67a5b83649f360cfc2e40c9ca8897c9e1884 Mon Sep 17 00:00:00 2001 From: Mingyu Chen Date: Mon, 23 Mar 2020 09:39:22 +0800 Subject: [PATCH] [Syntax] Remove all EmptyStmt from the end of multi-statements list (#3140) to resolve the ISSUE: #3139 When user execute query by some client library such as python MysqlDb, if user execute like: "select * from tbl1;" (with a comma at the end of statement) The sql parser will produce 2 statements: `SelectStmt` and `EmptyStmt`. Here we discard the `EmptyStmt` to make it act like one single statement. This is for some compatibility. Because in python MysqlDb, if the first `SelectStmt` results in some warnings, it will try to execute a `SHOW WARNINGS` statement right after the SelectStmt, but before the execution of `EmptyStmt`. So there will be an exception: `(2014, "Commands out of sync; you can't run this command now")` I though it is a flaw of python MysqlDb. However, in order to maintain the consistency of user use, here we remove all EmptyStmt at the end to prevent errors.(Leave at least one statement) But if user execute statements like: `"select * from tbl1;;select 2"` If first `select * from tbl1` has warnings, python MysqlDb will still throw exception. --- .../doris/common/util/SqlParserUtils.java | 30 ++++++++++++++++++- .../apache/doris/planner/QueryPlanTest.java | 6 ++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/fe/src/main/java/org/apache/doris/common/util/SqlParserUtils.java b/fe/src/main/java/org/apache/doris/common/util/SqlParserUtils.java index 878b6bf96a..a5219ba200 100644 --- a/fe/src/main/java/org/apache/doris/common/util/SqlParserUtils.java +++ b/fe/src/main/java/org/apache/doris/common/util/SqlParserUtils.java @@ -17,6 +17,7 @@ package org.apache.doris.common.util; +import org.apache.doris.analysis.EmptyStmt; import org.apache.doris.analysis.SqlParser; import org.apache.doris.analysis.StatementBase; import org.apache.doris.common.AnalysisException; @@ -46,6 +47,33 @@ public class SqlParserUtils { // get all parsed statements as a list public static List getMultiStmts(SqlParser parser) throws Exception { - return (List) parser.parse().value; + List stmts = (List) parser.parse().value; + /* + * When user execute query by some client library such as python MysqlDb, if user execute like: + * + * "select * from tbl1;" (with a comma at the end of statement) + * + * The sql parser will produce 2 statements: SelectStmt and EmptyStmt. + * Here we discard the second EmptyStmt to make it act like one single statement. + * This is for some compatibility. Because in python MysqlDb, if the first SelectStmt results in + * some warnings, it will try to execute a 'SHOW WARNINGS' statement right after the SelectStmt, + * but before the execution of EmptyStmt. So there will be an exception: + * + * (2014, "Commands out of sync; you can't run this command now") + * + * I though it is a flaw of python MysqlDb. + * However, in order to maintain the consistency of user use, here we remove all EmptyStmt + * at the end to prevent errors.(Leave at least one statement) + * + * But if user execute statements like: + * + * "select * from tbl1;;select 2" + * + * If first "select * from tbl1" has warnings, python MysqlDb will still throw exception. + */ + while (stmts.size() > 1 && stmts.get(stmts.size() - 1) instanceof EmptyStmt) { + stmts.remove(stmts.size() - 1); + } + return stmts; } } 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 3ecf767970..2eaf6dd38d 100644 --- a/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java +++ b/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java @@ -19,7 +19,6 @@ package org.apache.doris.planner; import org.apache.doris.analysis.CreateDbStmt; -import org.apache.doris.analysis.CreateDbStmtTest; import org.apache.doris.analysis.CreateTableStmt; import org.apache.doris.analysis.DropDbStmt; import org.apache.doris.analysis.ShowCreateDbStmt; @@ -30,7 +29,6 @@ import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.QueryState.MysqlStateType; import org.apache.doris.utframe.UtFrameUtils; -import org.codehaus.jackson.map.ser.StdSerializers; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; @@ -308,6 +306,10 @@ public class QueryPlanTest { 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_%'";