代码提交

This commit is contained in:
inrgihc
2020-08-31 00:11:24 +08:00
commit 1f2565d40e
215 changed files with 20016 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

89
dbswitch-core/pom.xml Normal file
View 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>

View File

@@ -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() {
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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() {
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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 "";
}
}

View File

@@ -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数据库的元信息实现
* 备注:
* 1Oracle12c安装教程
* 官方安装版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();
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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 "";
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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
+ "]";
}
}

View File

@@ -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());
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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() {
}
}

View File

@@ -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 说明:
* 1SQLServer数据库驱动问题 在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"; 2Oracle数据库驱动连接问题
* 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;
}
}
}