mysql->oracle建表语句转换

This commit is contained in:
diantu
2023-01-31 15:33:23 +08:00
parent b2740605b0
commit 683585c527
6 changed files with 271 additions and 5 deletions

View File

@@ -1,6 +1,31 @@
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;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.ast.statement.SQLTableElement;
import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey;
import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUnique;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleSysdateExpr;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateTableStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OraclePrimaryKey;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUnique;
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 java.util.List;
import java.util.Objects;
/**
* mysql转oracle遍历实现
@@ -10,6 +35,11 @@ import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
*/
public class MySqlToOracleOutputVisitor extends MySqlOutputVisitor {
private final MySqlToOracleFunctionTransform functionTransform = new MySqlToOracleFunctionTransform();
// 目标数据库类型
private final DbType distDbType = DbType.oracle;
public MySqlToOracleOutputVisitor(Appendable appender) {
super(appender);
}
@@ -18,5 +48,93 @@ public class MySqlToOracleOutputVisitor extends MySqlOutputVisitor {
super(appender, parameterized);
}
/**
* mysql建表语句遍历
* @param x
* @return
*/
@Override
public boolean visit(MySqlCreateTableStatement x) {
OracleCreateTableStatement oracleCreateTableStatement = new OracleCreateTableStatement();
oracleCreateTableStatement.setTableSource(x.getTableSource());
String tableName = x.getTableSource().getName().getSimpleName();
oracleCreateTableStatement.setName(String.valueOf(x.getName()).replaceAll("\"", ""));
oracleCreateTableStatement.setName(String.valueOf(x.getName()).replaceAll("`", ""));
oracleCreateTableStatement.setComment(x.getComment());
for(SQLTableElement sqlTableElement : x.getTableElementList()){
if( sqlTableElement instanceof SQLColumnDefinition) {
SQLColumnDefinition sqlColumnDefinition = ((SQLColumnDefinition)sqlTableElement);
String columnName = sqlColumnDefinition.getName().getSimpleName().replaceAll("\"", "");
columnName = columnName.replaceAll("`", "");
sqlColumnDefinition.setName(columnName);
if(OracleUtil.containsKeyWords(columnName)){
sqlColumnDefinition.setName("\""+columnName+"\"");
}
sqlColumnDefinition.setDataType(MySqlSQLDataTypeTransformUtil.transformMySqlToOracle(SQLParserUtils.createExprParser(sqlColumnDefinition.getDataType().toString(), DbType.mysql).parseDataType()));
if(sqlColumnDefinition.getDefaultExpr() != null) {
SQLExpr expr = sqlColumnDefinition.getDefaultExpr();
if(expr instanceof SQLMethodInvokeExpr) {
functionTransform.methodInvoke((SQLMethodInvokeExpr) sqlColumnDefinition.getDefaultExpr());
}else if(expr instanceof SQLIdentifierExpr) {
SQLIdentifierExpr sqlIdentifierExpr = (SQLIdentifierExpr) expr;
final long nameHashCode64 = sqlIdentifierExpr.nameHashCode64();
if(nameHashCode64 == FnvHash.Constants.SYSTIMESTAMP) {
SQLIdentifierExpr xx = sqlIdentifierExpr.clone();
xx.setName("CURRENT_TIMESTAMP");
xx.setParent(sqlIdentifierExpr.getParent());
sqlColumnDefinition.setDefaultExpr(xx);
if(sqlColumnDefinition.getColumnName().contains("UPDATE_TIME")
|| sqlColumnDefinition.getColumnName().contains("MDFY_TIME")) {
sqlColumnDefinition.setOnUpdate(xx);
}
}
}else if(expr instanceof OracleSysdateExpr) {
SQLIdentifierExpr xx = new SQLIdentifierExpr("CURRENT_TIMESTAMP");
xx.setParent(expr.getParent());
sqlColumnDefinition.setDefaultExpr(xx);
if(sqlColumnDefinition.getColumnName().contains("UPDATE_TIME")
|| sqlColumnDefinition.getColumnName().contains("MDFY_TIME")) {
sqlColumnDefinition.setOnUpdate(xx);
}
}
}
//@TODO 自增转换(oracle没有AUTO_INCREMENT)
if(sqlColumnDefinition.isAutoIncrement()){
sqlColumnDefinition.setAutoIncrement(false);
//SQLIdentifierExpr xx = new SQLIdentifierExpr("sys_guid()");
//xx.setName("sys_guid()");
//sqlColumnDefinition.setDefaultExpr(xx);
}
//@TODO 注释待转换
if(sqlColumnDefinition.getComment()!= null){
sqlColumnDefinition.setComment((String) null);
}
sqlColumnDefinition.setDbType(distDbType);
MapCacheUtil.getInstance().addCacheData(tableName.toUpperCase() + ":" + columnName.toUpperCase(), sqlColumnDefinition.toString().replaceAll(sqlColumnDefinition.getColumnName(), ""));
oracleCreateTableStatement.getTableElementList().add(sqlColumnDefinition);
}else if(sqlTableElement instanceof MySqlPrimaryKey){
OraclePrimaryKey oraclePrimaryKey = new OraclePrimaryKey();
List<SQLSelectOrderByItem> list = ((MySqlPrimaryKey) sqlTableElement).getIndexDefinition().getColumns();
for(int i=0;i<list.size();i++){
SQLIdentifierExpr sQLIdentifierExpr = (SQLIdentifierExpr)list.get(i).getExpr();
sQLIdentifierExpr.setName(sQLIdentifierExpr.getName().replaceAll("`", ""));
oraclePrimaryKey.addColumn(sQLIdentifierExpr);
}
oracleCreateTableStatement.getTableElementList().add(oraclePrimaryKey);
}else if(sqlTableElement instanceof MySqlUnique) {
OracleUnique oracleUnique = new OracleUnique();
((MySqlUnique) sqlTableElement).cloneTo(oracleUnique);
oracleCreateTableStatement.getTableElementList().add(oracleUnique);
}
}
if(Objects.nonNull(x.getSelect())){
x.setParent(oracleCreateTableStatement);
oracleCreateTableStatement.setSelect(x.getSelect());
}
println();
print(oracleCreateTableStatement.toString());
return false;
}
}

View File

@@ -0,0 +1,104 @@
package com.zyplayer.doc.db.framework.db.sql.dialect.mysql.util;
import com.alibaba.druid.sql.SQLTransformUtils;
import com.alibaba.druid.sql.SQLUtils;
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.sql.ast.expr.SQLNumericLiteralExpr;
import com.alibaba.druid.sql.ast.statement.SQLCharacterDataType;
import com.alibaba.druid.util.FnvHash;
import java.util.List;
/**
* mysql sql转换工具类
*
* @author diantu
* @since 2023年1月30日
*/
public class MySqlSQLDataTypeTransformUtil extends SQLTransformUtils {
public static SQLDataType transformMySqlToOracle(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
//|| nameHash == FnvHash.Constants.MEDIUMINT
|| nameHash == FnvHash.Constants.INT
|| nameHash == FnvHash.Constants.BIGINT
|| nameHash == FnvHash.Constants.TINYINT) {
if(argumentns.size() > 0){
int len;
SQLExpr arg0 = argumentns.get(0);
if (arg0 instanceof SQLNumericLiteralExpr) {
len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue();
} else {
throw new UnsupportedOperationException(SQLUtils.toMySqlString(x));
}
dataType = new SQLDataTypeImpl("NUMBER",len);
} else {
dataType = new SQLCharacterDataType("NUMBER");
}
} else if (nameHash == FnvHash.Constants.FLOAT
|| nameHash == FnvHash.Constants.DOUBLE
|| nameHash == FnvHash.Constants.DECIMAL) {
dataType = new SQLDataTypeImpl("DECIMAL");
int precision = 0;
if (argumentns.size() > 0) {
precision = ((SQLIntegerExpr) argumentns.get(0)).getNumber().intValue();
dataType = new SQLDataTypeImpl("DECIMAL",precision);
}
int scale = 0;
if (argumentns.size() > 1) {
scale = ((SQLIntegerExpr) argumentns.get(1)).getNumber().intValue();
dataType = new SQLDataTypeImpl("DECIMAL",precision,scale);
}
} else if (nameHash == FnvHash.Constants.DATE
|| nameHash == FnvHash.Constants.DATETIME) {
dataType = new SQLDataTypeImpl("DATE");
} else if (nameHash == FnvHash.Constants.TIMESTAMP) {
dataType = new SQLDataTypeImpl("TIMESTAMP");
} else if (nameHash == FnvHash.Constants.VARCHAR
||nameHash == FnvHash.Constants.CHAR) {
if(argumentns.size() > 0){
int len;
SQLExpr arg0 = argumentns.get(0);
if (arg0 instanceof SQLNumericLiteralExpr) {
len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue();
} else {
throw new UnsupportedOperationException(SQLUtils.toMySqlString(x));
}
dataType = new SQLDataTypeImpl("VARCHAR2",len);
}else{
dataType = new SQLDataTypeImpl("VARCHAR2");
}
} else if (nameHash == FnvHash.Constants.LONGTEXT) {
argumentns.clear();
dataType = new SQLCharacterDataType("CLOB");
} else if (nameHash == FnvHash.Constants.BOOLEAN) {
dataType = new SQLDataTypeImpl("NUMBER",1);
} else {
dataType = x;
}
if (dataType != x) {
dataType.setParent(x.getParent());
}
return dataType;
}
}

View File

@@ -0,0 +1,25 @@
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

@@ -3,6 +3,7 @@ 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.zyplayer.doc.db.framework.db.sql.dialect.mysql.MySqlToOracleOutputVisitor;
import com.zyplayer.doc.db.framework.db.sql.dialect.oracle.OracleToMySqlOutputVisitor;
import java.io.BufferedReader;
@@ -37,6 +38,24 @@ public class SQLTransformUtils {
return mysqlSql;
}
/**
* mysql sql语句转换为oracle sql语句
* @param sql
* @return
*/
public static String translateMySqlToOracle(String sql) {
List<SQLStatement> stmtList = SQLUtils.toStatementList(sql, DbType.mysql);
StringBuilder out = new StringBuilder();
MySqlToOracleOutputVisitor visitor = new MySqlToOracleOutputVisitor(out, false);
for(int i = 0; i < stmtList.size(); ++i) {
((SQLStatement)stmtList.get(i)).accept(visitor);
}
String oracleSql = out.toString();
return oracleSql;
}
/**
* 将字CLOB转成STRING类型
* @param clob

View File

@@ -12,6 +12,7 @@ import com.zyplayer.doc.db.framework.db.mapper.base.ExecuteParam;
import com.zyplayer.doc.db.framework.db.mapper.base.ExecuteResult;
import com.zyplayer.doc.db.framework.db.mapper.base.ExecuteType;
import com.zyplayer.doc.db.framework.db.mapper.mysql.MysqlMapper;
import com.zyplayer.doc.db.framework.utils.SQLTransformUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@@ -109,11 +110,11 @@ public class MysqlServiceImpl extends DbBaseService {
List<Map<String, Object>> tableDdlList = baseMapper.getTableDdl(dbName, tableName);
TableDdlVo tableDdlVo = new TableDdlVo();
tableDdlVo.setCurrent(DatabaseProductEnum.MYSQL.name().toLowerCase());
tableDdlVo.setMysql("// 生成失败");
tableDdlVo.setOracle("// TODO 等待大佬来实现转换");
// TODO 将建表语句转换为其他数据库的,还不知道怎么做,先这样留着,看有没大佬来实现
if (CollectionUtils.isNotEmpty(tableDdlList)) {
tableDdlVo.setMysql(tableDdlList.get(0).get("Create Table") + ";");
String mysqlSql = tableDdlList.get(0).get("Create Table") + ";";
tableDdlVo.setMysql(mysqlSql);
tableDdlVo.setOracle(SQLTransformUtils.translateMySqlToOracle(mysqlSql));
// TODO sqlserver等数据库同理
}
return tableDdlVo;
}

View File

@@ -84,7 +84,6 @@ public class OracleServiceImpl extends DbBaseService {
} catch (IOException e) {
throw new RuntimeException(e);
}
//String oracleSql = tableDdlList.get(0).get("CREATETABLE") + ";";
tableDdlVo.setOracle(oracleSql);
//oracle建表语句转换为mysql建表语句
String mysqlSql = SQLTransformUtils.translateOracleToMySql(oracleSql);