mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
Merge branch 'master' of https://github.com/chenhaoyus/druid
Conflicts: src/main/java/com/alibaba/druid/sql/parser/SQLParserUtils.java
This commit is contained in:
@@ -37,6 +37,7 @@ public class MockConnection extends ConnectionBase implements Connection {
|
||||
|
||||
private final long createdTimeMillis = System.currentTimeMillis();
|
||||
private long lastActiveTimeMillis = System.currentTimeMillis();
|
||||
private int networkTimeout;
|
||||
|
||||
private SQLException error;
|
||||
|
||||
@@ -455,11 +456,11 @@ public class MockConnection extends ConnectionBase implements Connection {
|
||||
}
|
||||
|
||||
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException();
|
||||
this.networkTimeout = milliseconds;
|
||||
}
|
||||
|
||||
public int getNetworkTimeout() throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException();
|
||||
return networkTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -43,6 +43,7 @@ import java.io.Serializable;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
||||
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
|
||||
@@ -70,6 +71,8 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = 60 * 1000L;
|
||||
public static final long DEFAULT_TIME_BETWEEN_CONNECT_ERROR_MILLIS = 500;
|
||||
public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;
|
||||
public static final int DEFAULT_TIME_CONNECT_TIMEOUT_MILLIS = 10_000;
|
||||
public static final int DEFAULT_TIME_SOCKET_TIMEOUT_MILLIS = 10_000;
|
||||
|
||||
public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L;
|
||||
public static final long DEFAULT_MAX_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 60L * 7;
|
||||
@@ -119,8 +122,11 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
|
||||
protected Driver driver;
|
||||
|
||||
protected volatile int queryTimeout;
|
||||
protected volatile int transactionQueryTimeout;
|
||||
protected volatile int connectTimeout = DEFAULT_TIME_CONNECT_TIMEOUT_MILLIS; // milliSeconds
|
||||
protected volatile int socketTimeout = DEFAULT_TIME_SOCKET_TIMEOUT_MILLIS; // milliSeconds
|
||||
|
||||
protected volatile int queryTimeout; // seconds
|
||||
protected volatile int transactionQueryTimeout; // seconds
|
||||
|
||||
protected long createTimespan;
|
||||
|
||||
@@ -251,6 +257,8 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
protected volatile long failContinuousTimeMillis;
|
||||
protected ScheduledExecutorService destroyScheduler;
|
||||
protected ScheduledExecutorService createScheduler;
|
||||
protected Executor netTimeoutExecutor;
|
||||
protected volatile boolean netTimeoutError;
|
||||
|
||||
static final AtomicLongFieldUpdater<DruidAbstractDataSource> failContinuousTimeMillisUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "failContinuousTimeMillis");
|
||||
static final AtomicIntegerFieldUpdater<DruidAbstractDataSource> failContinuousUpdater = AtomicIntegerFieldUpdater.newUpdater(DruidAbstractDataSource.class, "failContinuous");
|
||||
@@ -995,6 +1003,38 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
this.queryTimeout = seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 1.2.12
|
||||
*/
|
||||
public int getConnectTimeout() {
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 1.2.12
|
||||
*/
|
||||
public void setConnectTimeout(int milliSeconds) {
|
||||
this.connectTimeout = milliSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 1.2.12
|
||||
*/
|
||||
public int getSocketTimeout() {
|
||||
return socketTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 1.2.12
|
||||
*/
|
||||
public void setSocketTimeout(int milliSeconds) {
|
||||
this.socketTimeout = milliSeconds;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if (name != null) {
|
||||
return name;
|
||||
@@ -1691,6 +1731,17 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
physicalConnectProperties.put("password", password);
|
||||
}
|
||||
|
||||
if (connectTimeout > 0) {
|
||||
if (isMySql) {
|
||||
physicalConnectProperties.put("connectTimeout", connectTimeout);
|
||||
} else if (isOracle) {
|
||||
physicalConnectProperties.put("oracle.net.CONNECT_TIMEOUT", connectTimeout);
|
||||
} else if (driver != null && "org.postgresql.Driver".equals(driver.getClass().getName())) {
|
||||
physicalConnectProperties.put("loginTimeout", connectTimeout);
|
||||
physicalConnectProperties.put("socketTimeout", connectTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
Connection conn = null;
|
||||
|
||||
long connectStartNanos = System.nanoTime();
|
||||
@@ -1716,6 +1767,16 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
initPhysicalConnection(conn, variables, globalVariables);
|
||||
initedNanos = System.nanoTime();
|
||||
|
||||
if (socketTimeout > 0 && !netTimeoutError) {
|
||||
try {
|
||||
conn.setNetworkTimeout(netTimeoutExecutor, socketTimeout);
|
||||
} catch (SQLFeatureNotSupportedException | AbstractMethodError e) {
|
||||
netTimeoutError = true;
|
||||
} catch (Exception ignored) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
validateConnection(conn);
|
||||
validatedNanos = System.nanoTime();
|
||||
|
||||
@@ -2225,4 +2286,19 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
return globalVairiables;
|
||||
}
|
||||
}
|
||||
|
||||
class SynchronousExecutor implements Executor {
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
try {
|
||||
command.run();
|
||||
} catch (AbstractMethodError error) {
|
||||
netTimeoutError = true;
|
||||
} catch (Exception ignored) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("failed to execute command " + command);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -866,6 +866,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
|
||||
initCheck();
|
||||
|
||||
this.netTimeoutExecutor = new SynchronousExecutor();
|
||||
|
||||
initExceptionSorter();
|
||||
initValidConnectionChecker();
|
||||
validationQueryCheck();
|
||||
@@ -1221,7 +1223,9 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
} else if (dbType == DbType.db2) {
|
||||
db2ValidationQueryCheck();
|
||||
} else if (dbType == DbType.mysql
|
||||
|| JdbcUtils.MYSQL_DRIVER_6.equals(this.driverClass)) {
|
||||
|| JdbcUtils.MYSQL_DRIVER.equals(this.driverClass)
|
||||
|| JdbcUtils.MYSQL_DRIVER_6.equals(this.driverClass)
|
||||
) {
|
||||
isMySql = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlSelectIntoStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
|
||||
import com.alibaba.druid.sql.dialect.odps.visitor.OdpsASTVisitorAdapter;
|
||||
import com.alibaba.druid.sql.dialect.odps.visitor.OdpsOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.odps.visitor.OdpsSchemaStatVisitor;
|
||||
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleOutputVisitor;
|
||||
@@ -49,10 +50,7 @@ import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerSchemaStatVisitor;
|
||||
import com.alibaba.druid.sql.parser.*;
|
||||
import com.alibaba.druid.sql.repository.SchemaRepository;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter;
|
||||
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
|
||||
import com.alibaba.druid.sql.visitor.VisitorFeature;
|
||||
import com.alibaba.druid.sql.visitor.*;
|
||||
import com.alibaba.druid.support.logging.Log;
|
||||
import com.alibaba.druid.support.logging.LogFactory;
|
||||
import com.alibaba.druid.util.*;
|
||||
@@ -63,6 +61,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class SQLUtils {
|
||||
public static final Charset UTF8 = Charset.forName("UTF-8");
|
||||
@@ -795,6 +795,55 @@ public class SQLUtils {
|
||||
return addSelectItem(selectSql, expr, alias, false, dbType);
|
||||
}
|
||||
|
||||
public static void acceptBooleanOr(String sql, DbType dbType, Consumer<SQLBinaryOpExprGroup> consumer) {
|
||||
acceptBinaryOpExpr(sql, dbType, consumer, e -> e.getOperator() == SQLBinaryOperator.BooleanOr);
|
||||
}
|
||||
|
||||
public static void acceptBinaryOpExpr(String sql, DbType dbType, Consumer<SQLBinaryOpExprGroup> consumer, Predicate<SQLBinaryOpExprGroup> filter) {
|
||||
if (sql == null || sql.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<SQLStatement> stmtList = new ArrayList<>();
|
||||
|
||||
try {
|
||||
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType, SQLParserFeature.EnableMultiUnion, SQLParserFeature.KeepComments, SQLParserFeature.EnableSQLBinaryOpExprGroup);
|
||||
parser.parseStatementList(stmtList, -1, null);
|
||||
} catch (Exception ignored) {
|
||||
return;
|
||||
}
|
||||
|
||||
SQLASTVisitor visitor;
|
||||
switch (dbType) {
|
||||
case odps:
|
||||
visitor = new OdpsASTVisitorAdapter() {
|
||||
@Override
|
||||
public boolean visit(SQLBinaryOpExprGroup x) {
|
||||
if (filter == null || filter.test(x)) {
|
||||
consumer.accept(x);
|
||||
}
|
||||
return super.visit(x);
|
||||
}
|
||||
};
|
||||
break;
|
||||
default:
|
||||
visitor = new SQLASTVisitorAdapter() {
|
||||
@Override
|
||||
public boolean visit(SQLBinaryOpExprGroup x) {
|
||||
if (filter == null || filter.test(x)) {
|
||||
consumer.accept(x);
|
||||
}
|
||||
return super.visit(x);
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
for (SQLStatement stmt : stmtList) {
|
||||
stmt.accept(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
public static String addSelectItem(String selectSql, String expr, String alias, boolean first, DbType dbType) {
|
||||
List<SQLStatement> stmtList = parseStatements(selectSql, dbType);
|
||||
|
||||
|
||||
@@ -19,9 +19,7 @@ import com.alibaba.druid.DbType;
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLName;
|
||||
import com.alibaba.druid.sql.ast.SQLPartitionBy;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIntervalExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIntervalUnit;
|
||||
import com.alibaba.druid.sql.ast.expr.*;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
|
||||
@@ -153,7 +151,13 @@ public class DB2OutputVisitor extends SQLASTOutputVisitor implements DB2ASTVisit
|
||||
|
||||
public boolean visit(SQLIntervalExpr x) {
|
||||
SQLExpr value = x.getValue();
|
||||
value.accept(this);
|
||||
if (value instanceof SQLLiteralExpr || value instanceof SQLName || value instanceof SQLVariantRefExpr) {
|
||||
value.accept(this);
|
||||
} else {
|
||||
print('(');
|
||||
value.accept(this);
|
||||
print(')');
|
||||
}
|
||||
|
||||
SQLIntervalUnit unit = x.getUnit();
|
||||
if (unit != null) {
|
||||
|
||||
@@ -2255,7 +2255,7 @@ public class Lexer {
|
||||
boolean ident = false;
|
||||
for (; ; ) {
|
||||
ch = charAt(++pos);
|
||||
if (isEOF()) {
|
||||
if (isEOF() || ch == ';' || ch == ';') {
|
||||
pos--;
|
||||
bufPos--;
|
||||
break;
|
||||
@@ -2287,7 +2287,7 @@ public class Lexer {
|
||||
this.ch = charAt(pos);
|
||||
|
||||
if (dbType == DbType.odps) {
|
||||
while (isIdentifierChar(this.ch)) {
|
||||
while (isIdentifierChar(this.ch) && ch != ';') {
|
||||
++pos;
|
||||
bufPos++;
|
||||
this.ch = charAt(pos);
|
||||
|
||||
@@ -26,6 +26,8 @@ import com.alibaba.druid.sql.dialect.ads.parser.AdsStatementParser;
|
||||
import com.alibaba.druid.sql.dialect.antspark.parser.AntsparkLexer;
|
||||
import com.alibaba.druid.sql.dialect.antspark.parser.AntsparkStatementParser;
|
||||
import com.alibaba.druid.sql.dialect.blink.parser.BlinkStatementParser;
|
||||
import com.alibaba.druid.sql.dialect.clickhouse.parser.ClickhouseExprParser;
|
||||
import com.alibaba.druid.sql.dialect.clickhouse.parser.ClickhouseLexer;
|
||||
import com.alibaba.druid.sql.dialect.clickhouse.parser.ClickhouseStatementParser;
|
||||
import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2SelectQueryBlock;
|
||||
import com.alibaba.druid.sql.dialect.db2.parser.DB2ExprParser;
|
||||
@@ -48,10 +50,6 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock;
|
||||
import com.alibaba.druid.sql.dialect.oracle.parser.OracleExprParser;
|
||||
import com.alibaba.druid.sql.dialect.oracle.parser.OracleLexer;
|
||||
import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser;
|
||||
import com.alibaba.druid.sql.dialect.oscar.ast.stmt.OscarSelectQueryBlock;
|
||||
import com.alibaba.druid.sql.dialect.oscar.parser.OscarExprParser;
|
||||
import com.alibaba.druid.sql.dialect.oscar.parser.OscarLexer;
|
||||
import com.alibaba.druid.sql.dialect.oscar.visitor.OscarStatementParser;
|
||||
import com.alibaba.druid.sql.dialect.phoenix.parser.PhoenixExprParser;
|
||||
import com.alibaba.druid.sql.dialect.phoenix.parser.PhoenixLexer;
|
||||
import com.alibaba.druid.sql.dialect.phoenix.parser.PhoenixStatementParser;
|
||||
@@ -144,8 +142,6 @@ public class SQLParserUtils {
|
||||
return new AntsparkStatementParser(sql);
|
||||
case clickhouse:
|
||||
return new ClickhouseStatementParser(sql);
|
||||
case oscar:
|
||||
return new OscarStatementParser(sql);
|
||||
default:
|
||||
return new SQLStatementParser(sql, dbType);
|
||||
}
|
||||
@@ -186,6 +182,8 @@ public class SQLParserUtils {
|
||||
return new PrestoExprParser(sql, features);
|
||||
case hive:
|
||||
return new HiveExprParser(sql, features);
|
||||
case clickhouse:
|
||||
return new ClickhouseExprParser(sql, features);
|
||||
case oscar:
|
||||
return new OscarExprParser(sql, features);
|
||||
default:
|
||||
@@ -231,6 +229,8 @@ public class SQLParserUtils {
|
||||
return new AntsparkLexer(sql);
|
||||
case oscar:
|
||||
return new OscarLexer(sql);
|
||||
case clickhouse:
|
||||
return new ClickhouseLexer(sql);
|
||||
default:
|
||||
return new Lexer(sql, null, dbType);
|
||||
}
|
||||
|
||||
@@ -637,6 +637,8 @@ public final class JdbcUtils implements JdbcConstants {
|
||||
return DbType.highgo;
|
||||
} else if (rawUrl.startsWith("jdbc:pivotal:greenplum:") || rawUrl.startsWith("jdbc:datadirect:greenplum:")) {
|
||||
return DbType.greenplum;
|
||||
} else if (rawUrl.startsWith("jdbc:gaussdb:") || rawUrl.startsWith("jdbc:dws:iam:")) {
|
||||
return DbType.gaussdb;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.alibaba.druid.sql.dialect.db2.visitor;
|
||||
|
||||
import com.alibaba.druid.DbType;
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.parser.SQLParserUtils;
|
||||
import com.alibaba.druid.sql.parser.SQLStatementParser;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abomb4 2022-06-19
|
||||
*/
|
||||
public class DB2OutputVisitorTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
List<TestCase> testCases = Arrays.asList(
|
||||
new TestCase("interval 表达式应该带括号 select",
|
||||
"SELECT A, B, C FROM D WHERE C < CURRENT TIMESTAMP + (10 * 60) SECONDS",
|
||||
"SELECT A, B, C FROM D WHERE C < CURRENT TIMESTAMP + (10 * 60) SECONDS"),
|
||||
new TestCase("interval 表达式应该带括号 insert",
|
||||
"INSERT INTO TEST VALUES (1, CURRENT TIMESTAMP + ((10 + 60) SECONDS))",
|
||||
"INSERT INTO TEST VALUES (1, CURRENT TIMESTAMP + (10 + 60) SECONDS)"),
|
||||
new TestCase("interval 表达式应该带括号 update",
|
||||
"UPDATE test SET created = CURRENT TIMESTAMP + 10 SECONDS WHERE created < CURRENT TIMESTAMP + (10 * 60) SECONDS",
|
||||
"UPDATE test SET created = CURRENT TIMESTAMP + (10) SECONDS WHERE created < CURRENT TIMESTAMP + (10 * 60) SECONDS")
|
||||
);
|
||||
|
||||
for (TestCase testCase : testCases) {
|
||||
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(testCase.origin, DbType.db2);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
DB2OutputVisitor visitor = new DB2OutputVisitor(builder);
|
||||
visitor.setUppCase(false);
|
||||
visitor.setPrettyFormat(false);
|
||||
visitor.setParameterized(false);
|
||||
SQLStatement stmt = parser.parseStatement();
|
||||
stmt.accept(visitor);
|
||||
String result = builder.toString();
|
||||
Assert.assertEquals(testCase.name, testCase.expected, result);
|
||||
}
|
||||
System.out.println("DB2 Interval test ok.");
|
||||
}
|
||||
|
||||
private static class TestCase {
|
||||
String name;
|
||||
String origin;
|
||||
String expected;
|
||||
|
||||
public TestCase(String name, String origin, String expected) {
|
||||
this.name = name;
|
||||
this.origin = origin;
|
||||
this.expected = expected;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user