diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlInsertStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlInsertStatement.java index 390d6f0e91..ffdaad94d3 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlInsertStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlInsertStatement.java @@ -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 duplicateKeyUpdate = new ArrayList(); @@ -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) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java index 4905196e0c..4b954b3c6d 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java @@ -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; } 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 7ffb1f71ad..6bba3f5f04 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 @@ -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) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java index ba6ae99b8c..98076c2a27 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java @@ -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 "); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlInsertTest_11.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlInsertTest_11.java new file mode 100644 index 0000000000..b80a2286f9 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlInsertTest_11.java @@ -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 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)); + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlUpdateTest_8.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlUpdateTest_8.java new file mode 100644 index 0000000000..4874ab7491 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlUpdateTest_8.java @@ -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 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); + } + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/schemaStat/SchemaStatTest4.java b/src/test/java/com/alibaba/druid/bvt/sql/schemaStat/SchemaStatTest4.java new file mode 100644 index 0000000000..6b1217d82f --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/schemaStat/SchemaStatTest4.java @@ -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 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()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/schemaStat/SchemaStatTest5.java b/src/test/java/com/alibaba/druid/bvt/sql/schemaStat/SchemaStatTest5.java new file mode 100644 index 0000000000..7dddde8a94 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/schemaStat/SchemaStatTest5.java @@ -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 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()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/schemaStat/SchemaStatTest6.java b/src/test/java/com/alibaba/druid/bvt/sql/schemaStat/SchemaStatTest6.java new file mode 100644 index 0000000000..8129451b5b --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/schemaStat/SchemaStatTest6.java @@ -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()); + } +} diff --git a/src/test/java/com/alibaba/druid/pool/postgres/PG_500_connection_Test.java b/src/test/java/com/alibaba/druid/pool/postgres/PG_500_connection_Test.java new file mode 100644 index 0000000000..686ac9ead3 --- /dev/null +++ b/src/test/java/com/alibaba/druid/pool/postgres/PG_500_connection_Test.java @@ -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(); + + } +}