sqlserver->mysql建表语句转换

升级druid版本到最新1.2.14
处理冗余代码
This commit is contained in:
diantu
2023-02-03 17:51:42 +08:00
parent 584fa48d0d
commit 848ce44b34
14 changed files with 355 additions and 66 deletions

View File

@@ -143,7 +143,7 @@
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>

View File

@@ -26,6 +26,56 @@
select #{tableName} as name
</select>
<select id="getTableDdl" resultType="java.util.Map">
select 'create table [' + so.name + '] (' + o.list + ')' + CASE
WHEN tc.Constraint_Name IS NULL THEN ''
ELSE 'ALTER TABLE ' + so.Name +
' ADD CONSTRAINT ' + tc.Constraint_Name +
' PRIMARY KEY ' +
' (' + LEFT(j.List, Len(j.List)-1) + ')' END
from sysobjects so
cross apply
(SELECT
' ['+ column_name +'] ' +
data_type + case data_type
when 'sql_variant' then ''
when 'text' then ''
when 'ntext' then ''
when 'xml' then ''
when 'image' then ''
when 'decimal' then '(' + cast (numeric_precision as varchar) + ', ' + cast (numeric_scale as varchar) + ')'
else coalesce ('('+ case when character_maximum_length = -1 then 'MAX' else cast (character_maximum_length as varchar) end +')', '') end + ' ' +
case when exists (
select id from syscolumns
where object_name(id)=so.name
and name = column_name
and columnproperty(id, name, 'IsIdentity') = 1
) then
'IDENTITY(' +
cast (ident_seed(so.name) as varchar) + ',' +
cast (ident_incr(so.name) as varchar) + ')'
else ''
end + ' ' +
(case when IS_NULLABLE = 'No' then 'NOT ' else '' end ) + 'NULL ' +
case when information_schema.columns.COLUMN_DEFAULT IS NOT NULL THEN 'DEFAULT '+ information_schema.columns.COLUMN_DEFAULT ELSE '' END + ', '
from information_schema.columns where table_name = so.name
order by ordinal_position
FOR XML PATH ('')) o (list)
left join
information_schema.table_constraints tc
on tc.Table_name = so.Name
AND tc.Constraint_Type = 'PRIMARY KEY'
cross apply
(select '[' + Column_Name + '], '
FROM information_schema.key_column_usage kcu
WHERE kcu.Constraint_Name = tc.Constraint_Name
ORDER BY
ORDINAL_POSITION
FOR XML PATH ('')) j (list)
where xtype = 'U'
AND name = '${tableName}'
</select>
<select id="getTableList" resultType="com.zyplayer.doc.db.framework.db.dto.TableInfoDto">
SELECT NAME as tableName, ID as tableId
FROM ${dbName}..SysObjects Where XType='U' ORDER BY NAME

View File

@@ -1,9 +1,7 @@
package com.zyplayer.doc.db.framework.db.sql.dialect.mysql;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
@@ -21,8 +19,8 @@ import com.alibaba.druid.sql.parser.SQLParserUtils;
import com.alibaba.druid.util.FnvHash;
import com.zyplayer.doc.db.framework.db.sql.dialect.mysql.function.MySqlToOracleFunctionTransform;
import com.zyplayer.doc.db.framework.db.sql.dialect.mysql.util.MySqlSQLDataTypeTransformUtil;
import com.zyplayer.doc.db.framework.db.sql.dialect.oracle.function.OracleUtil;
import com.zyplayer.doc.db.framework.utils.MapCacheUtil;
import com.zyplayer.doc.db.framework.utils.SQLTransformUtils;
import java.util.List;
import java.util.Objects;
@@ -67,7 +65,7 @@ public class MySqlToOracleOutputVisitor extends MySqlOutputVisitor {
String columnName = sqlColumnDefinition.getName().getSimpleName().replaceAll("\"", "");
columnName = columnName.replaceAll("`", "");
sqlColumnDefinition.setName(columnName);
if(OracleUtil.containsKeyWords(columnName)){
if(SQLTransformUtils.containsKeyWords(columnName,DbType.oracle)){
sqlColumnDefinition.setName("\""+columnName+"\"");
}
sqlColumnDefinition.setDataType(MySqlSQLDataTypeTransformUtil.transformMySqlToOracle(SQLParserUtils.createExprParser(sqlColumnDefinition.getDataType().toString(), DbType.mysql).parseDataType()));

View File

@@ -1,26 +0,0 @@
package com.zyplayer.doc.db.framework.db.sql.dialect.mysql.util;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlLexer;
import org.springframework.util.StringUtils;
/**
* mysql sql语句相关工具类
*
* @author diantu
* @since 2023年1月29日
*/
public class MySqlUtil {
/**
* 是否包含关键词
* @param name
* @return
*/
public static boolean containsKeyWords(String name) {
if (StringUtils.isEmpty(name)) {
return false;
}
return MySqlLexer.DEFAULT_MYSQL_KEYWORDS.getKeywords().containsKey(name.toUpperCase());
}
}

View File

@@ -17,10 +17,10 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUnique;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleOutputVisitor;
import com.alibaba.druid.sql.parser.SQLParserUtils;
import com.alibaba.druid.util.FnvHash;
import com.zyplayer.doc.db.framework.db.sql.dialect.mysql.util.MySqlUtil;
import com.zyplayer.doc.db.framework.db.sql.dialect.oracle.function.OracleToMySqlFunctionTransform;
import com.zyplayer.doc.db.framework.db.sql.dialect.oracle.util.OracleSQLDataTypeTransformUtil;
import com.zyplayer.doc.db.framework.utils.MapCacheUtil;
import com.zyplayer.doc.db.framework.utils.SQLTransformUtils;
import java.util.List;
import java.util.Objects;
@@ -62,7 +62,7 @@ public class OracleToMySqlOutputVisitor extends OracleOutputVisitor {
SQLColumnDefinition sqlColumnDefinition = ((SQLColumnDefinition)sqlTableElement);
String columnName = sqlColumnDefinition.getName().getSimpleName().replaceAll("\"", "");
sqlColumnDefinition.setName(columnName);
if(MySqlUtil.containsKeyWords(columnName)){
if(SQLTransformUtils.containsKeyWords(columnName,DbType.mysql)){
sqlColumnDefinition.setName("`"+columnName+"`");
}
sqlColumnDefinition.setDataType(OracleSQLDataTypeTransformUtil.transformOracleToMySql(SQLParserUtils.createExprParser(sqlColumnDefinition.getDataType().toString(), DbType.oracle).parseDataType()));

View File

@@ -1,25 +0,0 @@
package com.zyplayer.doc.db.framework.db.sql.dialect.oracle.function;
import com.alibaba.druid.sql.dialect.oracle.parser.OracleLexer;
import org.springframework.util.StringUtils;
/**
* oracle sql语句相关工具类
*
* @author diantu
* @since 2023年1月30日
*/
public class OracleUtil {
/**
* 是否包含关键词
* @param name
* @return
*/
public static boolean containsKeyWords(String name) {
if (StringUtils.isEmpty(name)) {
return false;
}
return OracleLexer.DEFAULT_ORACLE_KEYWORDS.getKeywords().containsKey(name.toUpperCase());
}
}

View File

@@ -235,14 +235,8 @@ public class OracleSQLDataTypeTransformUtil extends SQLTransformUtils {
}
}
/*if (len >= 0) {
if (len > 6) {
len = 6;
}
dataType = new SQLDataTypeImpl("datetime", len);
} else {*/
dataType = new SQLDataTypeImpl("datetime");
/* }*/
} else if (nameHash == FnvHash.Constants.BLOB
|| nameHash == FnvHash.Constants.LONG_RAW) {
argumentns.clear();

View File

@@ -0,0 +1,130 @@
package com.zyplayer.doc.db.framework.db.sql.dialect.sqlserver;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLIndexDefinition;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerOutputVisitor;
import com.alibaba.druid.sql.parser.SQLParserUtils;
import com.alibaba.druid.util.FnvHash;
import com.zyplayer.doc.db.framework.db.sql.dialect.sqlserver.function.SqlServerToMySqlFunctionTransform;
import com.zyplayer.doc.db.framework.db.sql.dialect.sqlserver.util.SqlServerSQLDataTypeTransformUtil;
import com.zyplayer.doc.db.framework.utils.MapCacheUtil;
import com.zyplayer.doc.db.framework.utils.SQLTransformUtils;
import java.util.List;
import java.util.Objects;
/**
* sqlserver转mysql遍历实现
*
* @author diantu
* @since 2023年2月2日
*/
public class SqlServerToMySqlOutputVisitor extends SQLServerOutputVisitor {
// 目标数据库类型
private final DbType distDbType = DbType.mysql;
private final SqlServerToMySqlFunctionTransform functionTransform = new SqlServerToMySqlFunctionTransform();
public SqlServerToMySqlOutputVisitor(Appendable appender) {
super(appender);
}
public SqlServerToMySqlOutputVisitor(Appendable appender, boolean printPostSemi) {
super(appender, printPostSemi);
}
/**
* sqlserver建表语句遍历
* @param x
* @return
*/
@Override
public boolean visit(SQLCreateTableStatement x) {
MySqlCreateTableStatement mySqlCreateTableStatement = new MySqlCreateTableStatement();
mySqlCreateTableStatement.setTableSource(x.getTableSource());
String tableName = x.getTableSource().getName().getSimpleName();
String name = String.valueOf(x.getName()).replaceAll("\"", "");
name = name.replaceAll("\\[", "").replaceAll("\\]", "");
mySqlCreateTableStatement.setName(name);
for(SQLTableElement sqlTableElement : x.getTableElementList()){
if( sqlTableElement instanceof SQLColumnDefinition) {
SQLColumnDefinition sqlColumnDefinition = ((SQLColumnDefinition)sqlTableElement);
String columnName = sqlColumnDefinition.getName().getSimpleName().replaceAll("\"", "");
columnName = columnName.replaceAll("\\[", "").replaceAll("\\]", "");
sqlColumnDefinition.setName(columnName);
if(SQLTransformUtils.containsKeyWords(columnName,DbType.mysql)){
sqlColumnDefinition.setName("`"+columnName+"`");
}
sqlColumnDefinition.setDataType(SqlServerSQLDataTypeTransformUtil.transformSqlServerToMySql(SQLParserUtils.createExprParser(sqlColumnDefinition.getDataType().toString(), DbType.oracle).parseDataType()));
if(sqlColumnDefinition.getDefaultExpr() != null) {
SQLExpr expr = sqlColumnDefinition.getDefaultExpr();
if(expr instanceof SQLMethodInvokeExpr) {
SQLMethodInvokeExpr sqlMethodInvokeExpr = (SQLMethodInvokeExpr) expr;
final long nameHashCode64 = sqlMethodInvokeExpr.methodNameHashCode64();
//mysql默认值只能为常量
if (nameHashCode64 == FnvHash.Constants.IDENTITY) {
SQLIdentifierExpr xx = new SQLIdentifierExpr("AUTO_INCREMENT");
xx.setParent(expr.getParent());
sqlColumnDefinition.setDefaultExpr(xx);
}else {
functionTransform.methodInvoke((SQLMethodInvokeExpr) sqlColumnDefinition.getDefaultExpr());
}
}
}
sqlColumnDefinition.setDbType(distDbType);
MapCacheUtil.getInstance().addCacheData(tableName.toUpperCase() + ":" + columnName.toUpperCase(), sqlColumnDefinition.toString().replaceAll(sqlColumnDefinition.getColumnName(), ""));
mySqlCreateTableStatement.getTableElementList().add(sqlColumnDefinition);
}
}
if(Objects.nonNull(x.getSelect())){
x.setParent(mySqlCreateTableStatement);
mySqlCreateTableStatement.setSelect(x.getSelect());
}
println();
print(mySqlCreateTableStatement.toString());
println(";");
return false;
}
/**
* sqlserver修改语句遍历
* @param x
* @return
*/
@Override
public boolean visit(SQLAlterTableStatement x) {
for (SQLAlterTableItem item : x.getItems()) {
if(item instanceof SQLAlterTableRename) {
((SQLAlterTableStatement) item.getParent()).setDbType(distDbType);
String rename = "";
if(x.isAfterSemi()) {
rename = x.toString().substring(0, x.toString().length() - 1);
} else {
rename = x.toString();
}
println();
print0(rename);
return false;
}
if(item instanceof SQLAlterTableAddConstraint) {
((SQLAlterTableStatement) item.getParent()).setDbType(distDbType);
SQLPrimaryKeyImpl sQLPrimaryKeyImpl = (SQLPrimaryKeyImpl) ((SQLAlterTableAddConstraint) item).getConstraint();
SQLIndexDefinition sQLIndexDefinition = sQLPrimaryKeyImpl.getIndexDefinition();
List<SQLSelectOrderByItem> list = sQLIndexDefinition.getColumns();
for(int i=0;i<list.size();i++){
SQLIdentifierExpr sQLIdentifierExpr = (SQLIdentifierExpr)list.get(i).getExpr();
sQLIdentifierExpr.setName(sQLIdentifierExpr.getName().replaceAll("\\[", "").replaceAll("\\]", ""));
}
}
}
return super.visit(x);
}
}

View File

@@ -0,0 +1,13 @@
package com.zyplayer.doc.db.framework.db.sql.dialect.sqlserver.function;
import com.zyplayer.doc.db.framework.db.sql.MethodInvoke;
/**
* sqlserver2mysql需要转换的函数
*
* @author diantu
* @since 2023年2月2日
*/
public interface SqlServerFunction extends MethodInvoke{
}

View File

@@ -0,0 +1,11 @@
package com.zyplayer.doc.db.framework.db.sql.dialect.sqlserver.function;
/**
* sqlserver2mysql需要转换的函数实现
*
* @author diantu
* @since 2023年2月2日
*/
public class SqlServerToMySqlFunctionTransform implements SqlServerFunction {
}

View File

@@ -0,0 +1,58 @@
package com.zyplayer.doc.db.framework.db.sql.dialect.sqlserver.util;
import com.alibaba.druid.sql.SQLTransformUtils;
import com.alibaba.druid.sql.ast.SQLDataType;
import com.alibaba.druid.sql.ast.SQLDataTypeImpl;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.util.FnvHash;
import java.util.List;
/**
* sqlserver sql转换工具类
*
* @author diantu
* @since 2023年2月2日
*/
public class SqlServerSQLDataTypeTransformUtil extends SQLTransformUtils {
public static SQLDataType transformSqlServerToMySql(SQLDataType x) {
final String name = x.getName();
final long nameHash = x.nameHashCode64();
if (name == null) {
return x;
}
List<SQLExpr> argumentns = x.getArguments();
SQLDataType dataType;
if (nameHash == FnvHash.Constants.SMALLINT) {
int precision = 0;
if (argumentns.size() > 0) {
precision = ((SQLIntegerExpr) argumentns.get(0)).getNumber().intValue();
}
dataType = new SQLDataTypeImpl("int", precision);
} else if (nameHash == FnvHash.Constants.TIME) {
dataType = new SQLDataTypeImpl("datetime");
} else if (nameHash == FnvHash.Constants.TEXT) {
dataType = new SQLDataTypeImpl("MEDIUMTEXT");
} else if(nameHash == FnvHash.Constants.NVARCHAR){
int precision = 0;
if (argumentns.size() > 0) {
precision = ((SQLIntegerExpr) argumentns.get(0)).getNumber().intValue();
}
dataType = new SQLDataTypeImpl("varchar", precision);
} else {
dataType = x;
}
if (dataType != x) {
dataType.setParent(x.getParent());
}
return dataType;
}
}

View File

@@ -3,8 +3,15 @@ package com.zyplayer.doc.db.framework.utils;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlLexer;
import com.alibaba.druid.sql.dialect.oracle.parser.OracleLexer;
import com.alibaba.druid.sql.dialect.sqlserver.parser.SQLServerLexer;
import com.alibaba.druid.sql.parser.Keywords;
import com.alibaba.druid.sql.parser.Lexer;
import com.zyplayer.doc.db.framework.db.sql.dialect.mysql.MySqlToOracleOutputVisitor;
import com.zyplayer.doc.db.framework.db.sql.dialect.oracle.OracleToMySqlOutputVisitor;
import com.zyplayer.doc.db.framework.db.sql.dialect.sqlserver.SqlServerToMySqlOutputVisitor;
import org.springframework.util.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
@@ -38,6 +45,24 @@ public class SQLTransformUtils {
return mysqlSql;
}
/**
* sqlserver sql语句转换为mysql sql语句
* @param sql
* @return
*/
public static String translateSqlServerToMySql(String sql) {
List<SQLStatement> stmtList = SQLUtils.toStatementList(sql, DbType.sqlserver);
StringBuilder out = new StringBuilder();
SqlServerToMySqlOutputVisitor visitor = new SqlServerToMySqlOutputVisitor(out, false);
for(int i = 0; i < stmtList.size(); ++i) {
((SQLStatement)stmtList.get(i)).accept(visitor);
}
String mysqlSql = out.toString();
return mysqlSql;
}
/**
* mysql sql语句转换为oracle sql语句
* @param sql
@@ -79,4 +104,26 @@ public class SQLTransformUtils {
reString = sb.toString();
return reString;
}
/**
* 是否包含关键词
* @param name 字段名
* @param dbType 数据库类型
* @return
*/
public static boolean containsKeyWords(String name,DbType dbType) {
if (StringUtils.isEmpty(name)) {
return false;
}
if(dbType == DbType.mysql){
return MySqlLexer.DEFAULT_MYSQL_KEYWORDS.getKeywords().containsKey(name.toUpperCase());
}else if(dbType == DbType.oracle){
return OracleLexer.DEFAULT_ORACLE_KEYWORDS.getKeywords().containsKey(name.toUpperCase());
}else if(dbType == DbType.sqlserver){
return SQLServerLexer.DEFAULT_SQL_SERVER_KEYWORDS.getKeywords().containsKey(name.toUpperCase());
}else if(dbType == DbType.dm){
return Keywords.DM_KEYWORDS.getKeywords().containsKey(name.toUpperCase());
}
return Keywords.DEFAULT_KEYWORDS.getKeywords().containsKey(name.toUpperCase());
}
}

View File

@@ -74,7 +74,7 @@ public class OracleServiceImpl extends DbBaseService {
BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId);
List<Map<String, Object>> tableDdlList = baseMapper.getTableDdl(dbName, tableName);
TableDdlVo tableDdlVo = new TableDdlVo();
tableDdlVo.setCurrent(DatabaseProductEnum.MYSQL.name().toLowerCase());
tableDdlVo.setCurrent(DatabaseProductEnum.ORACLE.name().toLowerCase());
if (CollectionUtils.isNotEmpty(tableDdlList)) {
String oracleSql = "";
try {

View File

@@ -2,14 +2,21 @@ package com.zyplayer.doc.db.service.database;
import com.zyplayer.doc.db.controller.param.DataViewParam;
import com.zyplayer.doc.db.controller.vo.TableColumnVo;
import com.zyplayer.doc.db.controller.vo.TableDdlVo;
import com.zyplayer.doc.db.framework.db.dto.TableColumnDescDto;
import com.zyplayer.doc.db.framework.db.enums.DatabaseProductEnum;
import com.zyplayer.doc.db.framework.db.mapper.base.BaseMapper;
import com.zyplayer.doc.db.framework.db.mapper.sqlserver.SqlServerMapper;
import com.zyplayer.doc.db.framework.utils.SQLTransformUtils;
import com.zyplayer.doc.db.service.download.SqlserverDownloadService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.sql.Clob;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -123,4 +130,36 @@ public class SqlserverServiceImpl extends DbBaseService {
}
return sqlSb.toString();
}
/**
* 获取建表语句
*
* @author diantu
* @since 2023年2月2日
*/
@Override
public TableDdlVo getTableDdl(Long sourceId, String dbName, String tableName) {
BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId);
List<Map<String, Object>> tableDdlList = baseMapper.getTableDdl(dbName, tableName);
TableDdlVo tableDdlVo = new TableDdlVo();
tableDdlVo.setCurrent(DatabaseProductEnum.SQLSERVER.name().toLowerCase());
if (CollectionUtils.isNotEmpty(tableDdlList)) {
String sqlserverSql = "";
try {
sqlserverSql = SQLTransformUtils.ClobToString((Clob)tableDdlList.get(0).get(""));
} catch (SQLException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
//String sqlserverSql = (String) tableDdlList.get(0).get("");
tableDdlVo.setSqlserver(sqlserverSql);
// tableDdlVo.setOracle(oracleSql);
//oracle建表语句转换为mysql建表语句
String mysqlSql = SQLTransformUtils.translateSqlServerToMySql(sqlserverSql);
tableDdlVo.setMysql(mysqlSql);
// TODO 其他数据库同理
}
return tableDdlVo;
}
}