mirror of
https://gitee.com/dromara/dbswitch.git
synced 2025-09-01 18:17:33 +00:00
代码提交
This commit is contained in:
BIN
dbswitch-core/lib/greenplum-jdbc-5.1.4.jar
Normal file
BIN
dbswitch-core/lib/greenplum-jdbc-5.1.4.jar
Normal file
Binary file not shown.
BIN
dbswitch-core/lib/msbase.jar
Normal file
BIN
dbswitch-core/lib/msbase.jar
Normal file
Binary file not shown.
BIN
dbswitch-core/lib/mssqlserver.jar
Normal file
BIN
dbswitch-core/lib/mssqlserver.jar
Normal file
Binary file not shown.
BIN
dbswitch-core/lib/msutil.jar
Normal file
BIN
dbswitch-core/lib/msutil.jar
Normal file
Binary file not shown.
BIN
dbswitch-core/lib/ojdbc7-12.1.0.2.jar
Normal file
BIN
dbswitch-core/lib/ojdbc7-12.1.0.2.jar
Normal file
Binary file not shown.
BIN
dbswitch-core/lib/sqljdbc4-4.0.jar
Normal file
BIN
dbswitch-core/lib/sqljdbc4-4.0.jar
Normal file
Binary file not shown.
89
dbswitch-core/pom.xml
Normal file
89
dbswitch-core/pom.xml
Normal file
@@ -0,0 +1,89 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.weishao</groupId>
|
||||
<artifactId>dbswitch</artifactId>
|
||||
<version>1.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dbswitch-core</artifactId>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.weishao</groupId>
|
||||
<artifactId>dbswitch-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.oracle.ojdbc</groupId>
|
||||
<artifactId>ojdbc8</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>sqljdbc4</artifactId>
|
||||
<version>4.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/lib/sqljdbc4-4.0.jar</systemPath>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>msbase</artifactId>
|
||||
<version>3.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/lib/msbase.jar</systemPath>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>msutil</artifactId>
|
||||
<version>3.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/lib/msutil.jar</systemPath>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssqlserver</artifactId>
|
||||
<version>3.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/lib/mssqlserver.jar</systemPath>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.pivotal</groupId>
|
||||
<artifactId>greenplum-jdbc</artifactId>
|
||||
<version>5.1.4</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/lib/greenplum-jdbc-5.1.4.jar</systemPath>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.1.5</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@@ -0,0 +1,77 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.constant;
|
||||
|
||||
/**
|
||||
* 常量定义
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public final class Const {
|
||||
|
||||
/**
|
||||
* What's the file systems file separator on this operating system?
|
||||
*/
|
||||
public static final String FILE_SEPARATOR = System.getProperty("file.separator");
|
||||
|
||||
/**
|
||||
* What's the path separator on this operating system?
|
||||
*/
|
||||
public static final String PATH_SEPARATOR = System.getProperty("path.separator");
|
||||
|
||||
/**
|
||||
* CR: operating systems specific Carriage Return
|
||||
*/
|
||||
public static final String CR = System.getProperty("line.separator");
|
||||
|
||||
/**
|
||||
* DOSCR: MS-DOS specific Carriage Return
|
||||
*/
|
||||
public static final String DOSCR = "\n\r";
|
||||
|
||||
/**
|
||||
* An empty ("") String.
|
||||
*/
|
||||
public static final String EMPTY_STRING = "";
|
||||
|
||||
/**
|
||||
* The Java runtime version
|
||||
*/
|
||||
public static final String JAVA_VERSION = System.getProperty("java.vm.version");
|
||||
|
||||
/**
|
||||
* Create Table Statement Prefix String
|
||||
*/
|
||||
public static final String CREATE_TABLE = " CREATE TABLE ";
|
||||
|
||||
/**
|
||||
* Drop Table Statement Prefix String
|
||||
*/
|
||||
public static final String DROP_TABLE = " DROP TABLE ";
|
||||
|
||||
/**
|
||||
* Constant Keyword String
|
||||
*/
|
||||
public static final String IF_NOT_EXISTS = " IF NOT EXISTS ";
|
||||
|
||||
/**
|
||||
* Constant Keyword String
|
||||
*/
|
||||
public static final String IF_EXISTS = " IF EXISTS ";
|
||||
|
||||
/**
|
||||
* Constructor Function
|
||||
*/
|
||||
private Const() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.constant;
|
||||
|
||||
/**
|
||||
* 数据库表类型:视图表、物理表
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public enum DBTableType {
|
||||
/**
|
||||
* 物理表
|
||||
*/
|
||||
TABLE(0),
|
||||
|
||||
/**
|
||||
* 视图表
|
||||
*/
|
||||
VIEW(1);
|
||||
|
||||
private int index;
|
||||
|
||||
DBTableType(int idx) {
|
||||
this.index = idx;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
@@ -0,0 +1,316 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.database;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
import com.weishao.dbswitch.core.model.ColumnDescription;
|
||||
import com.weishao.dbswitch.core.model.ColumnMetaData;
|
||||
import com.weishao.dbswitch.core.model.TableDescription;
|
||||
import com.weishao.dbswitch.core.util.JdbcOperatorUtils;
|
||||
|
||||
/**
|
||||
* 数据库元信息抽象基类
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractDatabase implements IDatabaseInterface {
|
||||
|
||||
public static final int CLOB_LENGTH = 9999999;
|
||||
|
||||
protected Connection connection = null;
|
||||
protected DatabaseMetaData metaData = null;
|
||||
protected String catalogName = null;
|
||||
|
||||
public AbstractDatabase(String driverClassName) {
|
||||
this.catalogName = null;
|
||||
|
||||
try {
|
||||
Class.forName(driverClassName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(String jdbcUrl, String username, String password) {
|
||||
/*
|
||||
* 超时时间设置问题: https://blog.csdn.net/lsunwing/article/details/79461217
|
||||
* https://blog.csdn.net/weixin_34405332/article/details/91664781
|
||||
*/
|
||||
try {
|
||||
/**
|
||||
* Oracle在通过jdbc连接的时候需要添加一个参数来设置是否获取注释
|
||||
*/
|
||||
Properties props = new Properties();
|
||||
props.put("user", username);
|
||||
props.put("password", password);
|
||||
props.put("remarksReporting", "true");
|
||||
|
||||
// 设置最大时间
|
||||
DriverManager.setLoginTimeout(15);
|
||||
this.connection = DriverManager.getConnection(jdbcUrl, props);
|
||||
this.metaData = this.connection.getMetaData();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (null != connection) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> querySchemaList() {
|
||||
Set<String> ret = new HashSet<>();
|
||||
ResultSet schemas = null;
|
||||
try {
|
||||
schemas = this.metaData.getSchemas();
|
||||
while (schemas.next()) {
|
||||
ret.add(schemas.getString("TABLE_SCHEM"));
|
||||
}
|
||||
return new ArrayList<>(ret);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
try {
|
||||
if (null != schemas) {
|
||||
schemas.close();
|
||||
schemas = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableDescription> queryTableList(String schemaName) {
|
||||
List<TableDescription> ret = new ArrayList<>();
|
||||
Set<String> uniqueSet = new HashSet<>();
|
||||
ResultSet tables = null;
|
||||
try {
|
||||
tables = this.metaData.getTables(this.catalogName, schemaName, "%", new String[] { "TABLE", "VIEW" });
|
||||
while (tables.next()) {
|
||||
String tableName = tables.getString("TABLE_NAME");
|
||||
if (uniqueSet.contains(tableName)) {
|
||||
continue;
|
||||
} else {
|
||||
uniqueSet.add(tableName);
|
||||
}
|
||||
|
||||
TableDescription td = new TableDescription();
|
||||
td.setSchemaName(schemaName);
|
||||
td.setTableName(tableName);
|
||||
td.setRemarks(tables.getString("REMARKS"));
|
||||
td.setTableType(tables.getString("TABLE_TYPE").toUpperCase());
|
||||
ret.add(td);
|
||||
}
|
||||
return ret;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
try {
|
||||
if (null != tables) {
|
||||
tables.close();
|
||||
tables = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnDescription> queryTableColumnMeta(String schemaName, String tableName) {
|
||||
String sql = this.getTableFieldsQuerySQL(schemaName, tableName);
|
||||
List<ColumnDescription> ret = this.querySelectSqlColumnMeta(sql);
|
||||
ResultSet columns = null;
|
||||
try {
|
||||
columns = this.metaData.getColumns(this.catalogName, schemaName, tableName, null);
|
||||
while (columns.next()) {
|
||||
String columnName = columns.getString("COLUMN_NAME");
|
||||
String remarks = columns.getString("REMARKS");
|
||||
for (ColumnDescription cd : ret) {
|
||||
if (columnName.equalsIgnoreCase(cd.getFieldName())) {
|
||||
cd.setRemarks(remarks);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
try {
|
||||
if (null != columns) {
|
||||
columns.close();
|
||||
columns = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> queryTablePrimaryKeys(String schemaName, String tableName) {
|
||||
Set<String> ret = new HashSet<>();
|
||||
ResultSet primarykeys = null;
|
||||
try {
|
||||
primarykeys = this.metaData.getPrimaryKeys(this.catalogName, schemaName, tableName);
|
||||
while (primarykeys.next()) {
|
||||
String name = primarykeys.getString("COLUMN_NAME");
|
||||
if (!ret.contains(name)) {
|
||||
ret.add(name);
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(ret);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
try {
|
||||
if (null != primarykeys) {
|
||||
primarykeys.close();
|
||||
primarykeys = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract List<ColumnDescription> querySelectSqlColumnMeta(String sql);
|
||||
|
||||
@Override
|
||||
public void testQuerySQL(String sql) {
|
||||
String wrapperSql = this.getTestQuerySQL(sql);
|
||||
try(PreparedStatement pstmt = this.connection.prepareStatement(wrapperSql);) {
|
||||
pstmt.executeQuery();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuotedSchemaTableCombination(String schemaName, String tableName) {
|
||||
return String.format(" \"%s\".\"%s\" ", schemaName, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFieldDefinition(ColumnMetaData v, List<String> pks, boolean useAutoInc, boolean addCr) {
|
||||
throw new RuntimeException("AbstractDatabase Unempliment!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrimaryKeyAsString(List<String> pks) {
|
||||
if (!pks.isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\"");
|
||||
sb.append(StringUtils.join(pks, "\" , \""));
|
||||
sb.append("\"");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract String formatSQL(String sql);
|
||||
|
||||
/**************************************
|
||||
* internal function
|
||||
**************************************/
|
||||
|
||||
protected abstract String getTableFieldsQuerySQL(String schemaName, String tableName);
|
||||
|
||||
protected abstract String getTestQuerySQL(String sql);
|
||||
|
||||
protected List<ColumnDescription> getSelectSqlColumnMeta(String querySQL, DatabaseTypeEnum dbtype) {
|
||||
List<ColumnDescription> ret = new ArrayList<ColumnDescription>();
|
||||
PreparedStatement pstmt = null;
|
||||
ResultSet rs = null;
|
||||
|
||||
try {
|
||||
pstmt = this.connection.prepareStatement(querySQL);
|
||||
rs = pstmt.executeQuery();
|
||||
|
||||
ResultSetMetaData m = rs.getMetaData();
|
||||
int columns = m.getColumnCount();
|
||||
for (int i = 1; i <= columns; i++) {
|
||||
String name = m.getColumnLabel(i);
|
||||
if (null == name) {
|
||||
name = m.getColumnName(i);
|
||||
}
|
||||
|
||||
ColumnDescription cd = new ColumnDescription();
|
||||
cd.setFieldName(name);
|
||||
cd.setLabelName(name);
|
||||
cd.setFieldType(m.getColumnType(i));
|
||||
if (0 != cd.getFieldType()) {
|
||||
cd.setFieldTypeName(m.getColumnTypeName(i));
|
||||
cd.setFiledTypeClassName(m.getColumnClassName(i));
|
||||
cd.setDisplaySize(m.getColumnDisplaySize(i));
|
||||
cd.setPrecisionSize(m.getPrecision(i));
|
||||
cd.setScaleSize(m.getScale(i));
|
||||
cd.setAutoIncrement(m.isAutoIncrement(i));
|
||||
cd.setNullable(m.isNullable(i) != ResultSetMetaData.columnNoNulls);
|
||||
} else {
|
||||
// 处理视图中NULL as fieldName的情况
|
||||
cd.setFieldTypeName("CHAR");
|
||||
cd.setFiledTypeClassName(String.class.getName());
|
||||
cd.setDisplaySize(1);
|
||||
cd.setPrecisionSize(1);
|
||||
cd.setScaleSize(0);
|
||||
cd.setAutoIncrement(false);
|
||||
cd.setNullable(true);
|
||||
}
|
||||
|
||||
boolean signed = false;
|
||||
try {
|
||||
signed = m.isSigned(i);
|
||||
} catch (Exception ignored) {
|
||||
// This JDBC Driver doesn't support the isSigned method
|
||||
// nothing more we can do here by catch the exception.
|
||||
}
|
||||
cd.setSigned(signed);
|
||||
cd.setDbType(dbtype);
|
||||
|
||||
ret.add(cd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
JdbcOperatorUtils.closeResultSet(rs);
|
||||
JdbcOperatorUtils.closeStatement(pstmt);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.database;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
import com.weishao.dbswitch.core.database.impl.DatabaseGreenplumImpl;
|
||||
import com.weishao.dbswitch.core.database.impl.DatabaseMysqlImpl;
|
||||
import com.weishao.dbswitch.core.database.impl.DatabaseOracleImpl;
|
||||
import com.weishao.dbswitch.core.database.impl.DatabasePostgresImpl;
|
||||
import com.weishao.dbswitch.core.database.impl.DatabaseSqlserver2000Impl;
|
||||
import com.weishao.dbswitch.core.database.impl.DatabaseSqlserverImpl;
|
||||
|
||||
/**
|
||||
* 数据库实例构建工厂类
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public final class DatabaseFactory {
|
||||
|
||||
private static final Map<DatabaseTypeEnum,String> DATABASE_MAPPER=new HashMap<DatabaseTypeEnum, String>(){
|
||||
|
||||
private static final long serialVersionUID = 9202705534880971997L;
|
||||
|
||||
{
|
||||
put(DatabaseTypeEnum.MYSQL,DatabaseMysqlImpl.class.getName());
|
||||
put(DatabaseTypeEnum.ORACLE,DatabaseOracleImpl.class.getName());
|
||||
put(DatabaseTypeEnum.SQLSERVER2000,DatabaseSqlserver2000Impl.class.getName());
|
||||
put(DatabaseTypeEnum.SQLSERVER,DatabaseSqlserverImpl.class.getName());
|
||||
put(DatabaseTypeEnum.POSTGRESQL,DatabasePostgresImpl.class.getName());
|
||||
put(DatabaseTypeEnum.GREENPLUM,DatabaseGreenplumImpl.class.getName());
|
||||
}};
|
||||
|
||||
public static AbstractDatabase getDatabaseInstance(DatabaseTypeEnum type) {
|
||||
if(DATABASE_MAPPER.containsKey(type)) {
|
||||
String className= DATABASE_MAPPER.get(type);
|
||||
try {
|
||||
return (AbstractDatabase) Class.forName(className).newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException(String.format("Unkown database type (%s)",type.name()));
|
||||
}
|
||||
|
||||
private DatabaseFactory() {
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,123 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.database;
|
||||
|
||||
import java.util.List;
|
||||
import com.weishao.dbswitch.core.model.ColumnDescription;
|
||||
import com.weishao.dbswitch.core.model.ColumnMetaData;
|
||||
import com.weishao.dbswitch.core.model.TableDescription;
|
||||
|
||||
/**
|
||||
* 数据库访问通用业务接口
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public interface IDatabaseInterface extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* 建立数据库连接
|
||||
*
|
||||
* @param jdbcurl JDBC的URL连接字符串
|
||||
* @param username 用户名
|
||||
* @param password 密码
|
||||
*/
|
||||
public void connect(String jdbcurl, String username, String password);
|
||||
|
||||
/**
|
||||
* 断开数据库连接
|
||||
*/
|
||||
@Override
|
||||
public void close();
|
||||
|
||||
/**
|
||||
* 获取数据库的模式schema列表
|
||||
*
|
||||
* @return 模式名列表
|
||||
*/
|
||||
public List<String> querySchemaList();
|
||||
|
||||
/**
|
||||
* 获取指定模式Schema内的所有表列表
|
||||
*
|
||||
* @param schemaName 模式名称
|
||||
* @return 表及视图名列表
|
||||
*/
|
||||
public List<TableDescription> queryTableList(String schemaName);
|
||||
|
||||
/**
|
||||
* 获取指定模式表的元信息
|
||||
*
|
||||
* @param schemaName 模式名称
|
||||
* @param tableName 表或视图名称
|
||||
* @return 字段元信息列表
|
||||
*/
|
||||
public List<ColumnDescription> queryTableColumnMeta(String schemaName, String tableName);
|
||||
|
||||
/**
|
||||
* 获取指定查询SQL的元信息
|
||||
*
|
||||
* @param sql SQL查询语句
|
||||
* @return 字段元信息列表
|
||||
*/
|
||||
public List<ColumnDescription> querySelectSqlColumnMeta(String sql);
|
||||
|
||||
/**
|
||||
* 获取指定模式表的主键字段列表
|
||||
*
|
||||
* @param schemaName 模式名称
|
||||
* @param tableName 表名称
|
||||
* @return 主键字段名称列表
|
||||
*/
|
||||
public List<String> queryTablePrimaryKeys(String schemaName, String tableName);
|
||||
|
||||
/**
|
||||
* 测试查询SQL语句的有效性
|
||||
*
|
||||
* @param sql 待验证的SQL语句
|
||||
*/
|
||||
public void testQuerySQL(String sql);
|
||||
|
||||
/**
|
||||
* 获取数据库的表全名
|
||||
*
|
||||
* @param schemaName 模式名称
|
||||
* @param tableName 表名称
|
||||
* @return 表全名
|
||||
*/
|
||||
public String getQuotedSchemaTableCombination(String schemaName, String tableName);
|
||||
|
||||
/**
|
||||
* 获取字段列的结构定义
|
||||
*
|
||||
* @param v 值元数据定义
|
||||
* @param pks 主键字段名称列表
|
||||
* @param addCr 是否结尾换行
|
||||
* @param useAutoInc 是否自增
|
||||
* @return 字段定义字符串
|
||||
*/
|
||||
public String getFieldDefinition(ColumnMetaData v, List<String> pks, boolean useAutoInc, boolean addCr);
|
||||
|
||||
/**
|
||||
* 主键列转换为逗号分隔的字符串
|
||||
*
|
||||
* @param pks 主键字段列表
|
||||
* @return 主键字段拼接串
|
||||
*/
|
||||
public String getPrimaryKeyAsString(List<String> pks);
|
||||
|
||||
/**
|
||||
* SQL语句格式化
|
||||
*
|
||||
* @param sql SQL的语句
|
||||
* @return 格式化后的SQL语句
|
||||
*/
|
||||
public String formatSQL(String sql);
|
||||
}
|
@@ -0,0 +1,132 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.database.impl;
|
||||
|
||||
import java.util.List;
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
import com.weishao.dbswitch.core.constant.Const;
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
import com.weishao.dbswitch.core.database.AbstractDatabase;
|
||||
import com.weishao.dbswitch.core.database.IDatabaseInterface;
|
||||
import com.weishao.dbswitch.core.model.ColumnDescription;
|
||||
import com.weishao.dbswitch.core.model.ColumnMetaData;
|
||||
|
||||
/**
|
||||
* 支持Greenplum数据库的元信息实现
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class DatabaseGreenplumImpl extends AbstractDatabase implements IDatabaseInterface {
|
||||
|
||||
public DatabaseGreenplumImpl() {
|
||||
super("com.pivotal.jdbc.GreenplumDriver");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnDescription> querySelectSqlColumnMeta(String sql) {
|
||||
String querySQL = String.format(" %s LIMIT 1 OFFSET 0 ", sql.replace(";", ""));
|
||||
return this.getSelectSqlColumnMeta(querySQL, DatabaseTypeEnum.GREENPLUM);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTableFieldsQuerySQL(String schemaName, String tableName) {
|
||||
return String.format("SELECT * FROM \"%s\".\"%s\" ", schemaName, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestQuerySQL(String sql) {
|
||||
return String.format("explain %s", sql.replace(";", ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatSQL(String sql) {
|
||||
return SQLUtils.formatPGSql(sql, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFieldDefinition(ColumnMetaData v, List<String> pks, boolean useAutoInc, boolean addCr) {
|
||||
String fieldname = v.getName();
|
||||
int length = v.getLength();
|
||||
int precision = v.getPrecision();
|
||||
int type = v.getType();
|
||||
|
||||
String retval =" \""+fieldname + "\" ";
|
||||
|
||||
switch (type) {
|
||||
case ColumnMetaData.TYPE_TIMESTAMP:
|
||||
retval += "TIMESTAMP";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_TIME:
|
||||
retval += "TIME";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_DATE:
|
||||
retval += "DATE";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_BOOLEAN:
|
||||
retval += "VARCHAR(32)";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_NUMBER:
|
||||
case ColumnMetaData.TYPE_INTEGER:
|
||||
case ColumnMetaData.TYPE_BIGNUMBER:
|
||||
if (null!=pks && pks.contains(fieldname)) {
|
||||
if (useAutoInc) {
|
||||
retval += "BIGSERIAL";
|
||||
} else {
|
||||
retval += "BIGINT";
|
||||
}
|
||||
} else {
|
||||
if (length > 0) {
|
||||
if (precision > 0 || length > 18) {
|
||||
if ((length + precision) > 0 && precision > 0) {
|
||||
// Numeric(Precision, Scale): Precision = total length; Scale = decimal places
|
||||
retval += "NUMERIC(" + (length + precision) + ", " + precision + ")";
|
||||
} else {
|
||||
retval += "DOUBLE PRECISION";
|
||||
}
|
||||
} else {
|
||||
if (length > 9) {
|
||||
retval += "BIGINT";
|
||||
} else {
|
||||
if (length < 5) {
|
||||
retval += "SMALLINT";
|
||||
} else {
|
||||
retval += "INTEGER";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
retval += "DOUBLE PRECISION";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ColumnMetaData.TYPE_STRING:
|
||||
if (length < 1 || length >= AbstractDatabase.CLOB_LENGTH) {
|
||||
retval += "TEXT";
|
||||
} else {
|
||||
retval += "VARCHAR(" + length + ")";
|
||||
}
|
||||
break;
|
||||
case ColumnMetaData.TYPE_BINARY:
|
||||
retval += "BYTEA";
|
||||
break;
|
||||
default:
|
||||
retval += " TEXT";
|
||||
break;
|
||||
}
|
||||
|
||||
if (addCr) {
|
||||
retval += Const.CR;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
@@ -0,0 +1,229 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.database.impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
import com.weishao.dbswitch.core.constant.Const;
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
import com.weishao.dbswitch.core.database.AbstractDatabase;
|
||||
import com.weishao.dbswitch.core.database.IDatabaseInterface;
|
||||
import com.weishao.dbswitch.core.model.ColumnDescription;
|
||||
import com.weishao.dbswitch.core.model.ColumnMetaData;
|
||||
import com.weishao.dbswitch.core.model.TableDescription;
|
||||
import com.weishao.dbswitch.core.util.JdbcOperatorUtils;
|
||||
import com.weishao.dbswitch.core.util.JdbcUrlUtils;
|
||||
|
||||
/**
|
||||
* 支持MySQL数据库的元信息实现
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class DatabaseMysqlImpl extends AbstractDatabase implements IDatabaseInterface {
|
||||
|
||||
public DatabaseMysqlImpl() {
|
||||
super("com.mysql.cj.jdbc.Driver");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> querySchemaList() {
|
||||
String mysqlJdbcUrl=null;
|
||||
try {
|
||||
mysqlJdbcUrl = this.metaData.getURL();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Map<String, String> data=JdbcUrlUtils.findParamsByMySqlJdbcUrl(mysqlJdbcUrl);
|
||||
List<String> ret=new ArrayList<String>();
|
||||
ret.add(data.get("schema"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableDescription> queryTableList(String schemaName) {
|
||||
List<TableDescription> ret = new ArrayList<>();
|
||||
String sql = String.format(
|
||||
"SELECT `TABLE_SCHEMA`,`TABLE_NAME`,`TABLE_TYPE`,`TABLE_COMMENT` FROM `information_schema`.`TABLES` where `TABLE_SCHEMA`='%s'",
|
||||
schemaName);
|
||||
PreparedStatement pstmt = null;
|
||||
ResultSet rs = null;
|
||||
|
||||
try {
|
||||
pstmt = this.connection.prepareStatement(sql);
|
||||
rs = pstmt.executeQuery();
|
||||
while (rs.next()) {
|
||||
TableDescription td=new TableDescription();
|
||||
td.setSchemaName(rs.getString("TABLE_SCHEMA"));
|
||||
td.setTableName(rs.getString("TABLE_NAME"));
|
||||
td.setRemarks(rs.getString("TABLE_COMMENT"));
|
||||
String tableType=rs.getString("TABLE_TYPE");
|
||||
if(tableType.equalsIgnoreCase("VIEW")) {
|
||||
td.setTableType("VIEW");
|
||||
}else {
|
||||
td.setTableType("TABLE");
|
||||
}
|
||||
|
||||
ret.add(td);
|
||||
}
|
||||
|
||||
return ret;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
JdbcOperatorUtils.closeResultSet(rs);
|
||||
JdbcOperatorUtils.closeStatement(pstmt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnDescription> querySelectSqlColumnMeta(String sql) {
|
||||
String querySQL = String.format(" %s LIMIT 1", sql.replace(";", ""));
|
||||
return this.getSelectSqlColumnMeta(querySQL, DatabaseTypeEnum.MYSQL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTableFieldsQuerySQL(String schemaName, String tableName) {
|
||||
return String.format("SELECT * FROM `%s`.`%s` ", schemaName, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestQuerySQL(String sql) {
|
||||
return String.format("explain %s", sql.replace(";", ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuotedSchemaTableCombination(String schemaName, String tableName) {
|
||||
return String.format(" `%s`.`%s` ", schemaName, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatSQL(String sql) {
|
||||
return SQLUtils.formatMySql(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFieldDefinition(ColumnMetaData v, List<String> pks, boolean useAutoInc, boolean addCr) {
|
||||
String fieldname = v.getName();
|
||||
int length = v.getLength();
|
||||
int precision = v.getPrecision();
|
||||
int type = v.getType();
|
||||
|
||||
String retval = " `"+fieldname + "` ";
|
||||
|
||||
switch (type) {
|
||||
case ColumnMetaData.TYPE_TIMESTAMP:
|
||||
retval += "DATETIME";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_TIME:
|
||||
retval += "TIME";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_DATE:
|
||||
retval += "DATE";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_BOOLEAN:
|
||||
retval += "VARCHAR(32)";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_NUMBER:
|
||||
case ColumnMetaData.TYPE_INTEGER:
|
||||
case ColumnMetaData.TYPE_BIGNUMBER:
|
||||
if (null!=pks && pks.contains(fieldname)) {
|
||||
if (useAutoInc) {
|
||||
retval += "BIGINT AUTO_INCREMENT NOT NULL";
|
||||
} else {
|
||||
retval += "BIGINT NOT NULL";
|
||||
}
|
||||
} else {
|
||||
// Integer values...
|
||||
if (precision == 0) {
|
||||
if (length > 9) {
|
||||
if (length < 19) {
|
||||
// can hold signed values between -9223372036854775808 and 9223372036854775807
|
||||
// 18 significant digits
|
||||
retval += "BIGINT";
|
||||
} else {
|
||||
retval += "DECIMAL(" + length + ")";
|
||||
}
|
||||
} else {
|
||||
retval += "INT";
|
||||
}
|
||||
} else {
|
||||
// Floating point values...
|
||||
if (length > 15) {
|
||||
retval += "DECIMAL(" + length;
|
||||
if (precision > 0) {
|
||||
retval += ", " + precision;
|
||||
}
|
||||
retval += ")";
|
||||
} else {
|
||||
// A double-precision floating-point number is accurate to approximately 15
|
||||
// decimal places.
|
||||
// http://mysql.mirrors-r-us.net/doc/refman/5.1/en/numeric-type-overview.html
|
||||
retval += "DOUBLE";
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ColumnMetaData.TYPE_STRING:
|
||||
if (length > 0) {
|
||||
if (length == 1) {
|
||||
retval += "CHAR(1)";
|
||||
} else if (length < 256) {
|
||||
retval += "VARCHAR(" + length + ")";
|
||||
}else if (null!=pks && pks.contains(fieldname)) {
|
||||
//MySQL中varchar字段为主键时最大长度为254
|
||||
retval += "VARCHAR(254)";
|
||||
} else if (length < 65536) {
|
||||
retval += "TEXT";
|
||||
} else if (length < 16777216) {
|
||||
retval += "MEDIUMTEXT";
|
||||
} else {
|
||||
retval += "LONGTEXT";
|
||||
}
|
||||
} else {
|
||||
retval += "TINYTEXT";
|
||||
}
|
||||
break;
|
||||
case ColumnMetaData.TYPE_BINARY:
|
||||
retval += "LONGBLOB";
|
||||
break;
|
||||
default:
|
||||
retval += " LONGTEXT";
|
||||
break;
|
||||
}
|
||||
|
||||
if (addCr) {
|
||||
retval += Const.CR;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrimaryKeyAsString(List<String> pks) {
|
||||
if (!pks.isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("`");
|
||||
sb.append(StringUtils.join(pks, "` , `"));
|
||||
sb.append("`");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,199 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.database.impl;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
import com.weishao.dbswitch.core.constant.Const;
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
import com.weishao.dbswitch.core.database.AbstractDatabase;
|
||||
import com.weishao.dbswitch.core.database.IDatabaseInterface;
|
||||
import com.weishao.dbswitch.core.model.ColumnDescription;
|
||||
import com.weishao.dbswitch.core.model.ColumnMetaData;
|
||||
import com.weishao.dbswitch.core.model.TableDescription;
|
||||
import com.weishao.dbswitch.core.util.JdbcOperatorUtils;
|
||||
|
||||
/**
|
||||
* 支持Oracle数据库的元信息实现
|
||||
* 备注:
|
||||
* (1)Oracle12c安装教程:
|
||||
* 官方安装版:https://www.w3cschool.cn/oraclejc/oraclejc-vuqx2qqu.html
|
||||
* Docker版本:http://www.pianshen.com/article/4448142743/
|
||||
* https://www.cnblogs.com/Dev0ps/p/10676930.html
|
||||
* (2) Oralce的一个表里至多只能有一个字段为LONG类型
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class DatabaseOracleImpl extends AbstractDatabase implements IDatabaseInterface {
|
||||
|
||||
public DatabaseOracleImpl() {
|
||||
super("oracle.jdbc.driver.OracleDriver");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableDescription> queryTableList(String schemaName) {
|
||||
List<TableDescription> ret = new ArrayList<TableDescription>();
|
||||
String sql = String.format(
|
||||
"SELECT \"OWNER\",\"TABLE_NAME\",\"TABLE_TYPE\",\"COMMENTS\" from all_tab_comments where \"OWNER\"='%s'",
|
||||
schemaName);
|
||||
PreparedStatement pstmt = null;
|
||||
ResultSet rs = null;
|
||||
|
||||
try {
|
||||
pstmt = this.connection.prepareStatement(sql);
|
||||
rs = pstmt.executeQuery();
|
||||
while (rs.next()) {
|
||||
TableDescription td=new TableDescription();
|
||||
td.setSchemaName(rs.getString("OWNER"));
|
||||
td.setTableName(rs.getString("TABLE_NAME"));
|
||||
td.setRemarks(rs.getString("COMMENTS"));
|
||||
String tableType=rs.getString("TABLE_TYPE").trim();
|
||||
if(tableType.equalsIgnoreCase("VIEW")) {
|
||||
td.setTableType("VIEW");
|
||||
}else {
|
||||
td.setTableType("TABLE");
|
||||
}
|
||||
|
||||
ret.add(td);
|
||||
}
|
||||
|
||||
return ret;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
JdbcOperatorUtils.closeResultSet(rs);
|
||||
JdbcOperatorUtils.closeStatement(pstmt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> queryTablePrimaryKeys(String schemaName, String tableName) {
|
||||
// Oracle表的主键可以使用如下命令设置主键是否生效
|
||||
// 使主键失效:alter table tableName disable primary key;
|
||||
// 使主键恢复:alter table tableName enable primary key;
|
||||
Set<String> ret = new HashSet<String>();
|
||||
String sql = String.format("SELECT COLUMN_NAME FROM user_cons_columns WHERE owner='%s' and constraint_name = "
|
||||
+ "(SELECT constraint_name FROM user_constraints WHERE table_name = '%s' AND constraint_type = 'P' and STATUS='ENABLED') ",
|
||||
schemaName, tableName);
|
||||
PreparedStatement pstmt = null;
|
||||
ResultSet rs = null;
|
||||
|
||||
try {
|
||||
pstmt = this.connection.prepareStatement(sql);
|
||||
rs = pstmt.executeQuery();
|
||||
while (rs.next()) {
|
||||
ret.add(rs.getString("COLUMN_NAME"));
|
||||
}
|
||||
|
||||
return new ArrayList<String>(ret);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
JdbcOperatorUtils.closeResultSet(rs);
|
||||
JdbcOperatorUtils.closeStatement(pstmt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnDescription> querySelectSqlColumnMeta(String sql) {
|
||||
String querySQL = String.format("SELECT * from (%s) tmp where ROWNUM<=1 ", sql.replace(";", ""));
|
||||
return this.getSelectSqlColumnMeta(querySQL, DatabaseTypeEnum.MYSQL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTableFieldsQuerySQL(String schemaName, String tableName) {
|
||||
return String.format("SELECT * FROM \"%s\".\"%s\" ", schemaName, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestQuerySQL(String sql) {
|
||||
return String.format("explain plan for %s", sql.replace(";", ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatSQL(String sql) {
|
||||
return SQLUtils.formatOracle(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFieldDefinition(ColumnMetaData v, List<String> pks, boolean useAutoInc, boolean addCr) {
|
||||
String fieldname = v.getName();
|
||||
int length = v.getLength();
|
||||
int precision = v.getPrecision();
|
||||
|
||||
StringBuilder retval = new StringBuilder(128);
|
||||
retval.append(" \"").append(fieldname).append("\" ");
|
||||
|
||||
int type = v.getType();
|
||||
switch (type) {
|
||||
case ColumnMetaData.TYPE_TIMESTAMP:
|
||||
case ColumnMetaData.TYPE_TIME:
|
||||
retval.append("TIMESTAMP");
|
||||
break;
|
||||
case ColumnMetaData.TYPE_DATE:
|
||||
retval.append("DATE");
|
||||
break;
|
||||
case ColumnMetaData.TYPE_BOOLEAN:
|
||||
retval.append("VARCHAR(32)");
|
||||
break;
|
||||
case ColumnMetaData.TYPE_NUMBER:
|
||||
case ColumnMetaData.TYPE_BIGNUMBER:
|
||||
retval.append("NUMBER");
|
||||
if (length > 0) {
|
||||
if (length > 38) {
|
||||
length = 38;
|
||||
}
|
||||
|
||||
retval.append('(').append(length);
|
||||
if (precision > 0) {
|
||||
retval.append(", ").append(precision);
|
||||
}
|
||||
retval.append(')');
|
||||
}
|
||||
break;
|
||||
case ColumnMetaData.TYPE_INTEGER:
|
||||
retval.append("INTEGER");
|
||||
break;
|
||||
case ColumnMetaData.TYPE_STRING:
|
||||
if (length >= AbstractDatabase.CLOB_LENGTH) {
|
||||
retval.append("CLOB");
|
||||
} else {
|
||||
if (length == 1) {
|
||||
retval.append("CHAR(1)");
|
||||
} else if (length > 0) {
|
||||
retval.append("VARCHAR2(").append(length).append(')');
|
||||
} else {
|
||||
retval.append("CLOB");// We don't know, so we just use the maximum...
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ColumnMetaData.TYPE_BINARY: // the BLOB can contain binary data.
|
||||
retval.append("BLOB");
|
||||
break;
|
||||
default:
|
||||
retval.append("CLOB");
|
||||
break;
|
||||
}
|
||||
|
||||
if (addCr) {
|
||||
retval.append(Const.CR);
|
||||
}
|
||||
|
||||
return retval.toString();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,133 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.database.impl;
|
||||
|
||||
import java.util.List;
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
import com.weishao.dbswitch.core.constant.Const;
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
import com.weishao.dbswitch.core.database.AbstractDatabase;
|
||||
import com.weishao.dbswitch.core.database.IDatabaseInterface;
|
||||
import com.weishao.dbswitch.core.model.ColumnDescription;
|
||||
import com.weishao.dbswitch.core.model.ColumnMetaData;
|
||||
|
||||
/**
|
||||
* 支持PostgreSQL数据库的元信息实现
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class DatabasePostgresImpl extends AbstractDatabase implements IDatabaseInterface {
|
||||
|
||||
public DatabasePostgresImpl() {
|
||||
super("org.postgresql.Driver");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnDescription> querySelectSqlColumnMeta(String sql) {
|
||||
String querySQL = String.format(" %s LIMIT 1 OFFSET 0 ", sql.replace(";", ""));
|
||||
return this.getSelectSqlColumnMeta(querySQL, DatabaseTypeEnum.POSTGRESQL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTableFieldsQuerySQL(String schemaName, String tableName) {
|
||||
return String.format("SELECT * FROM \"%s\".\"%s\" ", schemaName, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestQuerySQL(String sql) {
|
||||
return String.format("explain %s", sql.replace(";", ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatSQL(String sql) {
|
||||
return SQLUtils.formatPGSql(sql,null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFieldDefinition(ColumnMetaData v, List<String> pks, boolean useAutoInc, boolean addCr) {
|
||||
String fieldname = v.getName();
|
||||
int length = v.getLength();
|
||||
int precision = v.getPrecision();
|
||||
int type = v.getType();
|
||||
|
||||
String retval = " \"" + fieldname + "\" ";
|
||||
|
||||
switch (type) {
|
||||
case ColumnMetaData.TYPE_TIMESTAMP:
|
||||
retval += "TIMESTAMP";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_TIME:
|
||||
retval += "TIME";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_DATE:
|
||||
retval += "DATE";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_BOOLEAN:
|
||||
retval += "VARCHAR(32)";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_NUMBER:
|
||||
case ColumnMetaData.TYPE_INTEGER:
|
||||
case ColumnMetaData.TYPE_BIGNUMBER:
|
||||
if (null != pks && pks.contains(fieldname)) {
|
||||
if (useAutoInc) {
|
||||
retval += "BIGSERIAL";
|
||||
} else {
|
||||
retval += "BIGINT";
|
||||
}
|
||||
} else {
|
||||
if (length > 0) {
|
||||
if (precision > 0 || length > 18) {
|
||||
if ((length + precision) > 0 && precision > 0) {
|
||||
// Numeric(Precision, Scale): Precision = total length; Scale = decimal places
|
||||
retval += "NUMERIC(" + (length + precision) + ", " + precision + ")";
|
||||
} else {
|
||||
retval += "DOUBLE PRECISION";
|
||||
}
|
||||
} else {
|
||||
if (length > 9) {
|
||||
retval += "BIGINT";
|
||||
} else {
|
||||
if (length < 5) {
|
||||
retval += "SMALLINT";
|
||||
} else {
|
||||
retval += "INTEGER";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
retval += "DOUBLE PRECISION";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ColumnMetaData.TYPE_STRING:
|
||||
if (length < 1 || length >= AbstractDatabase.CLOB_LENGTH) {
|
||||
retval += "TEXT";
|
||||
} else {
|
||||
retval += "VARCHAR(" + length + ")";
|
||||
}
|
||||
break;
|
||||
case ColumnMetaData.TYPE_BINARY:
|
||||
retval += "BYTEA";
|
||||
break;
|
||||
default:
|
||||
retval += "TEXT";
|
||||
break;
|
||||
}
|
||||
|
||||
if (addCr) {
|
||||
retval += Const.CR;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.database.impl;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import com.weishao.dbswitch.core.database.IDatabaseInterface;
|
||||
import com.weishao.dbswitch.core.model.ColumnDescription;
|
||||
import com.weishao.dbswitch.core.model.TableDescription;
|
||||
import com.weishao.dbswitch.core.util.JdbcOperatorUtils;
|
||||
|
||||
/**
|
||||
* 支持SQLServer2000数据库的元信息实现
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class DatabaseSqlserver2000Impl extends DatabaseSqlserverImpl implements IDatabaseInterface {
|
||||
|
||||
public DatabaseSqlserver2000Impl() {
|
||||
super("com.microsoft.jdbc.sqlserver.SQLServerDriver");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableDescription> queryTableList(String schemaName) {
|
||||
List<TableDescription> ret = new ArrayList<>();
|
||||
Set<String> uniqueSet = new HashSet<>();
|
||||
ResultSet tables = null;
|
||||
try {
|
||||
tables = this.metaData.getTables(this.catalogName, schemaName, "%", new String[] { "TABLE","VIEW" });
|
||||
while (tables.next()) {
|
||||
String tableName = tables.getString("TABLE_NAME");
|
||||
if (uniqueSet.contains(tableName)) {
|
||||
continue;
|
||||
} else {
|
||||
uniqueSet.add(tableName);
|
||||
}
|
||||
|
||||
TableDescription td = new TableDescription();
|
||||
td.setSchemaName(schemaName);
|
||||
td.setTableName(tableName);
|
||||
td.setRemarks(tables.getString("REMARKS"));
|
||||
if (tables.getString("TABLE_TYPE").equalsIgnoreCase("VIEW")) {
|
||||
td.setTableType("VIEW");
|
||||
} else {
|
||||
td.setTableType("TABLE");
|
||||
}
|
||||
ret.add(td);
|
||||
}
|
||||
return ret;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
JdbcOperatorUtils.closeResultSet(tables);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnDescription> queryTableColumnMeta(String schemaName, String tableName) {
|
||||
String sql = this.getTableFieldsQuerySQL(schemaName, tableName);
|
||||
List<ColumnDescription> ret = this.querySelectSqlColumnMeta(sql);
|
||||
ResultSet columns = null;
|
||||
try {
|
||||
columns = this.metaData.getColumns(this.catalogName, schemaName, tableName, null);
|
||||
while (columns.next()) {
|
||||
String columnName = columns.getString("COLUMN_NAME");
|
||||
String remarks = columns.getString("REMARKS");
|
||||
for (ColumnDescription cd : ret) {
|
||||
if (columnName.equalsIgnoreCase(cd.getFieldName())) {
|
||||
cd.setRemarks(remarks);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
JdbcOperatorUtils.closeResultSet(columns);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
@@ -0,0 +1,302 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.database.impl;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
import com.weishao.dbswitch.core.constant.Const;
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
import com.weishao.dbswitch.core.database.AbstractDatabase;
|
||||
import com.weishao.dbswitch.core.database.IDatabaseInterface;
|
||||
import com.weishao.dbswitch.core.model.ColumnDescription;
|
||||
import com.weishao.dbswitch.core.model.ColumnMetaData;
|
||||
import com.weishao.dbswitch.core.model.TableDescription;
|
||||
import com.weishao.dbswitch.core.util.JdbcOperatorUtils;
|
||||
|
||||
/**
|
||||
* 支持SQLServer数据库的元信息实现
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class DatabaseSqlserverImpl extends AbstractDatabase implements IDatabaseInterface {
|
||||
|
||||
private static Set<String> excludesSchemaNames;
|
||||
|
||||
static {
|
||||
excludesSchemaNames = new HashSet<>();
|
||||
excludesSchemaNames.add("db_denydatawriter");
|
||||
excludesSchemaNames.add("db_datawriter");
|
||||
excludesSchemaNames.add("db_accessadmin");
|
||||
excludesSchemaNames.add("db_ddladmin");
|
||||
excludesSchemaNames.add("db_securityadmin");
|
||||
excludesSchemaNames.add("db_denydatareader");
|
||||
excludesSchemaNames.add("db_backupoperator");
|
||||
excludesSchemaNames.add("db_datareader");
|
||||
excludesSchemaNames.add("db_owner");
|
||||
}
|
||||
|
||||
public DatabaseSqlserverImpl() {
|
||||
super("com.microsoft.sqlserver.jdbc.SQLServerDriver");
|
||||
}
|
||||
|
||||
public DatabaseSqlserverImpl(String driverName) {
|
||||
super(driverName);
|
||||
}
|
||||
|
||||
private int getDatabaseMajorVersion() {
|
||||
int majorVersion = 0;
|
||||
try {
|
||||
majorVersion = this.metaData.getDatabaseMajorVersion();
|
||||
return majorVersion;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> querySchemaList() {
|
||||
Set<String> ret = new HashSet<String>();
|
||||
ResultSet schemas = null;
|
||||
try {
|
||||
schemas = this.metaData.getSchemas();
|
||||
while (schemas.next()) {
|
||||
String name = schemas.getString("TABLE_SCHEM");
|
||||
if (!excludesSchemaNames.contains(name)) {
|
||||
ret.add(name);
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(ret);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
try {
|
||||
if (null != schemas) {
|
||||
schemas.close();
|
||||
schemas = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableDescription> queryTableList(String schemaName) {
|
||||
int majorVersion=getDatabaseMajorVersion();
|
||||
if(majorVersion<=8) {
|
||||
return super.queryTableList(schemaName);
|
||||
}
|
||||
|
||||
List<TableDescription> ret = new ArrayList<>();
|
||||
String sql = String.format(
|
||||
"SELECT DISTINCT t.TABLE_SCHEMA as TABLE_SCHEMA, t.TABLE_NAME as TABLE_NAME, t.TABLE_TYPE as TABLE_TYPE, CONVERT(nvarchar(50),ISNULL(g.[value], '')) as COMMENTS \r\n" +
|
||||
"FROM INFORMATION_SCHEMA.TABLES t LEFT JOIN sysobjects d on t.TABLE_NAME = d.name \r\n" +
|
||||
"LEFT JOIN sys.extended_properties g on g.major_id=d.id and g.minor_id='0' where t.TABLE_SCHEMA='%s'",
|
||||
schemaName);
|
||||
PreparedStatement pstmt = null;
|
||||
ResultSet rs = null;
|
||||
|
||||
try {
|
||||
pstmt = this.connection.prepareStatement(sql);
|
||||
rs = pstmt.executeQuery();
|
||||
while (rs.next()) {
|
||||
TableDescription td = new TableDescription();
|
||||
td.setSchemaName(rs.getString("TABLE_SCHEMA"));
|
||||
td.setTableName(rs.getString("TABLE_NAME"));
|
||||
td.setRemarks(rs.getString("COMMENTS"));
|
||||
String tableType = rs.getString("TABLE_TYPE").trim();
|
||||
if (tableType.equalsIgnoreCase("VIEW")) {
|
||||
td.setTableType("VIEW");
|
||||
} else {
|
||||
td.setTableType("TABLE");
|
||||
}
|
||||
|
||||
ret.add(td);
|
||||
}
|
||||
|
||||
return ret;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
JdbcOperatorUtils.closeResultSet(rs);
|
||||
JdbcOperatorUtils.closeStatement(pstmt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnDescription> queryTableColumnMeta(String schemaName, String tableName) {
|
||||
int majorVersion = getDatabaseMajorVersion();
|
||||
if (majorVersion <= 8) {
|
||||
return super.queryTableColumnMeta(schemaName, tableName);
|
||||
}
|
||||
|
||||
String sql=this.getTableFieldsQuerySQL(schemaName, tableName);
|
||||
List<ColumnDescription> ret= this.querySelectSqlColumnMeta(sql);
|
||||
String qsql = String.format(
|
||||
"SELECT a.name AS COLUMN_NAME,CONVERT(nvarchar(50),ISNULL(g.[value], '')) AS REMARKS FROM sys.columns a\r\n" +
|
||||
"LEFT JOIN sys.extended_properties g ON ( a.object_id = g.major_id AND g.minor_id = a.column_id )\r\n" +
|
||||
"WHERE object_id = (SELECT top 1 object_id FROM sys.tables st INNER JOIN INFORMATION_SCHEMA.TABLES t on st.name=t.TABLE_NAME\r\n" +
|
||||
"WHERE st.name = '%s' and t.TABLE_SCHEMA='%s')",
|
||||
tableName,schemaName);
|
||||
PreparedStatement pstmt = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
pstmt = this.connection.prepareStatement(qsql);
|
||||
rs = pstmt.executeQuery();
|
||||
while (rs.next()) {
|
||||
String columnName = rs.getString("COLUMN_NAME");
|
||||
String remarks = rs.getString("REMARKS");
|
||||
for (ColumnDescription cd : ret) {
|
||||
if (columnName.equalsIgnoreCase(cd.getFieldName())) {
|
||||
cd.setRemarks(remarks);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
JdbcOperatorUtils.closeResultSet(rs);
|
||||
JdbcOperatorUtils.closeStatement(pstmt);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnDescription> querySelectSqlColumnMeta(String sql) {
|
||||
String querySQL = String.format("SELECT TOP 1 * from (%s) tmp ", sql.replace(";", ""));
|
||||
return this.getSelectSqlColumnMeta(querySQL, DatabaseTypeEnum.SQLSERVER);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTableFieldsQuerySQL(String schemaName, String tableName) {
|
||||
return String.format("select top 1 * from [%s].[%s] ", schemaName, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestQuerySQL(String sql) {
|
||||
return String.format("SELECT top 1 * from ( %s ) tmp", sql.replace(";", ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuotedSchemaTableCombination(String schemaName, String tableName) {
|
||||
return String.format(" [%s].[%s] ", schemaName, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatSQL(String sql) {
|
||||
return SQLUtils.formatSQLServer(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFieldDefinition(ColumnMetaData v, List<String> pks, boolean useAutoInc, boolean addCr) {
|
||||
String fieldname = v.getName();
|
||||
int length = v.getLength();
|
||||
int precision = v.getPrecision();
|
||||
int type = v.getType();
|
||||
|
||||
String retval = " [" + fieldname + "] ";
|
||||
|
||||
switch (type) {
|
||||
case ColumnMetaData.TYPE_TIMESTAMP:
|
||||
retval += "DATETIME";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_TIME:
|
||||
retval += "TIME";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_DATE:
|
||||
retval += "DATE";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_BOOLEAN:
|
||||
retval += "VARCHAR(32)";
|
||||
break;
|
||||
case ColumnMetaData.TYPE_NUMBER:
|
||||
case ColumnMetaData.TYPE_INTEGER:
|
||||
case ColumnMetaData.TYPE_BIGNUMBER:
|
||||
if (null != pks && pks.contains(fieldname)) {
|
||||
if (useAutoInc) {
|
||||
retval += "BIGINT IDENTITY(0,1)";
|
||||
} else {
|
||||
retval += "BIGINT";
|
||||
}
|
||||
} else {
|
||||
if (precision == 0) {
|
||||
if (length > 18) {
|
||||
retval += "DECIMAL(" + length + ",0)";
|
||||
} else {
|
||||
if (length > 9) {
|
||||
retval += "BIGINT";
|
||||
} else {
|
||||
retval += "INT";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (precision > 0 && length > 0) {
|
||||
retval += "DECIMAL(" + length + "," + precision + ")";
|
||||
} else {
|
||||
retval += "FLOAT(53)";
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ColumnMetaData.TYPE_STRING:
|
||||
if (length < 8000) {
|
||||
// Maybe use some default DB String length in case length<=0
|
||||
if (length > 0) {
|
||||
// VARCHAR(n)最多能存n个字节,一个中文是两个字节。
|
||||
length = 2 * length;
|
||||
if (length > 8000) {
|
||||
length = 8000;
|
||||
}
|
||||
retval += "VARCHAR(" + length + ")";
|
||||
} else {
|
||||
retval += "VARCHAR(100)";
|
||||
}
|
||||
} else {
|
||||
retval += "TEXT"; // Up to 2bilion characters.
|
||||
}
|
||||
break;
|
||||
case ColumnMetaData.TYPE_BINARY:
|
||||
retval += "VARBINARY(MAX)";
|
||||
break;
|
||||
default:
|
||||
retval += "TEXT";
|
||||
break;
|
||||
}
|
||||
|
||||
if (addCr) {
|
||||
retval += Const.CR;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrimaryKeyAsString(List<String> pks) {
|
||||
if (!pks.isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[");
|
||||
sb.append(StringUtils.join(pks, "] , ["));
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,153 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.model;
|
||||
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
|
||||
/**
|
||||
* 数据库列描述符信息定义(Column Description)
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class ColumnDescription {
|
||||
|
||||
private String fieldName;
|
||||
private String labelName;
|
||||
private String fieldTypeName;
|
||||
private String filedTypeClassName;
|
||||
private int fieldType;
|
||||
private int displaySize;
|
||||
private int scaleSize;
|
||||
private int precisionSize;
|
||||
private boolean isAutoIncrement;
|
||||
private boolean isNullable;
|
||||
private String remarks;
|
||||
private boolean signed = false;
|
||||
private DatabaseTypeEnum dbtype;
|
||||
|
||||
public String getFieldName() {
|
||||
if (null != this.fieldName) {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
return this.labelName;
|
||||
}
|
||||
|
||||
public void setFieldName(String fieldName) {
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
public String getLabelName() {
|
||||
if (null != labelName) {
|
||||
return labelName;
|
||||
}
|
||||
|
||||
return this.fieldName;
|
||||
}
|
||||
|
||||
public void setLabelName(String labalName) {
|
||||
this.labelName = labalName;
|
||||
}
|
||||
|
||||
public String getFieldTypeName() {
|
||||
return fieldTypeName;
|
||||
}
|
||||
|
||||
public void setFieldTypeName(String fieldTypeName) {
|
||||
this.fieldTypeName = fieldTypeName;
|
||||
}
|
||||
|
||||
public String getFiledTypeClassName() {
|
||||
return filedTypeClassName;
|
||||
}
|
||||
|
||||
public void setFiledTypeClassName(String filedTypeClassName) {
|
||||
this.filedTypeClassName = filedTypeClassName;
|
||||
}
|
||||
|
||||
public int getFieldType() {
|
||||
return fieldType;
|
||||
}
|
||||
|
||||
public void setFieldType(int fieldType) {
|
||||
this.fieldType = fieldType;
|
||||
}
|
||||
|
||||
public int getDisplaySize() {
|
||||
return displaySize;
|
||||
}
|
||||
|
||||
public void setDisplaySize(int displaySize) {
|
||||
this.displaySize = displaySize;
|
||||
}
|
||||
|
||||
public int getScaleSize() {
|
||||
return scaleSize;
|
||||
}
|
||||
|
||||
public void setScaleSize(int scaleSize) {
|
||||
this.scaleSize = scaleSize;
|
||||
}
|
||||
|
||||
public int getPrecisionSize() {
|
||||
return precisionSize;
|
||||
}
|
||||
|
||||
public void setPrecisionSize(int precisionSize) {
|
||||
this.precisionSize = precisionSize;
|
||||
}
|
||||
|
||||
public boolean isAutoIncrement() {
|
||||
return isAutoIncrement;
|
||||
}
|
||||
|
||||
public void setAutoIncrement(boolean isAutoIncrement) {
|
||||
this.isAutoIncrement = isAutoIncrement;
|
||||
}
|
||||
|
||||
public boolean isNullable() {
|
||||
return isNullable;
|
||||
}
|
||||
|
||||
public void setNullable(boolean isNullable) {
|
||||
this.isNullable = isNullable;
|
||||
}
|
||||
|
||||
public boolean isSigned() {
|
||||
return signed;
|
||||
}
|
||||
|
||||
public void setSigned(boolean signed) {
|
||||
this.signed=signed;
|
||||
}
|
||||
|
||||
public DatabaseTypeEnum getDbType() {
|
||||
return this.dbtype;
|
||||
}
|
||||
|
||||
public void setDbType(DatabaseTypeEnum dbtype) {
|
||||
this.dbtype=dbtype;
|
||||
}
|
||||
|
||||
public String getRemarks() {
|
||||
return this.remarks;
|
||||
}
|
||||
|
||||
public void setRemarks(String remarks) {
|
||||
this.remarks=remarks;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
|
||||
public ColumnMetaData getMetaData() {
|
||||
return new ColumnMetaData(this);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,424 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.model;
|
||||
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
import com.weishao.dbswitch.core.database.AbstractDatabase;
|
||||
|
||||
/**
|
||||
* 数据库表列的元信息
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class ColumnMetaData {
|
||||
|
||||
/** Value type indicating that the value has no type set */
|
||||
public static final int TYPE_NONE = 0;
|
||||
|
||||
/**
|
||||
* Value type indicating that the value contains a floating point double
|
||||
* precision number.
|
||||
*/
|
||||
public static final int TYPE_NUMBER = 1;
|
||||
|
||||
/** Value type indicating that the value contains a text String. */
|
||||
public static final int TYPE_STRING = 2;
|
||||
|
||||
/** Value type indicating that the value contains a Date. */
|
||||
public static final int TYPE_DATE = 3;
|
||||
|
||||
/** Value type indicating that the value contains a boolean. */
|
||||
public static final int TYPE_BOOLEAN = 4;
|
||||
|
||||
/** Value type indicating that the value contains a long integer. */
|
||||
public static final int TYPE_INTEGER = 5;
|
||||
|
||||
/**
|
||||
* Value type indicating that the value contains a floating point precision
|
||||
* number with arbitrary precision.
|
||||
*/
|
||||
public static final int TYPE_BIGNUMBER = 6;
|
||||
|
||||
/** Value type indicating that the value contains an Object. */
|
||||
public static final int TYPE_SERIALIZABLE = 7;
|
||||
|
||||
/**
|
||||
* Value type indicating that the value contains binary data: BLOB, CLOB, ...
|
||||
*/
|
||||
public static final int TYPE_BINARY = 8;
|
||||
|
||||
/**
|
||||
* Value type indicating that the value contains a date-time with nanosecond
|
||||
* precision
|
||||
*/
|
||||
public static final int TYPE_TIMESTAMP = 9;
|
||||
|
||||
/** Value type indicating that the value contains a time */
|
||||
public static final int TYPE_TIME=10;
|
||||
|
||||
/** Value type indicating that the value contains a Internet address */
|
||||
public static final int TYPE_INET = 11;
|
||||
|
||||
/** The Constant typeCodes. */
|
||||
public static final String[] TYPE_CODES = new String[] { "-", "Number", "String", "Date", "Boolean", "Integer",
|
||||
"BigNumber", "Serializable", "Binary", "Timestamp", "Time", "Internet Address", };
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** Column name */
|
||||
protected String name;
|
||||
protected int length;
|
||||
protected int precision;
|
||||
protected int type;
|
||||
|
||||
/**
|
||||
* Constructor function
|
||||
*
|
||||
* @param name
|
||||
* @param type
|
||||
* @param length
|
||||
* @param precision
|
||||
*/
|
||||
public ColumnMetaData(ColumnDescription desc) {
|
||||
this.create(desc);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(int length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public int getPrecision() {
|
||||
return precision;
|
||||
}
|
||||
|
||||
public void setPrecision(int precision) {
|
||||
this.precision = precision;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not the value is a String.
|
||||
*
|
||||
* @return true if the value is a String.
|
||||
*/
|
||||
public boolean isString() {
|
||||
return type == TYPE_STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not this value is a Date
|
||||
*
|
||||
* @return true if the value is a Date
|
||||
*/
|
||||
public boolean isDate() {
|
||||
return type == TYPE_DATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not this value is a Time
|
||||
*
|
||||
* @return true if the value is a Time
|
||||
*/
|
||||
public boolean isTime() {
|
||||
return type == TYPE_TIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not this value is a DateTime
|
||||
*
|
||||
* @return true if the value is a DateTime
|
||||
*/
|
||||
public boolean isDateTime() {
|
||||
return type == TYPE_TIMESTAMP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not the value is a Big Number
|
||||
*
|
||||
* @return true is this value is a big number
|
||||
*/
|
||||
public boolean isBigNumber() {
|
||||
return type == TYPE_BIGNUMBER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not the value is a Number
|
||||
*
|
||||
* @return true is this value is a number
|
||||
*/
|
||||
public boolean isNumber() {
|
||||
return type == TYPE_NUMBER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not this value is a boolean
|
||||
*
|
||||
* @return true if this value has type boolean.
|
||||
*/
|
||||
public boolean isBoolean() {
|
||||
return type == TYPE_BOOLEAN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not this value is of type Serializable
|
||||
*
|
||||
* @return true if this value has type Serializable
|
||||
*/
|
||||
public boolean isSerializableType() {
|
||||
return type == TYPE_SERIALIZABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not this value is of type Binary
|
||||
*
|
||||
* @return true if this value has type Binary
|
||||
*/
|
||||
public boolean isBinary() {
|
||||
return type == TYPE_BINARY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not this value is an Integer
|
||||
*
|
||||
* @return true if this value is an integer
|
||||
*/
|
||||
public boolean isInteger() {
|
||||
return type == TYPE_INTEGER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not this Value is Numeric A Value is numeric if it is
|
||||
* either of type Number or Integer
|
||||
*
|
||||
* @return true if the value is either of type Number or Integer
|
||||
*/
|
||||
public boolean isNumeric() {
|
||||
return isInteger() || isNumber() || isBigNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not the specified type is either Integer or Number
|
||||
*
|
||||
* @param t the type to check
|
||||
* @return true if the type is Integer or Number
|
||||
*/
|
||||
public static final boolean isNumeric(int t) {
|
||||
return t == TYPE_INTEGER || t == TYPE_NUMBER || t == TYPE_BIGNUMBER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of a value in a textual form: "String", "Number", "Integer",
|
||||
* "Boolean", "Date", ...
|
||||
*
|
||||
* @return A String describing the type of value.
|
||||
*/
|
||||
public String getTypeDesc() {
|
||||
return TYPE_CODES[type];
|
||||
}
|
||||
|
||||
private void create(ColumnDescription desc) {
|
||||
int length = -1;
|
||||
int precision = -1;
|
||||
int valtype = ColumnMetaData.TYPE_NONE;
|
||||
int type = desc.getFieldType();
|
||||
boolean signed = desc.isSigned();
|
||||
|
||||
switch (type) {
|
||||
case java.sql.Types.CHAR:
|
||||
case java.sql.Types.VARCHAR:
|
||||
case java.sql.Types.NVARCHAR:
|
||||
case java.sql.Types.LONGVARCHAR: // Character Large Object
|
||||
valtype = ColumnMetaData.TYPE_STRING;
|
||||
length = desc.getDisplaySize();
|
||||
break;
|
||||
|
||||
case java.sql.Types.CLOB:
|
||||
case java.sql.Types.NCLOB:
|
||||
valtype = ColumnMetaData.TYPE_STRING;
|
||||
length = AbstractDatabase.CLOB_LENGTH;
|
||||
break;
|
||||
|
||||
case java.sql.Types.BIGINT:
|
||||
// verify Unsigned BIGINT overflow!
|
||||
//
|
||||
if (signed) {
|
||||
valtype = ColumnMetaData.TYPE_INTEGER;
|
||||
precision = 0; // Max 9.223.372.036.854.775.807
|
||||
length = 15;
|
||||
} else {
|
||||
valtype = ColumnMetaData.TYPE_BIGNUMBER;
|
||||
precision = 0; // Max 18.446.744.073.709.551.615
|
||||
length = 16;
|
||||
}
|
||||
break;
|
||||
|
||||
case java.sql.Types.INTEGER:
|
||||
valtype = ColumnMetaData.TYPE_INTEGER;
|
||||
precision = 0; // Max 2.147.483.647
|
||||
length = 9;
|
||||
break;
|
||||
|
||||
case java.sql.Types.SMALLINT:
|
||||
valtype = ColumnMetaData.TYPE_INTEGER;
|
||||
precision = 0; // Max 32.767
|
||||
length = 4;
|
||||
break;
|
||||
|
||||
case java.sql.Types.TINYINT:
|
||||
valtype = ColumnMetaData.TYPE_INTEGER;
|
||||
precision = 0; // Max 127
|
||||
length = 2;
|
||||
break;
|
||||
|
||||
case java.sql.Types.DECIMAL:
|
||||
case java.sql.Types.DOUBLE:
|
||||
case java.sql.Types.FLOAT:
|
||||
case java.sql.Types.REAL:
|
||||
case java.sql.Types.NUMERIC:
|
||||
valtype = ColumnMetaData.TYPE_NUMBER;
|
||||
length = desc.getPrecisionSize();
|
||||
precision = desc.getScaleSize();
|
||||
if (length >= 126) {
|
||||
length = -1;
|
||||
}
|
||||
if (precision >= 126) {
|
||||
precision = -1;
|
||||
}
|
||||
|
||||
if (type == java.sql.Types.DOUBLE || type == java.sql.Types.FLOAT || type == java.sql.Types.REAL) {
|
||||
if (precision == 0) {
|
||||
if (!signed) {
|
||||
precision = -1; // precision is obviously incorrect if the type if
|
||||
// Double/Float/Real
|
||||
} else {
|
||||
length = 18;
|
||||
precision = 4;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're dealing with PostgreSQL and double precision types
|
||||
if (desc.getDbType() == DatabaseTypeEnum.POSTGRESQL && type == java.sql.Types.DOUBLE && precision >= 16
|
||||
&& length >= 16) {
|
||||
precision = -1;
|
||||
length = -1;
|
||||
}
|
||||
|
||||
// MySQL: max resolution is double precision floating point (double)
|
||||
// The (12,31) that is given back is not correct
|
||||
if (desc.getDbType() == DatabaseTypeEnum.MYSQL) {
|
||||
if (precision >= length) {
|
||||
precision = -1;
|
||||
length = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// if the length or precision needs a BIGNUMBER
|
||||
//if (length > 15 || precision > 15) {
|
||||
// valtype = ColumnMetaData.TYPE_BIGNUMBER;
|
||||
//}
|
||||
} else {
|
||||
if (precision == 0) {
|
||||
if (length <= 18 && length > 0) { // Among others Oracle is affected
|
||||
// here.
|
||||
valtype = ColumnMetaData.TYPE_INTEGER; // Long can hold up to 18
|
||||
// significant digits
|
||||
} else if (length > 18) {
|
||||
valtype = ColumnMetaData.TYPE_BIGNUMBER;
|
||||
}
|
||||
} else { // we have a precision: keep NUMBER or change to BIGNUMBER?
|
||||
if (length > 15 || precision > 15) {
|
||||
valtype = ColumnMetaData.TYPE_BIGNUMBER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (desc.getDbType() == DatabaseTypeEnum.POSTGRESQL || desc.getDbType() == DatabaseTypeEnum.GREENPLUM) {
|
||||
// undefined size => arbitrary precision
|
||||
if (type == java.sql.Types.NUMERIC && length == 0 && precision == 0) {
|
||||
valtype = ColumnMetaData.TYPE_BIGNUMBER;
|
||||
length = -1;
|
||||
precision = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (desc.getDbType() == DatabaseTypeEnum.ORACLE) {
|
||||
if (precision == 0 && length == 38) {
|
||||
valtype = ColumnMetaData.TYPE_INTEGER;
|
||||
}
|
||||
if (precision <= 0 && length <= 0) {
|
||||
// undefined size: BIGNUMBER,
|
||||
// precision on Oracle can be 38, too
|
||||
// big for a Number type
|
||||
valtype = ColumnMetaData.TYPE_BIGNUMBER;
|
||||
length = -1;
|
||||
precision = -1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case java.sql.Types.TIMESTAMP:
|
||||
valtype = ColumnMetaData.TYPE_TIMESTAMP;
|
||||
length = desc.getScaleSize();
|
||||
break;
|
||||
|
||||
case java.sql.Types.DATE:
|
||||
valtype = ColumnMetaData.TYPE_DATE;
|
||||
break;
|
||||
|
||||
case java.sql.Types.TIME:
|
||||
valtype = ColumnMetaData.TYPE_TIME;
|
||||
break;
|
||||
|
||||
case java.sql.Types.BOOLEAN:
|
||||
case java.sql.Types.BIT:
|
||||
valtype = ColumnMetaData.TYPE_BOOLEAN;
|
||||
break;
|
||||
|
||||
case java.sql.Types.BINARY:
|
||||
case java.sql.Types.BLOB:
|
||||
case java.sql.Types.VARBINARY:
|
||||
case java.sql.Types.LONGVARBINARY:
|
||||
valtype = ColumnMetaData.TYPE_BINARY;
|
||||
precision = -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
valtype = ColumnMetaData.TYPE_STRING;
|
||||
precision = desc.getScaleSize();
|
||||
break;
|
||||
}
|
||||
|
||||
this.name = desc.getFieldName();
|
||||
this.length = length;
|
||||
this.precision = precision;
|
||||
this.type = valtype;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.model;
|
||||
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
|
||||
/**
|
||||
* 数据库连接描述符信息定义(Database Description)
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class DatabaseDescription {
|
||||
protected DatabaseTypeEnum type;
|
||||
protected String host;
|
||||
protected int port;
|
||||
protected String mode;//对于Oracle数据库的模式,可取范围为:sid,servicename,tnsname三种
|
||||
protected String dbname;
|
||||
protected String charset;
|
||||
protected String username;
|
||||
protected String password;
|
||||
|
||||
public DatabaseDescription(String dbtype, String host, int port, String mode, String dbname, String charset,String username, String password) {
|
||||
this.type = DatabaseTypeEnum.valueOf(dbtype.toUpperCase());
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.mode = mode;
|
||||
this.dbname = dbname;
|
||||
this.charset = charset;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public DatabaseTypeEnum getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public String getDbname() {
|
||||
return dbname;
|
||||
}
|
||||
|
||||
public String getCharset() {
|
||||
return charset;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DatabaseDescription [type=" + type + ", host=" + host + ", port=" + port + ", mode=" + mode
|
||||
+ ", dbname=" + dbname + ", charset=" + charset + ", username=" + username + ", password=" + password
|
||||
+ "]";
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.model;
|
||||
|
||||
import com.weishao.dbswitch.core.constant.DBTableType;
|
||||
|
||||
/**
|
||||
* 数据库表描述符信息定义(Table Description)
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class TableDescription {
|
||||
|
||||
private String tableName;
|
||||
private String schemaName;
|
||||
private String remarks;
|
||||
private DBTableType tableType;
|
||||
|
||||
public String getTableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
public void setTableName(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public String getSchemaName() {
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
public void setSchemaName(String schemaName) {
|
||||
this.schemaName = schemaName;
|
||||
}
|
||||
|
||||
public String getRemarks() {
|
||||
return this.remarks;
|
||||
}
|
||||
|
||||
public void setRemarks(String remarks) {
|
||||
this.remarks=remarks;
|
||||
}
|
||||
|
||||
public String getTableType() {
|
||||
return tableType.name();
|
||||
}
|
||||
|
||||
public void setTableType(String tableType) {
|
||||
this.tableType = DBTableType.valueOf(tableType.toUpperCase());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,114 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
import com.weishao.dbswitch.core.model.ColumnDescription;
|
||||
import com.weishao.dbswitch.core.model.TableDescription;
|
||||
|
||||
/**
|
||||
* 元信息获取接口定义
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public interface IMetaDataService {
|
||||
|
||||
/**
|
||||
* 设置数据库连接的数据库类型
|
||||
*
|
||||
* @param dbtype 数据库类型
|
||||
*/
|
||||
public void setDatabaseConnection(DatabaseTypeEnum dbtype);
|
||||
|
||||
/**
|
||||
* 获取数据库的schema模式列表
|
||||
*
|
||||
* @param jdbcUrl 数据库连接的JDBC-URL
|
||||
* @param username 数据库连接的帐号
|
||||
* @param password 数据库连接的密码
|
||||
* @return
|
||||
*/
|
||||
public List<String> querySchemaList(String jdbcUrl, String username, String password);
|
||||
|
||||
/**
|
||||
* 获取指定Schema下所有的表列表
|
||||
*
|
||||
* @param jdbcUrl 数据库连接的JDBC-URL
|
||||
* @param username 数据库连接的帐号
|
||||
* @param password 数据库连接的密码
|
||||
* @param schemaName 模式名称
|
||||
* @return
|
||||
*/
|
||||
public List<TableDescription> queryTableList(String jdbcUrl, String username, String password, String schemaName);
|
||||
|
||||
/**
|
||||
* 获取指定schema.table的表结构字段信息
|
||||
*
|
||||
* @param jdbcUrl 数据库连接的JDBC-URL
|
||||
* @param username 数据库连接的帐号
|
||||
* @param password 数据库连接的密码
|
||||
* @param schemaName 模式名称
|
||||
* @param tableName 表或视图名称
|
||||
* @return
|
||||
*/
|
||||
public List<ColumnDescription> queryTableColumnMeta(String jdbcUrl, String username, String password,
|
||||
String schemaName, String tableName);
|
||||
|
||||
/**
|
||||
* 获取指定SQL结构字段信息
|
||||
*
|
||||
* @param jdbcUrl 数据库连接的JDBC-URL
|
||||
* @param username 数据库连接的帐号
|
||||
* @param password 数据库连接的密码
|
||||
* @param querySql 查询的SQL语句
|
||||
* @return
|
||||
*/
|
||||
public List<ColumnDescription> querySqlColumnMeta(String jdbcUrl, String username, String password,
|
||||
String querySql);
|
||||
|
||||
/**
|
||||
* 获取表的主键信息字段列表
|
||||
*
|
||||
* @param jdbcUrl 数据库连接的JDBC-URL
|
||||
* @param username 数据库连接的帐号
|
||||
* @param password 数据库连接的密码
|
||||
* @param schemaName Schema模式名称
|
||||
* @param tableName Table表名称
|
||||
* @return
|
||||
*/
|
||||
public List<String> queryTablePrimaryKeys(String jdbcUrl, String username, String password, String schemaName,
|
||||
String tableName);
|
||||
|
||||
/**
|
||||
* 测试数据库SQL查询
|
||||
*
|
||||
* @param jdbcUrl 数据库连接的JDBC-URL
|
||||
* @param username 数据库连接的帐号
|
||||
* @param password 数据库连接的密码
|
||||
* @param sql 待查询的SQL语句
|
||||
*/
|
||||
public void testQuerySQL(String jdbcUrl, String username, String password, String sql);
|
||||
|
||||
/**
|
||||
* 根据字段结构信息组装对应数据库的建表DDL语句
|
||||
*
|
||||
* @param type 目的数据库类型
|
||||
* @param fieldNames 字段结构信息
|
||||
* @param primaryKeys 主键字段信息
|
||||
* @param tableName 模式名称
|
||||
* @param tableName 表名称
|
||||
* @param autoIncr 是否允许主键自增
|
||||
* @return 对应数据库的DDL建表语句
|
||||
*/
|
||||
public String getDDLCreateTableSQL(DatabaseTypeEnum type, List<ColumnDescription> fieldNames, List<String> primaryKeys,
|
||||
String schemaName, String tableName, boolean autoIncr);
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
import com.weishao.dbswitch.core.model.ColumnDescription;
|
||||
import com.weishao.dbswitch.core.model.DatabaseDescription;
|
||||
import com.weishao.dbswitch.core.model.TableDescription;
|
||||
|
||||
/**
|
||||
* 表结构迁移接口定义
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public interface IMigrationService {
|
||||
|
||||
/**
|
||||
* 设置数据库的连接信息
|
||||
* @param databaseDesc 数据库的连接信息
|
||||
*/
|
||||
public void setDatabaseConnection(DatabaseDescription databaseDesc);
|
||||
|
||||
/**
|
||||
* 获取数据库的schema模式列表
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<String> querySchemaList();
|
||||
|
||||
/**
|
||||
* 获取指定Schema下所有的表列表
|
||||
*
|
||||
* @param schemaName 模式名称
|
||||
* @return
|
||||
*/
|
||||
public List<TableDescription> queryTableList(String schemaName);
|
||||
|
||||
/**
|
||||
* 获取指定schema.table的表结构字段信息
|
||||
*
|
||||
* @param schemaName 模式名称
|
||||
* @param tableName 表或视图名称
|
||||
* @return
|
||||
*/
|
||||
public List<ColumnDescription> queryTableColumnMeta(String schemaName, String tableName);
|
||||
|
||||
/**
|
||||
* 获取指定SQL结构字段信息
|
||||
*
|
||||
* @param querySql 查询的SQL语句
|
||||
* @return
|
||||
*/
|
||||
public List<ColumnDescription> querySqlColumnMeta(String querySql);
|
||||
|
||||
/**
|
||||
* 获取表的主键信息字段列表
|
||||
*
|
||||
* @param schemaName
|
||||
* @param tableName
|
||||
* @return
|
||||
*/
|
||||
public List<String> queryTablePrimaryKeys(String schemaName, String tableName);
|
||||
|
||||
/**
|
||||
* 测试数据库SQL查询
|
||||
* @param sql 待查询的SQL语句
|
||||
*/
|
||||
public void testQuerySQL(String sql);
|
||||
|
||||
/**
|
||||
* 根据字段结构信息组装对应数据库的建表DDL语句
|
||||
*
|
||||
* @param type 目的数据库类型
|
||||
* @param fieldNames 字段结构信息
|
||||
* @param primaryKeys 主键字段信息
|
||||
* @param tableName 模式名称
|
||||
* @param tableName 表名称
|
||||
* @param autoIncr 是否允许主键自增
|
||||
* @return 对应数据库的DDL建表语句
|
||||
*/
|
||||
public String getDDLCreateTableSQL(DatabaseTypeEnum type, List<ColumnDescription> fieldNames, List<String> primaryKeys,
|
||||
String schemaName, String tableName, boolean autoIncr);
|
||||
}
|
@@ -0,0 +1,132 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
import com.weishao.dbswitch.core.database.AbstractDatabase;
|
||||
import com.weishao.dbswitch.core.database.DatabaseFactory;
|
||||
import com.weishao.dbswitch.core.model.ColumnDescription;
|
||||
import com.weishao.dbswitch.core.model.DatabaseDescription;
|
||||
import com.weishao.dbswitch.core.model.TableDescription;
|
||||
import com.weishao.dbswitch.core.service.IMigrationService;
|
||||
import com.weishao.dbswitch.core.util.GenerateSqlUtils;
|
||||
import com.weishao.dbswitch.core.util.JdbcUrlUtils;
|
||||
|
||||
/**
|
||||
* 结构迁移转换实现类
|
||||
* 备注:字段信息、主键、生成建表的SQL语句
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class MigrationConvertServiceImpl implements IMigrationService {
|
||||
|
||||
private static int connectTimeOut=6;
|
||||
protected AbstractDatabase database=null;
|
||||
protected DatabaseDescription databaseDesc=null;
|
||||
|
||||
@Override
|
||||
public void setDatabaseConnection(DatabaseDescription databaseDesc) {
|
||||
this.database=DatabaseFactory.getDatabaseInstance(databaseDesc.getType());
|
||||
this.databaseDesc=databaseDesc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> querySchemaList() {
|
||||
String jdbcUrl=JdbcUrlUtils.getJdbcUrl(this.databaseDesc,MigrationConvertServiceImpl.connectTimeOut);
|
||||
String username=this.databaseDesc.getUsername();
|
||||
String password=this.databaseDesc.getPassword();
|
||||
|
||||
try {
|
||||
this.database.connect(jdbcUrl, username, password);
|
||||
return this.database.querySchemaList();
|
||||
}finally {
|
||||
this.database.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableDescription> queryTableList(String schemaName) {
|
||||
String jdbcUrl=JdbcUrlUtils.getJdbcUrl(this.databaseDesc,MigrationConvertServiceImpl.connectTimeOut);
|
||||
String username=this.databaseDesc.getUsername();
|
||||
String password=this.databaseDesc.getPassword();
|
||||
|
||||
try {
|
||||
this.database.connect(jdbcUrl, username, password);
|
||||
return this.database.queryTableList(schemaName);
|
||||
}finally {
|
||||
this.database.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnDescription> queryTableColumnMeta(String schemaName, String tableName) {
|
||||
String jdbcUrl=JdbcUrlUtils.getJdbcUrl(this.databaseDesc,MigrationConvertServiceImpl.connectTimeOut);
|
||||
String username=this.databaseDesc.getUsername();
|
||||
String password=this.databaseDesc.getPassword();
|
||||
|
||||
try {
|
||||
this.database.connect(jdbcUrl, username, password);
|
||||
return this.database.queryTableColumnMeta(schemaName, tableName);
|
||||
}finally {
|
||||
this.database.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnDescription> querySqlColumnMeta(String querySql){
|
||||
String jdbcUrl=JdbcUrlUtils.getJdbcUrl(this.databaseDesc,MigrationConvertServiceImpl.connectTimeOut);
|
||||
String username=this.databaseDesc.getUsername();
|
||||
String password=this.databaseDesc.getPassword();
|
||||
|
||||
try {
|
||||
this.database.connect(jdbcUrl, username, password);
|
||||
return this.database.querySelectSqlColumnMeta(querySql);
|
||||
}finally {
|
||||
this.database.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> queryTablePrimaryKeys(String schemaName, String tableName) {
|
||||
String jdbcUrl=JdbcUrlUtils.getJdbcUrl(this.databaseDesc,MigrationConvertServiceImpl.connectTimeOut);
|
||||
String username=this.databaseDesc.getUsername();
|
||||
String password=this.databaseDesc.getPassword();
|
||||
|
||||
try {
|
||||
this.database.connect(jdbcUrl, username, password);
|
||||
return this.database.queryTablePrimaryKeys(schemaName, tableName);
|
||||
}finally {
|
||||
this.database.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testQuerySQL(String sql) {
|
||||
String jdbcUrl=JdbcUrlUtils.getJdbcUrl(this.databaseDesc,MigrationConvertServiceImpl.connectTimeOut);
|
||||
String username=this.databaseDesc.getUsername();
|
||||
String password=this.databaseDesc.getPassword();
|
||||
|
||||
try {
|
||||
this.database.connect(jdbcUrl, username, password);
|
||||
this.database.testQuerySQL(sql);
|
||||
}finally {
|
||||
this.database.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDDLCreateTableSQL(DatabaseTypeEnum type, List<ColumnDescription> fieldNames, List<String> primaryKeys,
|
||||
String schemaName, String tableName, boolean autoIncr) {
|
||||
return GenerateSqlUtils.getDDLCreateTableSQL(type, fieldNames, primaryKeys, schemaName, tableName, autoIncr);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
import com.weishao.dbswitch.core.database.AbstractDatabase;
|
||||
import com.weishao.dbswitch.core.database.DatabaseFactory;
|
||||
import com.weishao.dbswitch.core.model.ColumnDescription;
|
||||
import com.weishao.dbswitch.core.model.TableDescription;
|
||||
import com.weishao.dbswitch.core.service.IMetaDataService;
|
||||
import com.weishao.dbswitch.core.util.GenerateSqlUtils;
|
||||
|
||||
/**
|
||||
* 元信息数据迁移实现类
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class MigrationMetaDataServiceImpl implements IMetaDataService {
|
||||
|
||||
protected AbstractDatabase database = null;
|
||||
|
||||
@Override
|
||||
public void setDatabaseConnection(DatabaseTypeEnum dbtype) {
|
||||
this.database = DatabaseFactory.getDatabaseInstance(dbtype);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> querySchemaList(String jdbcUrl, String username, String password) {
|
||||
AbstractDatabase db = Objects.requireNonNull(this.database, "Please call setDatabaseConnection() first!");
|
||||
try {
|
||||
db.connect(jdbcUrl, username, password);
|
||||
return db.querySchemaList();
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableDescription> queryTableList(String jdbcUrl, String username, String password, String schemaName) {
|
||||
AbstractDatabase db = Objects.requireNonNull(this.database, "Please call setDatabaseConnection() first!");
|
||||
try {
|
||||
db.connect(jdbcUrl, username, password);
|
||||
return db.queryTableList(schemaName);
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnDescription> queryTableColumnMeta(String jdbcUrl, String username, String password,
|
||||
String schemaName, String tableName) {
|
||||
AbstractDatabase db = Objects.requireNonNull(this.database, "Please call setDatabaseConnection() first!");
|
||||
try {
|
||||
db.connect(jdbcUrl, username, password);
|
||||
return db.queryTableColumnMeta(schemaName, tableName);
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnDescription> querySqlColumnMeta(String jdbcUrl, String username, String password,
|
||||
String querySql) {
|
||||
AbstractDatabase db = Objects.requireNonNull(this.database, "Please call setDatabaseConnection() first!");
|
||||
try {
|
||||
db.connect(jdbcUrl, username, password);
|
||||
return db.querySelectSqlColumnMeta(querySql);
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> queryTablePrimaryKeys(String jdbcUrl, String username, String password, String schemaName,
|
||||
String tableName) {
|
||||
AbstractDatabase db = Objects.requireNonNull(this.database, "Please call setDatabaseConnection() first!");
|
||||
try {
|
||||
db.connect(jdbcUrl, username, password);
|
||||
return db.queryTablePrimaryKeys(schemaName, tableName);
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testQuerySQL(String jdbcUrl, String username, String password, String sql) {
|
||||
AbstractDatabase db = Objects.requireNonNull(this.database, "Please call setDatabaseConnection() first!");
|
||||
try {
|
||||
db.connect(jdbcUrl, username, password);
|
||||
db.testQuerySQL(sql);
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDDLCreateTableSQL(DatabaseTypeEnum type, List<ColumnDescription> fieldNames, List<String> primaryKeys,
|
||||
String schemaName, String tableName, boolean autoIncr) {
|
||||
return GenerateSqlUtils.getDDLCreateTableSQL(type, fieldNames, primaryKeys, schemaName, tableName, autoIncr);
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.weishao.dbswitch.common.constant.DatabaseTypeEnum;
|
||||
import com.weishao.dbswitch.core.constant.Const;
|
||||
import com.weishao.dbswitch.core.database.AbstractDatabase;
|
||||
import com.weishao.dbswitch.core.database.DatabaseFactory;
|
||||
import com.weishao.dbswitch.core.model.ColumnDescription;
|
||||
import com.weishao.dbswitch.core.model.ColumnMetaData;
|
||||
|
||||
/**
|
||||
* 拼接SQL工具类
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class GenerateSqlUtils {
|
||||
|
||||
public static String getDDLCreateTableSQL(DatabaseTypeEnum type, List<ColumnDescription> fieldNames,
|
||||
List<String> primaryKeys, String schemaName, String tableName, boolean autoIncr) {
|
||||
StringBuilder retval = new StringBuilder();
|
||||
List<String> pks = fieldNames.stream().filter((cd) -> primaryKeys.contains(cd.getFieldName()))
|
||||
.map((cd) -> cd.getFieldName()).collect(Collectors.toList());
|
||||
|
||||
AbstractDatabase db = DatabaseFactory.getDatabaseInstance(type);
|
||||
|
||||
retval.append(Const.CREATE_TABLE);
|
||||
// if(ifNotExist && type!=DatabaseType.ORACLE) {
|
||||
// retval.append( Const.IF_NOT_EXISTS );
|
||||
// }
|
||||
retval.append(db.getQuotedSchemaTableCombination(schemaName, tableName) + Const.CR);
|
||||
retval.append("(").append(Const.CR);
|
||||
|
||||
for (int i = 0; i < fieldNames.size(); i++) {
|
||||
if (i > 0) {
|
||||
retval.append(", ");
|
||||
} else {
|
||||
retval.append(" ");
|
||||
}
|
||||
|
||||
ColumnMetaData v = fieldNames.get(i).getMetaData();
|
||||
retval.append(db.getFieldDefinition(v, pks, autoIncr, true));
|
||||
}
|
||||
|
||||
if (!pks.isEmpty()) {
|
||||
String pk = db.getPrimaryKeyAsString(pks);
|
||||
retval.append(", PRIMARY KEY (").append(pk).append(")").append(Const.CR);
|
||||
}
|
||||
|
||||
retval.append(")").append(Const.CR);
|
||||
return db.formatSQL(retval.toString());
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.util;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
/**
|
||||
* JDBC操作封装工具类
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public final class JdbcOperatorUtils {
|
||||
|
||||
public static void closeConnection(Connection con) {
|
||||
if (con != null) {
|
||||
try {
|
||||
con.close();
|
||||
} catch (SQLException ex) {
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void closeStatement(Statement stmt) {
|
||||
if (stmt != null) {
|
||||
try {
|
||||
stmt.close();
|
||||
} catch (SQLException ex) {
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void closeResultSet(ResultSet rs) {
|
||||
if (rs != null) {
|
||||
try {
|
||||
rs.close();
|
||||
} catch (SQLException ex) {
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JdbcOperatorUtils() {
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,180 @@
|
||||
// Copyright tang. All rights reserved.
|
||||
// https://gitee.com/inrgihc/dbswitch
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
//
|
||||
// Author: tang (inrgihc@126.com)
|
||||
// Data : 2020/1/2
|
||||
// Location: beijing , china
|
||||
/////////////////////////////////////////////////////////////
|
||||
package com.weishao.dbswitch.core.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import com.weishao.dbswitch.core.model.DatabaseDescription;
|
||||
|
||||
/**
|
||||
* JDBC的URL相关工具类
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
public class JdbcUrlUtils {
|
||||
|
||||
private static Pattern patternWithParam = Pattern
|
||||
.compile("(?<protocol>^.+):(?<dbtype>.+)://(?<addresss>.+):(?<port>.+)/(?<schema>.+)\\?(?<path>.+)");
|
||||
|
||||
private static Pattern patternSimple = Pattern
|
||||
.compile("(?<protocol>^.+):(?<dbtype>.+)://(?<addresss>.+):(?<port>.+)/(?<schema>.+)");
|
||||
|
||||
/**
|
||||
* Oracle数据库Jdbc连接模式
|
||||
*
|
||||
* @author tang
|
||||
*
|
||||
*/
|
||||
protected enum OracleJdbcConnectionMode {
|
||||
/**
|
||||
* SID
|
||||
*/
|
||||
SID(1),
|
||||
|
||||
/**
|
||||
* SerivceName
|
||||
*/
|
||||
SERVICENAME(2),
|
||||
|
||||
/**
|
||||
* TNSName
|
||||
*/
|
||||
TNSNAME(3);
|
||||
|
||||
private int index;
|
||||
|
||||
OracleJdbcConnectionMode(int idx) {
|
||||
this.index = idx;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据库种类拼接jdbc的url信息 参考地址:https://www.cnblogs.com/chenglc/p/8421573.html 说明:
|
||||
* (1)SQLServer数据库驱动问题 在SQL Server 2000 中加载驱动和URL路径的语句是 String driverName =
|
||||
* "com.microsoft.jdbc.sqlserver.SQLServerDriver"; String dbURL =
|
||||
* "jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=sample"; 而SQL Server
|
||||
* 2005和SQL Server 2008 中加载驱动和URL的语句则为 String driverName =
|
||||
* "com.microsoft.sqlserver.jdbc.SQLServerDriver"; String dbURL =
|
||||
* "jdbc:sqlserver://localhost:1433; DatabaseName=sample"; (2)Oracle数据库驱动连接问题
|
||||
* JDBC的URL三种方式:https://blog.csdn.net/gnail_oug/article/details/80075263
|
||||
*
|
||||
* @param db 数据库连接描述信息
|
||||
* @param connectTimeout 连接超时时间(单位:秒)
|
||||
* @param mode 对于Oracle数据库的模式,可取范围为:sid,servicename,tnsname三种
|
||||
* @return 对应数据库的JDBC的URL字符串
|
||||
*
|
||||
*/
|
||||
public static String getJdbcUrl(DatabaseDescription db, int connectTimeout) {
|
||||
switch (db.getType()) {
|
||||
case MYSQL:
|
||||
String charset = db.getCharset();
|
||||
if (Objects.isNull(charset) || charset.isEmpty()) {
|
||||
charset = "utf-8";
|
||||
}
|
||||
return String.format(
|
||||
"jdbc:mysql://%s:%d/%s?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=%s&nullCatalogMeansCurrent=true&connectTimeout=%d",
|
||||
db.getHost(), db.getPort(), db.getDbname(), charset, connectTimeout * 1000);
|
||||
case ORACLE:
|
||||
OracleJdbcConnectionMode type;
|
||||
String mode = db.getMode();
|
||||
if (Objects.isNull(mode)) {
|
||||
type = OracleJdbcConnectionMode.SID;
|
||||
} else {
|
||||
try {
|
||||
type = OracleJdbcConnectionMode.valueOf(mode.trim().toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(String.format("Invalid Oracle mode type: %s", mode));
|
||||
}
|
||||
}
|
||||
|
||||
// 处理Oracle的oracle.sql.TIMESTAMP类型到java.sql.Timestamp的兼容问题
|
||||
// 参考地址:https://blog.csdn.net/alanwei04/article/details/77507807
|
||||
System.setProperty("oracle.jdbc.J2EE13Compliant", "true");
|
||||
// Oracle设置连接超时时间
|
||||
System.setProperty("oracle.net.CONNECT_TIMEOUT", Integer.toString(1000 * connectTimeout));
|
||||
if (OracleJdbcConnectionMode.SID == type) {
|
||||
return String.format("jdbc:oracle:thin:@%s:%d:%s", db.getHost(), db.getPort(), db.getDbname());
|
||||
} else if (OracleJdbcConnectionMode.SERVICENAME == type) {
|
||||
return String.format("jdbc:oracle:thin:@//%s:%d/%s", db.getHost(), db.getPort(), db.getDbname());
|
||||
} else if (OracleJdbcConnectionMode.TNSNAME == type) {
|
||||
//
|
||||
// return String.format(
|
||||
// "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=%s)(PORT=%d)))
|
||||
// "
|
||||
// + "(CONNECT_DATA=(SERVICE_NAME=%s)))",
|
||||
/// db.getHost(), db.getPort(), db.getDbname());
|
||||
//
|
||||
// (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=172.17.207.158)(PORT=1521)))(CONNECT_DATA=(SID=orcl)))
|
||||
//
|
||||
// or
|
||||
//
|
||||
// (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=172.17.207.158)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=orcl.ruijie.com.cn)))
|
||||
return String.format("jdbc:oracle:thin:@%s", db.getDbname());
|
||||
} else {
|
||||
return String.format("jdbc:oracle:thin:@%s:%d:%s", db.getHost(), db.getPort(), db.getDbname());
|
||||
}
|
||||
case SQLSERVER2000:
|
||||
return String.format("jdbc:microsoft:sqlserver://%s:%d;DatabaseName=%s", db.getHost(), db.getPort(),
|
||||
db.getDbname());
|
||||
case SQLSERVER:
|
||||
return String.format("jdbc:sqlserver://%s:%d;DatabaseName=%s", db.getHost(), db.getPort(), db.getDbname());
|
||||
case POSTGRESQL:
|
||||
return String.format("jdbc:postgresql://%s:%d/%s?connectTimeout=%d", db.getHost(), db.getPort(),
|
||||
db.getDbname(), connectTimeout);
|
||||
case GREENPLUM:
|
||||
return String.format("jdbc:pivotal:greenplum://%s:%d;DatabaseName=%s", db.getHost(), db.getPort(),
|
||||
db.getDbname());
|
||||
default:
|
||||
throw new RuntimeException(String.format("Unkown database type (%s)", db.getType().name()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从MySQL数据库的JDBC的URL中提取数据库连接相关参数
|
||||
*
|
||||
* @param jdbcUrl JDBC连接的URL字符串
|
||||
* @return Map 参数列表
|
||||
*/
|
||||
public static Map<String, String> findParamsByMySqlJdbcUrl(String jdbcUrl) {
|
||||
Pattern pattern = null;
|
||||
if (jdbcUrl.indexOf('?') > 0) {
|
||||
pattern = patternWithParam;
|
||||
} else {
|
||||
pattern = patternSimple;
|
||||
}
|
||||
|
||||
Matcher m = pattern.matcher(jdbcUrl);
|
||||
if (m.find()) {
|
||||
Map<String, String> ret = new HashMap<String, String>();
|
||||
ret.put("protocol", m.group("protocol"));
|
||||
ret.put("dbtype", m.group("dbtype"));
|
||||
ret.put("addresss", m.group("addresss"));
|
||||
ret.put("port", m.group("port"));
|
||||
ret.put("schema", m.group("schema"));
|
||||
|
||||
if (m.groupCount() > 5) {
|
||||
ret.put("path", m.group("path"));
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user