de/backend/src/main/java/io/dataease/datasource/provider/JdbcProvider.java

626 lines
28 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package io.dataease.datasource.provider;
import com.alibaba.druid.pool.DruidDataSource;
import com.google.gson.Gson;
import io.dataease.datasource.constants.DatasourceTypes;
import io.dataease.datasource.dto.*;
import io.dataease.datasource.request.DatasourceRequest;
import io.dataease.exception.DataEaseException;
import io.dataease.i18n.Translator;
import io.dataease.provider.QueryProvider;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.beans.PropertyVetoException;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.*;
@Service("jdbc")
public class JdbcProvider extends DatasourceProvider {
private static Map<String, DruidDataSource> jdbcConnection = new HashMap<>();
private static Map<String, ExtendedJdbcClassLoader> extendedJdbcClassLoaderHashMap = new HashMap<>();
private static int initPoolSize = 5;
private static int maxConnections = 200;
private ExtendedJdbcClassLoader extendedJdbcClassLoader;
static private String FILE_PATH = "/opt/dataease/drivers";
@PostConstruct
public void init() throws Exception{
extendedJdbcClassLoader = new ExtendedJdbcClassLoader(new URL[]{new File(FILE_PATH).toURI().toURL()});
File file = new File(FILE_PATH);
File[] array = file.listFiles();
Optional.ofNullable(array).ifPresent(files -> {
for (File tmp : array) {
if (tmp.getName().endsWith(".jar")) {
try {
extendedJdbcClassLoader.addFile(tmp);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
/**
* 增加缓存机制 key 由 'provider_sql_' dsr.datasource.id dsr.table dsr.query共4部分组成命中则使用缓存直接返回不再执行sql逻辑
* @param dsr
* @return
* @throws Exception
*/
/**
* 这里使用声明式缓存不是很妥当
* 改为chartViewService中使用编程式缓存
@Cacheable(
value = JdbcConstants.JDBC_PROVIDER_KEY,
key = "'provider_sql_' + #dsr.datasource.id + '_' + #dsr.table + '_' + #dsr.query",
condition = "#dsr.pageSize == null || #dsr.pageSize == 0L"
)
*/
@Override
public List<String[]> getData(DatasourceRequest dsr) throws Exception {
List<String[]> list = new LinkedList<>();
Connection connection = null;
try {
connection = getConnection(dsr);
Statement stat = connection.createStatement();
ResultSet rs = stat.executeQuery(dsr.getQuery());
list = fetchResult(rs);
if(dsr.isPageable() && dsr.getDatasource().getType().equalsIgnoreCase(DatasourceTypes.sqlServer.name())){
Integer realSize = dsr.getPage() * dsr.getPageSize() < list.size() ? dsr.getPage() * dsr.getPageSize(): list.size();
list = list.subList((dsr.getPage() - 1) * dsr.getPageSize(), realSize);
}
} catch (SQLException e) {
DataEaseException.throwException(e);
} catch (Exception e) {
DataEaseException.throwException(e);
} finally {
if(connection != null){
connection.close();
}
}
return list;
}
public void exec(DatasourceRequest datasourceRequest) throws Exception {
Connection connection = null;
try {
connection = getConnectionFromPool(datasourceRequest);
Statement stat = connection.createStatement();
Boolean result = stat.execute(datasourceRequest.getQuery());
stat.close();
} catch (SQLException e) {
DataEaseException.throwException(e);
} catch (Exception e) {
DataEaseException.throwException(e);
} finally {
if(connection != null){
connection.close();
}
}
}
@Override
public List<String[]> fetchResult(DatasourceRequest datasourceRequest) throws Exception {
ResultSet rs;
Connection connection = null;
try {
connection = getConnectionFromPool(datasourceRequest);
Statement stat = connection.createStatement();
rs = stat.executeQuery(datasourceRequest.getQuery());
return fetchResult(rs);
} catch (SQLException e) {
DataEaseException.throwException(e);
} catch (Exception e) {
DataEaseException.throwException(e);
} finally {
if(connection != null){
connection.close();
}
}
return new ArrayList<>();
}
private List<String[]> fetchResult(ResultSet rs) throws Exception {
List<String[]> list = new LinkedList<>();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
while (rs.next()) {
String[] row = new String[columnCount];
for (int j = 0; j < columnCount; j++) {
int columType = metaData.getColumnType(j + 1);
switch (columType) {
case Types.DATE:
if(rs.getDate(j + 1) != null){
row[j] = rs.getDate(j + 1).toString();
}
break;
default:
row[j] = rs.getString(j + 1);
break;
}
}
list.add(row);
}
return list;
}
@Override
public List<TableFiled> fetchResultField(DatasourceRequest datasourceRequest) throws Exception {
ResultSet rs;
Connection connection = null;
try {
connection = getConnectionFromPool(datasourceRequest);
Statement stat = connection.createStatement();
rs = stat.executeQuery(datasourceRequest.getQuery());
return fetchResultField(rs, datasourceRequest);
} catch (SQLException e) {
DataEaseException.throwException(e);
} catch (Exception e) {
DataEaseException.throwException(Translator.get("i18n_datasource_connect_error") + e.getMessage());
} finally {
if(connection != null){
connection.close();
}
}
return new ArrayList<>();
}
@Override
public Map<String, List> fetchResultAndField(DatasourceRequest datasourceRequest) throws Exception {
ResultSet rs;
Map<String, List> result = new HashMap<>();
Connection connection = null;
List<String[]> dataList = new LinkedList<>();
List<TableFiled> fieldList = new ArrayList<>();
try {
connection = getConnectionFromPool(datasourceRequest);
Statement stat = connection.createStatement();
rs = stat.executeQuery(datasourceRequest.getQuery());
dataList = fetchResult(rs);
fieldList = fetchResultField(rs, datasourceRequest);
result.put("dataList", dataList);
result.put("fieldList", fieldList);
return result;
} catch (SQLException e) {
DataEaseException.throwException(e);
} catch (Exception e) {
DataEaseException.throwException(e);
} finally {
if(connection != null){
connection.close();
}
}
return new HashMap<>();
}
private List<TableFiled> fetchResultField(ResultSet rs, DatasourceRequest datasourceRequest) throws Exception {
List<TableFiled> fieldList = new ArrayList<>();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
for (int j = 0; j < columnCount; j++) {
String f = metaData.getColumnName(j + 1);
String l = StringUtils.isNotEmpty(metaData.getColumnLabel(j + 1)) ? metaData.getColumnLabel(j + 1) : f;
String t = metaData.getColumnTypeName(j + 1);
TableFiled field = new TableFiled();
field.setFieldName(l);
field.setRemarks(l);
field.setFieldType(t);
if(datasourceRequest.getDatasource().getType().equalsIgnoreCase(DatasourceTypes.ck.name())){
QueryProvider qp = ProviderFactory.getQueryProvider(datasourceRequest.getDatasource().getType());
field.setFieldSize(qp.transFieldSize(t));
}else {
field.setFieldSize(metaData.getColumnDisplaySize(j + 1));
}
if(t.equalsIgnoreCase("LONG")){field.setFieldSize(65533);} //oracle LONG
if(StringUtils.isNotEmpty(t) && t.toLowerCase().contains("date") && field.getFieldSize() < 50 ){
field.setFieldSize(50);
}
fieldList.add(field);
}
return fieldList;
}
@Override
public List<String> getTables(DatasourceRequest datasourceRequest) throws Exception {
List<String> tables = new ArrayList<>();
Connection con = null;
try {
String queryStr = getTablesSql(datasourceRequest);
con = getConnection(datasourceRequest);
Statement statement = con.createStatement();
ResultSet resultSet = statement.executeQuery(queryStr);
while (resultSet.next()) {
tables.add(resultSet.getString(1));
}
resultSet.close();
statement.close();
String queryView = getViewSql(datasourceRequest);
if(StringUtils.isNotEmpty(queryView)){
con = getConnection(datasourceRequest);
statement = con.createStatement();
resultSet = statement.executeQuery(queryView);
while (resultSet.next()) {
tables.add(resultSet.getString(1));
}
resultSet.close();
statement.close();
}
return tables;
} catch (Exception e) {
DataEaseException.throwException(e);
} finally {
if(con != null){
con.close();
}
}
return new ArrayList<>();
}
@Override
public List<String> getSchema(DatasourceRequest datasourceRequest) throws Exception {
List<String> schemas = new ArrayList<>();
String queryStr = getSchemaSql(datasourceRequest);
Connection con = null;
try {
con = getConnection(datasourceRequest);
Statement statement = con.createStatement();
ResultSet resultSet = statement.executeQuery(queryStr);
while (resultSet.next()) {
schemas.add(resultSet.getString(1));
}
resultSet.close();
statement.close();
return schemas;
} catch (Exception e) {
DataEaseException.throwException(e);
} finally {
if(con != null){
con.close();
}
}
return new ArrayList<>();
}
private TableFiled getTableFiled(ResultSet resultSet, DatasourceRequest datasourceRequest) throws SQLException {
TableFiled tableFiled = new TableFiled();
String colName = resultSet.getString("COLUMN_NAME");
tableFiled.setFieldName(colName);
String remarks = resultSet.getString("REMARKS");
if (remarks == null || remarks.equals("")) {
remarks = colName;
}
tableFiled.setRemarks(remarks);
String dbType = resultSet.getString("TYPE_NAME").toUpperCase();
tableFiled.setFieldType(dbType);
if(dbType.equalsIgnoreCase("LONG")){tableFiled.setFieldSize(65533);}
if(StringUtils.isNotEmpty(dbType) && dbType.toLowerCase().contains("date") && tableFiled.getFieldSize() < 50 ){
tableFiled.setFieldSize(50);
}
if(datasourceRequest.getDatasource().getType().equalsIgnoreCase(DatasourceTypes.ck.name())){
QueryProvider qp = ProviderFactory.getQueryProvider(datasourceRequest.getDatasource().getType());
tableFiled.setFieldSize(qp.transFieldSize(dbType));
}else {
tableFiled.setFieldSize(Integer.valueOf(resultSet.getString("COLUMN_SIZE")));
}
return tableFiled;
}
@Override
public void checkStatus(DatasourceRequest datasourceRequest) throws Exception {
Connection con = null;
try {
con = getConnection(datasourceRequest);
Statement statement = con.createStatement();
String queryStr = getTablesSql(datasourceRequest);
ResultSet resultSet = statement.executeQuery(queryStr);
resultSet.close();
statement.close();
} catch (Exception e) {
e.printStackTrace();
DataEaseException.throwException(e.getMessage());
} finally {
if(con != null){con.close();}
}
}
public Long count(DatasourceRequest datasourceRequest) throws Exception {
Connection con = null;
try {
con = getConnectionFromPool(datasourceRequest);
Statement ps = con.createStatement();
ResultSet resultSet = ps.executeQuery(datasourceRequest.getQuery());
while (resultSet.next()) {
return resultSet.getLong(1);
}
} catch (Exception e) {
DataEaseException.throwException( e);
} finally {
con.close();
}
return 0L;
}
private Connection getConnectionFromPool(DatasourceRequest datasourceRequest) throws Exception {
DruidDataSource dataSource = jdbcConnection.get(datasourceRequest.getDatasource().getId());
if (dataSource == null) {
handleDatasource(datasourceRequest, "add");
}
dataSource = jdbcConnection.get(datasourceRequest.getDatasource().getId());
Connection co = dataSource.getConnection();
return co;
}
@Override
public void handleDatasource(DatasourceRequest datasourceRequest, String type) throws Exception {
DruidDataSource dataSource = null;
switch (type){
case "add":
checkStatus(datasourceRequest);
dataSource = jdbcConnection.get(datasourceRequest.getDatasource().getId());
if (dataSource == null) {
addToPool(datasourceRequest);
}
break;
case "edit":
dataSource = jdbcConnection.get(datasourceRequest.getDatasource().getId());
if (dataSource != null) {
dataSource.close();
}
checkStatus(datasourceRequest);
addToPool(datasourceRequest);
break;
case "delete":
dataSource = jdbcConnection.get(datasourceRequest.getDatasource().getId());
if (dataSource != null) {
dataSource.close();
}
break;
default:
break;
}
}
private void addToPool(DatasourceRequest datasourceRequest) throws PropertyVetoException {
DruidDataSource dataSource = new DruidDataSource();
JdbcConfiguration jdbcConfiguration = setCredential(datasourceRequest, dataSource);
dataSource.setInitialSize(jdbcConfiguration.getInitialPoolSize());// 初始连接数
dataSource.setMinIdle(jdbcConfiguration.getMinPoolSize()); // 最小连接数
dataSource.setMaxActive(jdbcConfiguration.getMaxPoolSize()); // 最大连接数
jdbcConnection.put(datasourceRequest.getDatasource().getId(), dataSource);
}
private Connection getConnection(DatasourceRequest datasourceRequest) throws Exception {
String username = null;
String password = null;
String driver = null;
String jdbcurl = null;
DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType());
Properties props = new Properties();
switch (datasourceType) {
case mysql:
case mariadb:
case de_doris:
case ds_doris:
MysqlConfiguration mysqlConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), MysqlConfiguration.class);
username = mysqlConfiguration.getUsername();
password = mysqlConfiguration.getPassword();
driver = mysqlConfiguration.getDriver();
jdbcurl = mysqlConfiguration.getJdbc();
break;
case sqlServer:
SqlServerConfiguration sqlServerConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), SqlServerConfiguration.class);
username = sqlServerConfiguration.getUsername();
password = sqlServerConfiguration.getPassword();
driver = sqlServerConfiguration.getDriver();
jdbcurl = sqlServerConfiguration.getJdbc();
break;
case oracle:
OracleConfiguration oracleConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), OracleConfiguration.class);
username = oracleConfiguration.getUsername();
password = oracleConfiguration.getPassword();
driver = oracleConfiguration.getDriver();
jdbcurl = oracleConfiguration.getJdbc();
props.put( "oracle.net.CONNECT_TIMEOUT" , "5000") ;
break;
case pg:
PgConfiguration pgConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), PgConfiguration.class);
username = pgConfiguration.getUsername();
password = pgConfiguration.getPassword();
driver = pgConfiguration.getDriver();
jdbcurl = pgConfiguration.getJdbc();
break;
case ck:
CHConfiguration chConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), CHConfiguration.class);
username = chConfiguration.getUsername();
password = chConfiguration.getPassword();
driver = chConfiguration.getDriver();
jdbcurl = chConfiguration.getJdbc();
break;
default:
break;
}
Driver driverClass = (Driver) extendedJdbcClassLoader.loadClass(driver).newInstance();
props.setProperty("user", username);
if (StringUtils.isNotBlank(password)) {
props.setProperty("password", password);
}
Connection conn = driverClass.connect(jdbcurl, props);
return conn;
}
private JdbcConfiguration setCredential(DatasourceRequest datasourceRequest, DruidDataSource dataSource) throws PropertyVetoException {
DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType());
JdbcConfiguration jdbcConfiguration = new JdbcConfiguration();
switch (datasourceType) {
case mysql:
case mariadb:
case de_doris:
case ds_doris:
MysqlConfiguration mysqlConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), MysqlConfiguration.class);
dataSource.setUsername(mysqlConfiguration.getUsername());
dataSource.setDriverClassLoader(extendedJdbcClassLoader);
dataSource.setPassword(mysqlConfiguration.getPassword());
dataSource.setUrl(mysqlConfiguration.getJdbc());
jdbcConfiguration = mysqlConfiguration;
break;
case sqlServer:
SqlServerConfiguration sqlServerConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), SqlServerConfiguration.class);
dataSource.setUsername(sqlServerConfiguration.getUsername());
dataSource.setDriverClassLoader(extendedJdbcClassLoader);
dataSource.setPassword(sqlServerConfiguration.getPassword());
dataSource.setUrl(sqlServerConfiguration.getJdbc());
jdbcConfiguration = sqlServerConfiguration;
break;
case oracle:
OracleConfiguration oracleConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), OracleConfiguration.class);
dataSource.setUsername(oracleConfiguration.getUsername());
dataSource.setDriverClassLoader(extendedJdbcClassLoader);
dataSource.setPassword(oracleConfiguration.getPassword());
dataSource.setUrl(oracleConfiguration.getJdbc());
jdbcConfiguration = oracleConfiguration;
break;
case pg:
PgConfiguration pgConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), PgConfiguration.class);
dataSource.setUsername(pgConfiguration.getUsername());
dataSource.setDriverClassLoader(extendedJdbcClassLoader);
dataSource.setPassword(pgConfiguration.getPassword());
dataSource.setUrl(pgConfiguration.getJdbc());
jdbcConfiguration = pgConfiguration;
break;
case ck:
CHConfiguration chConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), CHConfiguration.class);
dataSource.setUsername(chConfiguration.getUsername());
dataSource.setDriverClassLoader(extendedJdbcClassLoader);
dataSource.setPassword(chConfiguration.getPassword());
dataSource.setUrl(chConfiguration.getJdbc());
jdbcConfiguration = chConfiguration;
break;
default:
break;
}
return jdbcConfiguration;
}
private String getDatabase(DatasourceRequest datasourceRequest) {
DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType());
switch (datasourceType) {
case mysql:
case de_doris:
case ds_doris:
case mariadb:
MysqlConfiguration mysqlConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), MysqlConfiguration.class);
return mysqlConfiguration.getDataBase();
case sqlServer:
SqlServerConfiguration sqlServerConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), SqlServerConfiguration.class);
return sqlServerConfiguration.getDataBase();
case pg:
PgConfiguration pgConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), PgConfiguration.class);
return pgConfiguration.getDataBase();
default:
JdbcConfiguration jdbcConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), JdbcConfiguration.class);
return jdbcConfiguration.getDataBase();
}
}
private String getTablesSql(DatasourceRequest datasourceRequest) throws Exception {
DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType());
switch (datasourceType) {
case mysql:
case mariadb:
case de_doris:
case ds_doris:
return "show tables;";
case sqlServer:
SqlServerConfiguration sqlServerConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), SqlServerConfiguration.class);
if(StringUtils.isEmpty(sqlServerConfiguration.getSchema())){
throw new Exception(Translator.get("i18n_schema_is_empty"));
}
return "SELECT TABLE_NAME FROM DATABASE.INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA = 'DS_SCHEMA' ;"
.replace("DATABASE", sqlServerConfiguration.getDataBase())
.replace("DS_SCHEMA", sqlServerConfiguration.getSchema());
case oracle:
OracleConfiguration oracleConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), OracleConfiguration.class);
if(StringUtils.isEmpty(oracleConfiguration.getSchema())){
throw new Exception(Translator.get("i18n_schema_is_empty"));
}
return "select table_name, owner from all_tables where owner='" + oracleConfiguration.getSchema() + "'";
case pg:
PgConfiguration pgConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), PgConfiguration.class);
if(StringUtils.isEmpty(pgConfiguration.getSchema())){
throw new Exception(Translator.get("i18n_schema_is_empty"));
}
return "SELECT tablename FROM pg_tables WHERE schemaname='SCHEMA' ;".replace("SCHEMA", pgConfiguration.getSchema());
case ck:
CHConfiguration chConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), CHConfiguration.class);
return "SELECT name FROM system.tables where database='DATABASE';".replace("DATABASE", chConfiguration.getDataBase());
default:
return "show tables;";
}
}
private String getViewSql(DatasourceRequest datasourceRequest) throws Exception {
DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType());
switch (datasourceType) {
case mysql:
case mariadb:
case de_doris:
case ds_doris:
case ck:
return null;
case sqlServer:
SqlServerConfiguration sqlServerConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), SqlServerConfiguration.class);
if(StringUtils.isEmpty(sqlServerConfiguration.getSchema())){
throw new Exception(Translator.get("i18n_schema_is_empty"));
}
return "SELECT TABLE_NAME FROM DATABASE.INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = 'DS_SCHEMA' ;"
.replace("DATABASE", sqlServerConfiguration.getDataBase())
.replace("DS_SCHEMA", sqlServerConfiguration.getSchema());
case oracle:
OracleConfiguration oracleConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), OracleConfiguration.class);
if(StringUtils.isEmpty(oracleConfiguration.getSchema())){
throw new Exception(Translator.get("i18n_schema_is_empty"));
}
return "select VIEW_NAME from all_views where owner='" + oracleConfiguration.getSchema() + "'";
case pg:
PgConfiguration pgConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), PgConfiguration.class);
if(StringUtils.isEmpty(pgConfiguration.getSchema())){
throw new Exception(Translator.get("i18n_schema_is_empty"));
}
return "SELECT viewname FROM pg_views WHERE schemaname='SCHEMA' ;".replace("SCHEMA", pgConfiguration.getSchema());
default:
return null;
}
}
private String getSchemaSql(DatasourceRequest datasourceRequest) {
DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType());
switch (datasourceType) {
case oracle:
return "select * from all_users";
case sqlServer:
return "select name from sys.schemas;";
case pg:
return "SELECT nspname FROM pg_namespace;";
default:
return "show tables;";
}
}
}