improved sql parser

This commit is contained in:
高铁
2016-05-19 01:06:49 +08:00
parent 186cfb6a80
commit 352a7ca08b
10 changed files with 360 additions and 16 deletions
@@ -30,6 +30,7 @@ public class MySqlInsertStatement extends SQLInsertStatement {
private boolean delayed = false;
private boolean highPriority = false;
private boolean ignore = false;
private boolean rollbackOnFail = false;
private final List<SQLExpr> duplicateKeyUpdate = new ArrayList<SQLExpr>();
@@ -69,6 +70,14 @@ public class MySqlInsertStatement extends SQLInsertStatement {
this.ignore = ignore;
}
public boolean isRollbackOnFail() {
return rollbackOnFail;
}
public void setRollbackOnFail(boolean rollbackOnFail) {
this.rollbackOnFail = rollbackOnFail;
}
@Override
protected void accept0(SQLASTVisitor visitor) {
if (visitor instanceof MySqlASTVisitor) {
@@ -249,11 +249,17 @@ public class MySqlLexer extends Lexer {
mark = pos;
bufPos = 1;
char ch;
char ch = '\0', last_ch;
for (;;) {
last_ch = ch;
ch = charAt(++pos);
if (!isIdentifierChar(ch)) {
if (last_ch == '-' && charAt(pos-2) != '-') {
ch = last_ch;
bufPos--;
pos--;
}
break;
}
@@ -1936,24 +1936,38 @@ public class MySqlStatementParser extends SQLStatementParser {
if (lexer.token() == Token.INSERT) {
lexer.nextToken();
if (identifierEquals(LOW_PRIORITY)) {
insertStatement.setLowPriority(true);
lexer.nextToken();
}
for (;;) {
if (identifierEquals(LOW_PRIORITY)) {
insertStatement.setLowPriority(true);
lexer.nextToken();
continue;
}
if (identifierEquals(DELAYED)) {
insertStatement.setDelayed(true);
lexer.nextToken();
}
if (identifierEquals(DELAYED)) {
insertStatement.setDelayed(true);
lexer.nextToken();
continue;
}
if (identifierEquals("HIGH_PRIORITY")) {
insertStatement.setHighPriority(true);
lexer.nextToken();
}
if (identifierEquals("HIGH_PRIORITY")) {
insertStatement.setHighPriority(true);
lexer.nextToken();
continue;
}
if (identifierEquals(IGNORE)) {
insertStatement.setIgnore(true);
lexer.nextToken();
if (identifierEquals(IGNORE)) {
insertStatement.setIgnore(true);
lexer.nextToken();
continue;
}
if (identifierEquals("ROLLBACK_ON_FAIL")) {
insertStatement.setRollbackOnFail(true);
lexer.nextToken();
continue;
}
break;
}
if (lexer.token() == Token.INTO) {
@@ -941,6 +941,10 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
if (x.isIgnore()) {
print0(ucase ? "IGNORE " : "ignore ");
}
if (x.isRollbackOnFail()) {
print0(ucase ? "ROLLBACK_ON_FAIL " : "rollback_on_fail ");
}
print0(ucase ? "INTO " : "into ");
@@ -0,0 +1,55 @@
/*
* Copyright 1999-2101 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 java.util.List;
import org.junit.Assert;
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.ast.statement.MySqlInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
public class MySqlInsertTest_11 extends MysqlTest {
public void test_insert_rollback_on_fail() throws Exception {
String sql = "insert ROLLBACK_ON_FAIL into t(a,b) values ('a1','b1')";
MySqlStatementParser parser = new MySqlStatementParser(sql);
parser.setParseCompleteValues(false);
parser.setParseValuesSize(3);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement stmt = statementList.get(0);
MySqlInsertStatement insertStmt = (MySqlInsertStatement) stmt;
Assert.assertEquals(1, insertStmt.getValuesList().size());
Assert.assertEquals(2, insertStmt.getValues().getValues().size());
Assert.assertEquals(2, insertStmt.getColumns().size());
Assert.assertEquals(1, statementList.size());
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
stmt.accept(visitor);
String formatSql = "INSERT ROLLBACK_ON_FAIL INTO t (a, b)"//
+ "\nVALUES ('a1', 'b1')";
Assert.assertEquals(formatSql, SQLUtils.toMySqlString(insertStmt));
}
}
@@ -0,0 +1,74 @@
/*
* Copyright 1999-2101 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 java.util.List;
import org.junit.Assert;
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 com.alibaba.druid.stat.TableStat;
import com.alibaba.druid.stat.TableStat.Column;
public class MySqlUpdateTest_8 extends MysqlTest {
public void test_0() throws Exception {
String sql = "update haskell_function set `arity` = arity-'1' where id = 1;";
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement stmt = statementList.get(0);
print(statementList);
Assert.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());
Assert.assertEquals(1, visitor.getTables().size());
Assert.assertEquals(2, visitor.getColumns().size());
Assert.assertEquals(1, visitor.getConditions().size());
Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("haskell_function")));
Assert.assertTrue(visitor.getColumns().contains(new Column("haskell_function", "arity")));
Assert.assertTrue(visitor.getColumns().contains(new Column("haskell_function", "id")));
{
String output = SQLUtils.toMySqlString(stmt);
Assert.assertEquals("UPDATE haskell_function"
+ "\nSET `arity` = arity - '1'"
+ "\nWHERE id = 1", //
output);
}
{
String output = SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION);
Assert.assertEquals("update haskell_function"
+ "\nset `arity` = arity - '1'"
+ "\nwhere id = 1", //
output);
}
}
}
@@ -0,0 +1,32 @@
package com.alibaba.druid.bvt.sql.schemaStat;
import java.util.List;
import org.junit.Assert;
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 junit.framework.TestCase;
public class SchemaStatTest4 extends TestCase {
public void test_schemaStat() throws Exception {
String sql = "select name, age from t_user where id = 1";
String dbType = JdbcConstants.MYSQL;
List<SQLStatement> stmtList = SQLUtils.parseStatements(sql, dbType);
SQLStatement stmt = stmtList.get(0);
SchemaStatVisitor statVisitor = SQLUtils.createSchemaStatVisitor(dbType);
stmt.accept(statVisitor);
System.out.println(statVisitor.getColumns());
System.out.println(statVisitor.getTables());
System.out.println(statVisitor.getConditions());
Assert.assertEquals(3, statVisitor.getColumns().size());
}
}
@@ -0,0 +1,32 @@
package com.alibaba.druid.bvt.sql.schemaStat;
import java.util.List;
import org.junit.Assert;
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 junit.framework.TestCase;
public class SchemaStatTest5 extends TestCase {
public void test_schemaStat() throws Exception {
String sql = "create table t_org (fid int, name varchar(256))";
String dbType = JdbcConstants.MYSQL;
List<SQLStatement> stmtList = SQLUtils.parseStatements(sql, dbType);
SQLStatement stmt = stmtList.get(0);
SchemaStatVisitor statVisitor = SQLUtils.createSchemaStatVisitor(dbType);
stmt.accept(statVisitor);
System.out.println(statVisitor.getColumns());
System.out.println(statVisitor.getTables());
System.out.println(statVisitor.getConditions());
Assert.assertEquals(2, statVisitor.getColumns().size());
}
}
@@ -0,0 +1,31 @@
package com.alibaba.druid.bvt.sql.schemaStat;
import org.junit.Assert;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.parser.SQLParserUtils;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
import com.alibaba.druid.util.JdbcConstants;
import junit.framework.TestCase;
public class SchemaStatTest6 extends TestCase {
public void test_schemaStat() throws Exception {
String sql = "select count(1), name from tg_rpc_user where id < 5 group by name order by id desc";
String dbType = JdbcConstants.MYSQL;
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType);
SQLStatement stmt = parser.parseStatementList().get(0);
SchemaStatVisitor statVisitor = SQLUtils.createSchemaStatVisitor(dbType);
stmt.accept(statVisitor);
System.out.println(statVisitor.getColumns());
System.out.println(statVisitor.getGroupByColumns()); // group by
Assert.assertEquals(2, statVisitor.getColumns().size());
}
}
@@ -0,0 +1,87 @@
package com.alibaba.druid.pool.postgres;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Assert;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.vendor.PGValidConnectionChecker;
import com.alibaba.druid.util.JdbcUtils;
import junit.framework.TestCase;
/**
* 这个场景测试minIdle > maxActive
*
* @author wenshao [szujobs@hotmail.com]
*/
public class PG_500_connection_Test extends TestCase {
private DruidDataSource dataSource;
protected void setUp() throws Exception {
dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:postgresql://192.168.199.231:5432/druid_test_db");
dataSource.setUsername("druid_test");
dataSource.setPassword("druid_test");
dataSource.setInitialSize(50);
dataSource.setMaxActive(80);
dataSource.setMinIdle(50);
dataSource.setMinEvictableIdleTimeMillis(300 * 1000); // 300 / 10
dataSource.setTimeBetweenEvictionRunsMillis(180 * 1000); // 180 / 10
dataSource.setTestWhileIdle(false);
dataSource.setTestOnBorrow(false);
// dataSource.setValidationQuery("SELECT 1 FROM DUAL");
dataSource.setFilters("stat");
}
protected void tearDown() throws Exception {
dataSource.close();
}
public void test_conect_500() throws Exception {
dataSource.init();
Assert.assertFalse(dataSource.isOracle());
Assert.assertTrue(dataSource.getValidConnectionChecker() instanceof PGValidConnectionChecker);
int taskCount = 1000 * 100;
final CountDownLatch endLatch = new CountDownLatch(taskCount);
Runnable task = new Runnable() {
@Override
public void run() {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = dataSource.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT 1");
while (rs.next()) {
}
} catch (SQLException ex) {
// skip
} finally {
endLatch.countDown();
}
JdbcUtils.close(rs);
JdbcUtils.close(stmt);
JdbcUtils.close(conn);
}
};
ExecutorService executor = Executors.newFixedThreadPool(100);
for (int i = 0; i < taskCount; ++i) {
executor.submit(task);
}
endLatch.await();
}
}