diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlReplaceStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlReplaceStatement.java index a65d2e653e..d7dc2abb77 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlReplaceStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlReplaceStatement.java @@ -90,7 +90,9 @@ public class MySqlReplaceStatement extends MySqlStatementImpl { } public void setQuery(SQLQueryExpr query) { - query.setParent(this); + if (query != null) { + query.setParent(this); + } this.query = query; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java index a11c499016..055cd38109 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java @@ -1850,10 +1850,9 @@ public class MySqlStatementParser extends SQLStatementParser { break; } } else if (lexer.token() == Token.LPAREN) { - lexer.nextToken(); - SQLQueryExpr queryExpr = (SQLQueryExpr) this.exprParser.expr(); + SQLSelect select = this.createSQLSelectParser().select(); + SQLQueryExpr queryExpr = new SQLQueryExpr(select); stmt.setQuery(queryExpr); - accept(Token.RPAREN); } return stmt; diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLParser.java index d666221696..7645c78564 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLParser.java @@ -240,6 +240,7 @@ public class SQLParser { case ADVISE: case TYPE: case CLOSE: + case OPEN: alias = lexer.stringVal(); lexer.nextToken(); return alias; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLReplaceParserTest.java b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLReplaceParserTest.java index fe7f342306..ff36bf11ab 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLReplaceParserTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLReplaceParserTest.java @@ -122,6 +122,8 @@ public class DMLReplaceParserTest extends TestCase { SQLStatement stmt = parser.parseStatementList().get(0); parser.match(Token.EOF); String output = SQLUtils.toMySqlString(stmt); - Assert.assertEquals("REPLACE LOW_PRIORITY INTO t1 (col1)\n\tSELECT id\n\tFROM t3", output); + Assert.assertEquals("REPLACE LOW_PRIORITY INTO t1 (col1)\n" + + "\t(SELECT id\n" + + "\tFROM t3)", output); } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlReplaceTest_1.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlReplaceTest_1.java new file mode 100644 index 0000000000..8954af9591 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlReplaceTest_1.java @@ -0,0 +1,180 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed 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 com.alibaba.druid.bvt.sql.mysql; + +import com.alibaba.druid.sql.MysqlTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor; + +import java.util.List; + +public class MySqlReplaceTest_1 extends MysqlTest { + + public void test_0() throws Exception { + String sql = "REPLACE INTO `tb_001` (`gmt_create`, `theday`, `pt`, `song_id`, `song_name`, `play_num_1d`) (SELECT now(), '20170820', case a.pt\n" + + " when 'android' then '安卓'\n" + + " when 'ios' then 'ios'\n" + + " when 'yunos' then '云os'\n" + + " end AS `pt`, a.song_id, if(b.song_name is null,'新发布歌曲',b.song_name), a.play_num_1d FROM ((SELECT pt, song_id, sum(play_num_1d) AS `play_num_1d` FROM `tb_002` WHERE `theday` = '20170820' AND `pt` IN ('android') GROUP BY `pt`, `song_id` ORDER BY `play_num_1d` DESC LIMIT 0, 100) UNION (SELECT pt, song_id, sum(play_num_1d) AS `play_num_1d` FROM `tb_002` WHERE `theday` = '20170820' AND `pt` IN ('ios') GROUP BY `pt`, `song_id` ORDER BY `play_num_1d` DESC LIMIT 0, 100) UNION (SELECT pt, song_id, sum(play_num_1d) AS `play_num_1d` FROM `tb_002` WHERE `theday` = '20170820' AND `pt` IN ('yunos') GROUP BY `pt`, `song_id` ORDER BY `play_num_1d` DESC LIMIT 0, 100)) AS `a` INNER JOIN (SELECT song_id, song_name FROM `tb_003` WHERE `song_name` IS NOT NULL) AS `b` ON `a`.`song_id` = `b`.`song_id`) UNION (SELECT now(), '20170820', '整体' AS `pt`, a.song_id, if(b.song_name is null,'新发布歌曲',b.song_name), a.play_num_1d FROM (SELECT song_id, play_num_1d FROM (SELECT song_id, sum(play_num_1d) AS `play_num_1d` FROM `tb_002` WHERE `theday` = '20170820' GROUP BY `song_id`) AS `tmp` ORDER BY `play_num_1d` DESC LIMIT 0, 100) AS `a` INNER JOIN (SELECT song_id, song_name FROM `tb_003` WHERE `song_name` IS NOT NULL) AS `b` ON `a`.`song_id` = `b`.`song_id`)"; + + MySqlStatementParser parser = new MySqlStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + assertEquals("REPLACE INTO `tb_001` (`gmt_create`, `theday`, `pt`, `song_id`, `song_name`, `play_num_1d`)\n" + + "\t(SELECT now(), '20170820'\n" + + "\t\t, CASE a.pt\n" + + "\t\t\tWHEN 'android' THEN '安卓'\n" + + "\t\t\tWHEN 'ios' THEN 'ios'\n" + + "\t\t\tWHEN 'yunos' THEN '云os'\n" + + "\t\tEND AS `pt`, a.song_id\n" + + "\t\t, if(b.song_name IS NULL, '新发布歌曲', b.song_name)\n" + + "\t\t, a.play_num_1d\n" + + "\tFROM (\n" + + "\t\t(SELECT pt, song_id, SUM(play_num_1d) AS `play_num_1d`\n" + + "\t\tFROM `tb_002`\n" + + "\t\tWHERE `theday` = '20170820'\n" + + "\t\t\tAND `pt` IN ('android')\n" + + "\t\tGROUP BY `pt`, `song_id`\n" + + "\t\tORDER BY `play_num_1d` DESC\n" + + "\t\tLIMIT 0, 100)\n" + + "\t\tUNION\n" + + "\t\t(SELECT pt, song_id, SUM(play_num_1d) AS `play_num_1d`\n" + + "\t\tFROM `tb_002`\n" + + "\t\tWHERE `theday` = '20170820'\n" + + "\t\t\tAND `pt` IN ('ios')\n" + + "\t\tGROUP BY `pt`, `song_id`\n" + + "\t\tORDER BY `play_num_1d` DESC\n" + + "\t\tLIMIT 0, 100)\n" + + "\t\tUNION\n" + + "\t\t(SELECT pt, song_id, SUM(play_num_1d) AS `play_num_1d`\n" + + "\t\tFROM `tb_002`\n" + + "\t\tWHERE `theday` = '20170820'\n" + + "\t\t\tAND `pt` IN ('yunos')\n" + + "\t\tGROUP BY `pt`, `song_id`\n" + + "\t\tORDER BY `play_num_1d` DESC\n" + + "\t\tLIMIT 0, 100)\n" + + "\t) `a`\n" + + "\t\tINNER JOIN (\n" + + "\t\t\tSELECT song_id, song_name\n" + + "\t\t\tFROM `tb_003`\n" + + "\t\t\tWHERE `song_name` IS NOT NULL\n" + + "\t\t) `b`\n" + + "\t\tON `a`.`song_id` = `b`.`song_id`)\n" + + "\tUNION\n" + + "\t(SELECT now(), '20170820', '整体' AS `pt`, a.song_id\n" + + "\t\t, if(b.song_name IS NULL, '新发布歌曲', b.song_name)\n" + + "\t\t, a.play_num_1d\n" + + "\tFROM (\n" + + "\t\tSELECT song_id, play_num_1d\n" + + "\t\tFROM (\n" + + "\t\t\tSELECT song_id, SUM(play_num_1d) AS `play_num_1d`\n" + + "\t\t\tFROM `tb_002`\n" + + "\t\t\tWHERE `theday` = '20170820'\n" + + "\t\t\tGROUP BY `song_id`\n" + + "\t\t) `tmp`\n" + + "\t\tORDER BY `play_num_1d` DESC\n" + + "\t\tLIMIT 0, 100\n" + + "\t) `a`\n" + + "\t\tINNER JOIN (\n" + + "\t\t\tSELECT song_id, song_name\n" + + "\t\t\tFROM `tb_003`\n" + + "\t\t\tWHERE `song_name` IS NOT NULL\n" + + "\t\t) `b`\n" + + "\t\tON `a`.`song_id` = `b`.`song_id`)", SQLUtils.toMySqlString(stmt)); + assertEquals("replace into `tb_001` (`gmt_create`, `theday`, `pt`, `song_id`, `song_name`, `play_num_1d`)\n" + + "\t(select now(), '20170820'\n" + + "\t\t, case a.pt\n" + + "\t\t\twhen 'android' then '安卓'\n" + + "\t\t\twhen 'ios' then 'ios'\n" + + "\t\t\twhen 'yunos' then '云os'\n" + + "\t\tend as `pt`, a.song_id\n" + + "\t\t, if(b.song_name is null, '新发布歌曲', b.song_name)\n" + + "\t\t, a.play_num_1d\n" + + "\tfrom (\n" + + "\t\t(select pt, song_id, sum(play_num_1d) as `play_num_1d`\n" + + "\t\tfrom `tb_002`\n" + + "\t\twhere `theday` = '20170820'\n" + + "\t\t\tand `pt` in ('android')\n" + + "\t\tgroup by `pt`, `song_id`\n" + + "\t\torder by `play_num_1d` desc\n" + + "\t\tlimit 0, 100)\n" + + "\t\tunion\n" + + "\t\t(select pt, song_id, sum(play_num_1d) as `play_num_1d`\n" + + "\t\tfrom `tb_002`\n" + + "\t\twhere `theday` = '20170820'\n" + + "\t\t\tand `pt` in ('ios')\n" + + "\t\tgroup by `pt`, `song_id`\n" + + "\t\torder by `play_num_1d` desc\n" + + "\t\tlimit 0, 100)\n" + + "\t\tunion\n" + + "\t\t(select pt, song_id, sum(play_num_1d) as `play_num_1d`\n" + + "\t\tfrom `tb_002`\n" + + "\t\twhere `theday` = '20170820'\n" + + "\t\t\tand `pt` in ('yunos')\n" + + "\t\tgroup by `pt`, `song_id`\n" + + "\t\torder by `play_num_1d` desc\n" + + "\t\tlimit 0, 100)\n" + + "\t) `a`\n" + + "\t\tinner join (\n" + + "\t\t\tselect song_id, song_name\n" + + "\t\t\tfrom `tb_003`\n" + + "\t\t\twhere `song_name` is not null\n" + + "\t\t) `b`\n" + + "\t\ton `a`.`song_id` = `b`.`song_id`)\n" + + "\tunion\n" + + "\t(select now(), '20170820', '整体' as `pt`, a.song_id\n" + + "\t\t, if(b.song_name is null, '新发布歌曲', b.song_name)\n" + + "\t\t, a.play_num_1d\n" + + "\tfrom (\n" + + "\t\tselect song_id, play_num_1d\n" + + "\t\tfrom (\n" + + "\t\t\tselect song_id, sum(play_num_1d) as `play_num_1d`\n" + + "\t\t\tfrom `tb_002`\n" + + "\t\t\twhere `theday` = '20170820'\n" + + "\t\t\tgroup by `song_id`\n" + + "\t\t) `tmp`\n" + + "\t\torder by `play_num_1d` desc\n" + + "\t\tlimit 0, 100\n" + + "\t) `a`\n" + + "\t\tinner join (\n" + + "\t\t\tselect song_id, song_name\n" + + "\t\t\tfrom `tb_003`\n" + + "\t\t\twhere `song_name` is not null\n" + + "\t\t) `b`\n" + + "\t\ton `a`.`song_id` = `b`.`song_id`)", SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + + assertEquals(1, statementList.size()); + + MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor(); + stmt.accept(visitor); + +// System.out.println("Tables : " + visitor.getTables()); +// System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); +// System.out.println("orderBy : " + visitor.getOrderByColumns()); + + assertEquals(3, visitor.getTables().size()); + assertEquals(16, visitor.getColumns().size()); + assertEquals(8, visitor.getConditions().size()); + + assertTrue(visitor.containsTable("tb_001")); + +// assertTrue(visitor.containsColumn("t1", "id")); +// assertTrue(visitor.containsColumn("t1", "name")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_51_open.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_51_open.java new file mode 100644 index 0000000000..f7be99990e --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_51_open.java @@ -0,0 +1,82 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed 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 com.alibaba.druid.bvt.sql.mysql.select; + +import com.alibaba.druid.sql.MysqlTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.util.JdbcConstants; + +import java.util.List; + +public class MySqlSelectTest_51_open extends MysqlTest { + + public void test_0() throws Exception { + String sql = "select id as id, gmt_create as gmtCreate, gmt_modified as gmtModified, name as name, owner as owner, type as type, statement as statement, datasource as datasource, meta as meta, param_file as paramFile, sharable as sharable, data_type as dataType, status as status, config as config, project_id as projectId, plugins as plugins, field_compare as fieldCompare, field_ext as fieldExt, open as open from tb_001 where id = 12569434"; + + + List statementList = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL, true); + SQLStatement stmt = statementList.get(0); + + assertEquals(1, statementList.size()); + + SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(JdbcConstants.MYSQL); + stmt.accept(visitor); + +// System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); +// System.out.println("orderBy : " + visitor.getOrderByColumns()); + +// assertEquals(1, visitor.getTables().size()); +// assertEquals(1, visitor.getColumns().size()); +// assertEquals(0, visitor.getConditions().size()); +// assertEquals(0, visitor.getOrderByColumns().size()); + + { + String output = SQLUtils.toMySqlString(stmt); + assertEquals("SELECT id AS id, gmt_create AS gmtCreate, gmt_modified AS gmtModified, name AS name, owner AS owner\n" + + "\t, type AS type, statement AS statement, datasource AS datasource, meta AS meta, param_file AS paramFile\n" + + "\t, sharable AS sharable, data_type AS dataType, status AS status, config AS config, project_id AS projectId\n" + + "\t, plugins AS plugins, field_compare AS fieldCompare, field_ext AS fieldExt, open AS open\n" + + "FROM tb_001\n" + + "WHERE id = 12569434", // + output); + } + { + String output = SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION); + assertEquals("select id as id, gmt_create as gmtCreate, gmt_modified as gmtModified, name as name, owner as owner\n" + + "\t, type as type, statement as statement, datasource as datasource, meta as meta, param_file as paramFile\n" + + "\t, sharable as sharable, data_type as dataType, status as status, config as config, project_id as projectId\n" + + "\t, plugins as plugins, field_compare as fieldCompare, field_ext as fieldExt, open as open\n" + + "from tb_001\n" + + "where id = 12569434", // + output); + } + + { + String output = SQLUtils.toMySqlString(stmt, new SQLUtils.FormatOption(true, true, true)); + assertEquals("SELECT id AS id, gmt_create AS gmtCreate, gmt_modified AS gmtModified, name AS name, owner AS owner\n" + + "\t, type AS type, statement AS statement, datasource AS datasource, meta AS meta, param_file AS paramFile\n" + + "\t, sharable AS sharable, data_type AS dataType, status AS status, config AS config, project_id AS projectId\n" + + "\t, plugins AS plugins, field_compare AS fieldCompare, field_ext AS fieldExt, open AS open\n" + + "FROM tb\n" + + "WHERE id = ?", // + output); + } + } +}