Conflicts:
	src/main/java/com/alibaba/druid/sql/parser/SQLParserUtils.java
This commit is contained in:
chenhaoyus
2022-08-29 10:11:48 +08:00
9 changed files with 216 additions and 21 deletions
@@ -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;
}
}
}