improved mysql parser.

This commit is contained in:
wenshao
2017-08-20 18:23:47 +08:00
parent 1b557fbc0a
commit 17772cde69
6 changed files with 271 additions and 5 deletions
@@ -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;
}
@@ -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;
@@ -240,6 +240,7 @@ public class SQLParser {
case ADVISE:
case TYPE:
case CLOSE:
case OPEN:
alias = lexer.stringVal();
lexer.nextToken();
return alias;
@@ -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);
}
}
@@ -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<SQLStatement> 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"));
}
}
@@ -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<SQLStatement> 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);
}
}
}