package com.alibaba.datax.plugin.rdbms.util;
import com.alibaba.datax.common.exception.DataXException;
import com.alibaba.datax.common.util.Configuration;
import com.alibaba.datax.common.util.RetryUtil;
import com.alibaba.datax.plugin.rdbms.reader.Key;
import com.alibaba.druid.sql.parser.SQLParserUtils;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutableTriple;
import org.apache.commons.lang3.tuple.Triple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.sql.*;
import java.util.*;
import java.util.concurrent.*;
public final class DBUtil {
private static final Logger LOG = LoggerFactory.getLogger(DBUtil.class);
private static final ThreadLocal<ExecutorService> rsExecutors = new ThreadLocal<ExecutorService>() {
@Override
protected ExecutorService initialValue() {
return Executors.newFixedThreadPool(1, new ThreadFactoryBuilder()
.setNameFormat("rsExecutors-%d")
.setDaemon(true)
.build());
}
};
private DBUtil() {
}
public static String chooseJdbcUrl(final DataBaseType dataBaseType,
final List<String> jdbcUrls, final String username,
final String password, final List<String> preSql,
final boolean checkSlave) {
if (null == jdbcUrls || jdbcUrls.isEmpty()) {
throw DataXException.asDataXException(
DBUtilErrorCode.CONF_ERROR,
String.format("您的jdbcUrl的配置信息有错, 因为jdbcUrl[%s]不能为空. 请检查您的配置并作出修改.",
StringUtils.join(jdbcUrls, ",")));
}
try {
return RetryUtil.executeWithRetry(new Callable<String>() {
@Override
public String call() throws Exception {
boolean connOK = false;
for (String url : jdbcUrls) {
if (StringUtils.isNotBlank(url)) {
url = url.trim();
if (null != preSql && !preSql.isEmpty()) {
connOK = testConnWithoutRetry(dataBaseType,
url, username, password, preSql);
} else {
connOK = testConnWithoutRetry(dataBaseType,
url, username, password, checkSlave);
}
if (connOK) {
return url;
}
}
}
throw new Exception("DataX无法连接对应的数据库,可能原因是:1) 配置的ip/port/database/jdbc错误,无法连接。2) 配置的username/password错误,鉴权失败。请和DBA确认该数据库的连接信息是否正确。");
// throw new Exception(DBUtilErrorCode.JDBC_NULL.toString());
}
}, 7, 1000L, true);
//warn: 7 means 2 minutes
} catch (Exception e) {
throw DataXException.asDataXException(
DBUtilErrorCode.CONN_DB_ERROR,
String.format("数据库连接失败. 因为根据您配置的连接信息,无法从:%s 中找到可连接的jdbcUrl. 请检查您的配置并作出修改.",
StringUtils.join(jdbcUrls, ",")), e);
}
}
public static String chooseJdbcUrlWithoutRetry(final DataBaseType dataBaseType,
final List<String> jdbcUrls, final String username,
final String password, final List<String> preSql,
final boolean checkSlave) throws DataXException {
if (null == jdbcUrls || jdbcUrls.isEmpty()) {
throw DataXException.asDataXException(
DBUtilErrorCode.CONF_ERROR,
String.format("您的jdbcUrl的配置信息有错, 因为jdbcUrl[%s]不能为空. 请检查您的配置并作出修改.",
StringUtils.join(jdbcUrls, ",")));
}
boolean connOK = false;
for (String url : jdbcUrls) {
if (StringUtils.isNotBlank(url)) {
url = url.trim();
if (null != preSql && !preSql.isEmpty()) {
connOK = testConnWithoutRetry(dataBaseType,
url, username, password, preSql);
} else {
try {
connOK = testConnWithoutRetry(dataBaseType,
url, username, password, checkSlave);
} catch (Exception e) {
throw DataXException.asDataXException(
DBUtilErrorCode.CONN_DB_ERROR,
String.format("数据库连接失败. 因为根据您配置的连接信息,无法从:%s 中找到可连接的jdbcUrl. 请检查您的配置并作出修改.",
StringUtils.join(jdbcUrls, ",")), e);
}
}
if (connOK) {
return url;
}
}
}
throw DataXException.asDataXException(
DBUtilErrorCode.CONN_DB_ERROR,
String.format("数据库连接失败. 因为根据您配置的连接信息,无法从:%s 中找到可连接的jdbcUrl. 请检查您的配置并作出修改.",
StringUtils.join(jdbcUrls, ",")));
}
/**
* 检查slave的库中的数据是否已到凌晨00:00
* 如果slave同步的数据还未到00:00返回false
* 否则范围true
*
* @author ZiChi
* @version 1.0 2014-12-01
*/
private static boolean isSlaveBehind(Connection conn) {
try {
ResultSet rs = query(conn, "SHOW VARIABLES LIKE 'read_only'");
if (DBUtil.asyncResultSetNext(rs)) {
String readOnly = rs.getString("Value");
if ("ON".equalsIgnoreCase(readOnly)) { //备库
ResultSet rs1 = query(conn, "SHOW SLAVE STATUS");
if (DBUtil.asyncResultSetNext(rs1)) {
String ioRunning = rs1.getString("Slave_IO_Running");
String sqlRunning = rs1.getString("Slave_SQL_Running");
long secondsBehindMaster = rs1.getLong("Seconds_Behind_Master");
if ("Yes".equalsIgnoreCase(ioRunning) && "Yes".equalsIgnoreCase(sqlRunning)) {
ResultSet rs2 = query(conn, "SELECT TIMESTAMPDIFF(SECOND, CURDATE(), NOW())");
DBUtil.asyncResultSetNext(rs2);
long secondsOfDay = rs2.getLong(1);
return secondsBehindMaster > secondsOfDay;
} else {
return true;
}
} else {
LOG.warn("SHOW SLAVE STATUS has no result");
}
}
} else {
LOG.warn("SHOW VARIABLES like 'read_only' has no result");
}
} catch (Exception e) {
LOG.warn("checkSlave failed, errorMessage:[{}].", e.getMessage());
}
return false;
}
/**
* 检查表是否具有insert 权限
* insert on *.* 或者 insert on database.* 时验证通过
* 当insert on database.tableName时,确保tableList中的所有table有insert 权限,验证通过
* 其它验证都不通过
*
* @author ZiChi
* @version 1.0 2015-01-28
*/
public static boolean hasInsertPrivilege(DataBaseType dataBaseType, String jdbcURL, String userName, String password, List<String> tableList) {
/*准备参数*/
String[] urls = jdbcURL.split("/");
String dbName;
if (urls != null && urls.length != 0) {
dbName = urls[3];
}else{
return false;
}
String dbPattern = "`" + dbName + "`.*";
Collection<String> tableNames = new HashSet<String>(tableList.size());
tableNames.addAll(tableList);
Connection connection = connect(dataBaseType, jdbcURL, userName, password);
try {
ResultSet rs = query(connection, "SHOW GRANTS FOR " + userName);
while (DBUtil.asyncResultSetNext(rs)) {
String grantRecord = rs.getString("Grants for " + userName + "@%");
String[] params = grantRecord.split("\\`");
if (params != null && params.length >= 3) {
String tableName = params[3];
if (params[0].contains("INSERT") && !tableName.equals("*") && tableNames.contains(tableName))
tableNames.remove(tableName);
} else {
if (grantRecord.contains("INSERT") ||grantRecord.contains("ALL PRIVILEGES")) {
if (grantRecord.contains("*.*"))
return true;
else if (grantRecord.contains(dbPattern)) {
return true;
}
}
}
}
} catch (Exception e) {
LOG.warn("Check the database has the Insert Privilege failed, errorMessage:[{}]", e.getMessage());
}
if (tableNames.isEmpty())
return true;
return false;
}
public static boolean checkInsertPrivilege(DataBaseType dataBaseType, String jdbcURL, String userName, String password, List<String> tableList) {
Connection connection = connect(dataBaseType, jdbcURL, userName, password);
String insertTemplate = "insert into %s(select * from %s where 1 = 2)";
boolean hasInsertPrivilege = true;
Statement insertStmt = null;
for(String tableName : tableList) {
String checkInsertPrivilegeSql = String.format(insertTemplate, tableName, tableName);
try {
insertStmt = connection.createStatement();
executeSqlWithoutResultSet(insertStmt, checkInsertPrivilegeSql);
} catch (Exception e) {
if(DataBaseType.Oracle.equals(dataBaseType)) {
if(e.getMessage() != null && e.getMessage().contains("insufficient privileges")) {
hasInsertPrivilege = false;
LOG.warn("User [" + userName +"] has no 'insert' privilege on table[" + tableName + "], errorMessage:[{}]", e.getMessage());
}
} else {
hasInsertPrivilege = false;
LOG.warn("User [" + userName + "] has no 'insert' privilege on table[" + tableName + "], errorMessage:[{}]", e.getMessage());
}
}
}
try {
connection.close();
} catch (SQLException e) {
LOG.warn("connection close failed, " + e.getMessage());
}
return hasInsertPrivilege;
}
public static boolean checkDeletePrivilege(DataBaseType dataBaseType,String jdbcURL, String userName, String password, List<String> tableList) {
Connection connection = connect(dataBaseType, jdbcURL, userName, password);
String deleteTemplate = "delete from %s WHERE 1 = 2";
boolean hasInsertPrivilege = true;
Statement deleteStmt = null;
for(String tableName : tableList) {
String checkDeletePrivilegeSQL = String.format(deleteTemplate, tableName);
try {
deleteStmt = connection.createStatement();
executeSqlWithoutResultSet(deleteStmt, checkDeletePrivilegeSQL);
} catch (Exception e) {
hasInsertPrivilege = false;
LOG.warn("User [" + userName +"] has no 'delete' privilege on table[" + tableName + "], errorMessage:[{}]", e.getMessage());
}
}
try {
connection.close();
} catch (SQLException e) {
LOG.warn("connection close failed, " + e.getMessage());
}
return hasInsertPrivilege;
}
public static boolean needCheckDeletePrivilege(Configuration originalConfig) {
List<String> allSqls =new ArrayList<String>();
List<String> preSQLs = originalConfig.getList(Key.PRE_SQL, String.class);
List<String> postSQLs = originalConfig.getList(Key.POST_SQL, String.class);
if (preSQLs != null && !preSQLs.isEmpty()){
allSqls.addAll(preSQLs);
}
if (postSQLs != null && !postSQLs.isEmpty()){
allSqls.addAll(postSQLs);
}
for(String sql : allSqls) {
if(StringUtils.isNotBlank(sql)) {
if (sql.trim().toUpperCase().startsWith("DELETE")) {
return true;
}
}
}
return false;
}
/**
* Get direct JDBC connection
* <p/>
* if connecting failed, try to connect for MAX_TRY_TIMES times
* <p/>
* NOTE: In DataX, we don't need connection pool in fact
*/
public static Connection getConnection(final DataBaseType dataBaseType,
final String jdbcUrl, final String username, final String password) {
return getConnection(dataBaseType, jdbcUrl, username, password, String.valueOf(Constant.SOCKET_TIMEOUT_INSECOND * 1000));
}
/**
*
* @param dataBaseType
* @param jdbcUrl
* @param username
* @param password
* @param socketTimeout 设置socketTimeout,单位ms,String类型
* @return
*/
public static Connection getConnection(final DataBaseType dataBaseType,
final String jdbcUrl, final String username, final String password, final String socketTimeout) {
try {
return RetryUtil.executeWithRetry(new Callable<Connection>() {
@Override
public Connection call() throws Exception {
return DBUtil.connect(dataBaseType, jdbcUrl, username,
password, socketTimeout);
}
}, 9, 1000L, true);
} catch (Exception e) {
throw DataXException.asDataXException(
DBUtilErrorCode.CONN_DB_ERROR,
String.format("数据库连接失败. 因为根据您配置的连接信息:%s获取数据库连接失败. 请检查您的配置并作出修改.", jdbcUrl), e);
}
}
/**
* Get direct JDBC connection
* <p/>
* if connecting failed, try to connect for MAX_TRY_TIMES times
* <p/>
* NOTE: In DataX, we don't need connection pool in fact
*/
public static Connection getConnectionWithoutRetry(final DataBaseType dataBaseType,
final String jdbcUrl, final String username, final String password) {
return getConnectionWithoutRetry(dataBaseType, jdbcUrl, username,
password, String.valueOf(Constant.SOCKET_TIMEOUT_INSECOND * 1000));
}
public static Connection getConnectionWithoutRetry(final DataBaseType dataBaseType,
final String jdbcUrl, final String username, final String password, String socketTimeout) {
return DBUtil.connect(dataBaseType, jdbcUrl, username,
password, socketTimeout);
}
private static synchronized Connection connect(DataBaseType dataBaseType,
String url, String user, String pass) {
return connect(dataBaseType, url, user, pass, String.valueOf(Constant.SOCKET_TIMEOUT_INSECOND * 1000));
}
private static synchronized Connection connect(DataBaseType dataBaseType,
String url, String user, String pass, String socketTimeout) {
//ob10的处理
if (url.startsWith(com.alibaba.datax.plugin.rdbms.writer.Constant.OB10_SPLIT_STRING) && dataBaseType == DataBaseType.MySql) {
String[] ss = url.split(com.alibaba.datax.plugin.rdbms.writer.Constant.OB10_SPLIT_STRING_PATTERN);
if (ss.length != 3) {
throw DataXException
.asDataXException(
DBUtilErrorCode.JDBC_OB10_ADDRESS_ERROR, "JDBC OB10格式错误,请联系askdatax");
}
LOG.info("this is ob1_0 jdbc url.");
user = ss[1].trim() +":"+user;
url = ss[2];
LOG.info("this is ob1_0 jdbc url. user="+user+" :url="+url);
}
Properties prop = new Properties();
prop.put("user", user);
prop.put("password", pass);
if (dataBaseType == DataBaseType.Oracle) {
//oracle.net.READ_TIMEOUT for jdbc versions < 10.1.0.5 oracle.jdbc.ReadTimeout for jdbc versions >=10.1.0.5
// unit ms
prop.put("oracle.jdbc.ReadTimeout", socketTimeout);
}
return connect(dataBaseType, url, prop);
}
private static synchronized Connection connect(DataBaseType dataBaseType,
String url, Properties prop) {
try {
Class.forName(dataBaseType.getDriverClassName());
DriverManager.setLoginTimeout(Constant.TIMEOUT_SECONDS);
return DriverManager.getConnection(url, prop);
} catch (Exception e) {
throw RdbmsException.asConnException(dataBaseType, e, prop.getProperty("user"), null);
}
}
/**
* a wrapped method to execute select-like sql statement .
*
* @param conn Database connection .
* @param sql sql statement to be executed
* @return a {@link ResultSet}
* @throws SQLException if occurs SQLException.
*/
public static ResultSet query(Connection conn, String sql, int fetchSize)
throws SQLException {
// 默认3600 s 的query Timeout
return query(conn, sql, fetchSize, Constant.SOCKET_TIMEOUT_INSECOND);
}
/**
* a wrapped method to execute select-like sql statement .
*
* @param conn Database connection .
* @param sql sql statement to be executed
* @param fetchSize
* @param queryTimeout unit:second
* @return
* @throws SQLException
*/
public static ResultSet query(Connection conn, String sql, int fetchSize, int queryTimeout)
throws SQLException {
// make sure autocommit is off
conn.setAutoCommit(false);
Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(fetchSize);
stmt.setQueryTimeout(queryTimeout);
return query(stmt, sql);
}
/**
* a wrapped method to execute select-like sql statement .
*
* @param stmt {@link Statement}
* @param sql sql statement to be executed
* @return a {@link ResultSet}
* @throws SQLException if occurs SQLException.
*/
public static ResultSet query(Statement stmt, String sql)
throws SQLException {
return stmt.executeQuery(sql);
}
public static void executeSqlWithoutResultSet(Statement stmt, String sql)
throws SQLException {
stmt.execute(sql);
}
/**
* Close {@link ResultSet}, {@link Statement} referenced by this
* {@link ResultSet}
*
* @param rs {@link ResultSet} to be closed
* @throws IllegalArgumentException
*/
public static void closeResultSet(ResultSet rs) {
try {
if (null != rs) {
Statement stmt = rs.getStatement();
if (null != stmt) {
stmt.close();
stmt = null;
}
rs.close();
}
rs = null;
} catch (SQLException e) {
throw new IllegalStateException(e);
}
}
public static void closeDBResources(ResultSet rs, Statement stmt,
Connection conn) {
if (null != rs) {
try {
rs.close();
} catch (SQLException unused) {
}
}
if (null != stmt) {
try {
stmt.close();
} catch (SQLException unused) {
}
}
if (null != conn) {
try {
conn.close();
} catch (SQLException unused) {
}
}
}
public static void closeDBResources(Statement stmt, Connection conn) {
closeDBResources(null, stmt, conn);
}
public static List<String> getTableColumns(DataBaseType dataBaseType,
String jdbcUrl, String user, String pass, String tableName) {
Connection conn = getConnection(dataBaseType, jdbcUrl, user, pass);
return getTableColumnsByConn(dataBaseType, conn, tableName, "jdbcUrl:"+jdbcUrl);
}
public static List<String> getTableColumnsByConn(DataBaseType dataBaseType, Connection conn, String tableName, String basicMsg) {
List<String> columns = new ArrayList<String>();
Statement statement = null;
ResultSet rs = null;
String queryColumnSql = null;
try {
statement = conn.createStatement();
queryColumnSql = String.format("select * from %s where 1=2",
tableName);
rs = statement.executeQuery(queryColumnSql);
ResultSetMetaData rsMetaData = rs.getMetaData();
for (int i = 0, len = rsMetaData.getColumnCount(); i < len; i++) {
columns.add(rsMetaData.getColumnName(i + 1));
}
} catch (SQLException e) {
throw RdbmsException.asQueryException(dataBaseType,e,queryColumnSql,tableName,null);
} finally {
DBUtil.closeDBResources(rs, statement, conn);
}
return columns;
}
/**
* @return Left:ColumnName Middle:ColumnType Right:ColumnTypeName
*/
public static Triple<List<String>, List<Integer>, List<String>> getColumnMetaData(
DataBaseType dataBaseType, String jdbcUrl, String user,
String pass, String tableName, String column) {
Connection conn = null;
try {
conn = getConnection(dataBaseType, jdbcUrl, user, pass);
return getColumnMetaData(conn, tableName, column);
} finally {
DBUtil.closeDBResources(null, null, conn);
}
}
/**
* @return Left:ColumnName Middle:ColumnType Right:ColumnTypeName
*/
public static Triple<List<String>, List<Integer>, List<String>> getColumnMetaData(
Connection conn, String tableName, String column) {
Statement statement = null;
ResultSet rs = null;
Triple<List<String>, List<Integer>, List<String>> columnMetaData = new ImmutableTriple<List<String>, List<Integer>, List<String>>(
new ArrayList<String>(), new ArrayList<Integer>(),
new ArrayList<String>());
try {
statement = conn.createStatement();
String queryColumnSql = "select " + column + " from " + tableName
+ " where 1=2";
rs = statement.executeQuery(queryColumnSql);
ResultSetMetaData rsMetaData = rs.getMetaData();
for (int i = 0, len = rsMetaData.getColumnCount(); i < len; i++) {
columnMetaData.getLeft().add(rsMetaData.getColumnName(i + 1));
columnMetaData.getMiddle().add(rsMetaData.getColumnType(i + 1));
columnMetaData.getRight().add(
rsMetaData.getColumnTypeName(i + 1));
}
return columnMetaData;
} catch (SQLException e) {
throw DataXException
.asDataXException(DBUtilErrorCode.GET_COLUMN_INFO_FAILED,
String.format("获取表:%s 的字段的元信息时失败. 请联系 DBA 核查该库、表信息.", tableName), e);
} finally {
DBUtil.closeDBResources(rs, statement, null);
}
}
public static boolean testConnWithoutRetry(DataBaseType dataBaseType,
String url, String user, String pass, boolean checkSlave){
Connection connection = null;
try {
connection = connect(dataBaseType, url, user, pass);
if (connection != null) {
if (dataBaseType.equals(dataBaseType.MySql) && checkSlave) {
//dataBaseType.MySql
boolean connOk = !isSlaveBehind(connection);
return connOk;
} else {
return true;
}
}
} catch (Exception e) {
LOG.warn("test connection of [{}] failed, for {}.", url,
e.getMessage());
} finally {
DBUtil.closeDBResources(null, connection);
}
return false;
}
public static boolean testConnWithoutRetry(DataBaseType dataBaseType,
String url, String user, String pass, List<String> preSql) {
Connection connection = null;
try {
connection = connect(dataBaseType, url, user, pass);
if (null != connection) {
for (String pre : preSql) {
if (doPreCheck(connection, pre) == false) {
LOG.warn("doPreCheck failed.");
return false;
}
}
return true;
}
} catch (Exception e) {
LOG.warn("test connection of [{}] failed, for {}.", url,
e.getMessage());
} finally {
DBUtil.closeDBResources(null, connection);
}
return false;
}
public static boolean isOracleMaster(final String url, final String user, final String pass) {
try {
return RetryUtil.executeWithRetry(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
Connection conn = null;
try {
conn = connect(DataBaseType.Oracle, url, user, pass);
ResultSet rs = query(conn, "select DATABASE_ROLE from V$DATABASE");
if (DBUtil.asyncResultSetNext(rs, 5)) {
String role = rs.getString("DATABASE_ROLE");
return "PRIMARY".equalsIgnoreCase(role);
}
throw DataXException.asDataXException(DBUtilErrorCode.RS_ASYNC_ERROR,
String.format("select DATABASE_ROLE from V$DATABASE failed,请检查您的jdbcUrl:%s.", url));
} finally {
DBUtil.closeDBResources(null, conn);
}
}
}, 3, 1000L, true);
} catch (Exception e) {
throw DataXException.asDataXException(DBUtilErrorCode.CONN_DB_ERROR,
String.format("select DATABASE_ROLE from V$DATABASE failed, url: %s", url), e);
}
}
public static ResultSet query(Connection conn, String sql)
throws SQLException {
Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
//默认3600 seconds
stmt.setQueryTimeout(Constant.SOCKET_TIMEOUT_INSECOND);
return query(stmt, sql);
}
private static boolean doPreCheck(Connection conn, String pre) {
ResultSet rs = null;
try {
rs = query(conn, pre);
int checkResult = -1;
if (DBUtil.asyncResultSetNext(rs)) {
checkResult = rs.getInt(1);
if (DBUtil.asyncResultSetNext(rs)) {
LOG.warn(
"pre check failed. It should return one result:0, pre:[{}].",
pre);
return false;
}
}
if (0 == checkResult) {
return true;
}
LOG.warn(
"pre check failed. It should return one result:0, pre:[{}].",
pre);
} catch (Exception e) {
LOG.warn("pre check failed. pre:[{}], errorMessage:[{}].", pre,
e.getMessage());
} finally {
DBUtil.closeResultSet(rs);
}
return false;
}
// warn:until now, only oracle need to handle session config.
public static void dealWithSessionConfig(Connection conn,
Configuration config, DataBaseType databaseType, String message) {
List<String> sessionConfig = null;
switch (databaseType) {
case Oracle:
sessionConfig = config.getList(Key.SESSION,
new ArrayList<String>(), String.class);
DBUtil.doDealWithSessionConfig(conn, sessionConfig, message);
break;
case DRDS:
// 用于关闭 drds 的分布式事务开关
sessionConfig = new ArrayList<String>();
sessionConfig.add("set transaction policy 4");
DBUtil.doDealWithSessionConfig(conn, sessionConfig, message);
break;
case MySql:
sessionConfig = config.getList(Key.SESSION,
new ArrayList<String>(), String.class);
DBUtil.doDealWithSessionConfig(conn, sessionConfig, message);
break;
default:
break;
}
}
private static void doDealWithSessionConfig(Connection conn,
List<String> sessions, String message) {
if (null == sessions || sessions.isEmpty()) {
return;
}
Statement stmt;
try {
stmt = conn.createStatement();
} catch (SQLException e) {
throw DataXException
.asDataXException(DBUtilErrorCode.SET_SESSION_ERROR, String
.format("session配置有误. 因为根据您的配置执行 session 设置失败. 上下文信息是:[%s]. 请检查您的配置并作出修改.", message),
e);
}
for (String sessionSql : sessions) {
LOG.info("execute sql:[{}]", sessionSql);
try {
DBUtil.executeSqlWithoutResultSet(stmt, sessionSql);
} catch (SQLException e) {
throw DataXException.asDataXException(
DBUtilErrorCode.SET_SESSION_ERROR, String.format(
"session配置有误. 因为根据您的配置执行 session 设置失败. 上下文信息是:[%s]. 请检查您的配置并作出修改.", message), e);
}
}
DBUtil.closeDBResources(stmt, null);
}
public static void sqlValid(String sql, DataBaseType dataBaseType){
SQLStatementParser statementParser = SQLParserUtils.createSQLStatementParser(sql,dataBaseType.getTypeName());
statementParser.parseStatementList();
}
/**
* 异步获取resultSet的next(),注意,千万不能应用在数据的读取中。只能用在meta的获取
* @param resultSet
* @return
*/
public static boolean asyncResultSetNext(final ResultSet resultSet) {
return asyncResultSetNext(resultSet, 3600);
}
public static boolean asyncResultSetNext(final ResultSet resultSet, int timeout) {
Future<Boolean> future = rsExecutors.get().submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return resultSet.next();
}
});
try {
return future.get(timeout, TimeUnit.SECONDS);
} catch (Exception e) {
throw DataXException.asDataXException(
DBUtilErrorCode.RS_ASYNC_ERROR, "异步获取ResultSet失败", e);
}
}
public static void loadDriverClass(String pluginType, String pluginName) {
try {
String pluginJsonPath = StringUtils.join(
new String[] { System.getProperty("datax.home"), "plugin",
pluginType,
String.format("%s%s", pluginName, pluginType),
"plugin.json" }, File.separator);
Configuration configuration = Configuration.from(new File(
pluginJsonPath));
List<String> drivers = configuration.getList("drivers",
String.class);
for (String driver : drivers) {
Class.forName(driver);
}
} catch (ClassNotFoundException e) {
throw DataXException.asDataXException(DBUtilErrorCode.CONF_ERROR,
"数据库驱动加载错误, 请确认libs目录有驱动jar包且plugin.json中drivers配置驱动类正确!",
e);
}
}
}