From d8b400189bb6ea5bd907e84f35bac964afb5ec81 Mon Sep 17 00:00:00 2001 From: diantu Date: Mon, 30 Jan 2023 14:53:37 +0800 Subject: [PATCH] =?UTF-8?q?sql=E7=BF=BB=E8=AF=91=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E6=90=AD=E5=BB=BA=E5=AE=8C=E6=88=90(?= =?UTF-8?q?=E5=9F=BA=E4=BA=8EDruid=20SQL=20Parser=E8=A7=A3=E6=9E=90SQL?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=B8=8D=E5=90=8C=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E9=97=B4sql=E8=AF=AD=E5=8F=A5=E4=BA=92=E8=BD=AC)=20=E7=9B=AE?= =?UTF-8?q?=E5=89=8D=E5=B7=B2=E5=AE=9E=E7=8E=B0oracle->mysql=E5=BB=BA?= =?UTF-8?q?=E8=A1=A8=E8=AF=AD=E5=8F=A5=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/db/mapper/base/BaseMapper.java | 30 +- .../db/mapper/oracle/OracleBaseMapper.xml | 4 + .../doc/db/framework/db/sql/MethodInvoke.java | 58 ++++ .../mysql/MySqlToOracleOutputVisitor.java | 22 ++ .../dialect/mysql/function/MySqlFunction.java | 12 + .../MySqlToOracleFunctionTransform.java | 10 + .../db/sql/dialect/mysql/util/MySqlUtil.java | 26 ++ .../oracle/OracleToMySqlOutputVisitor.java | 130 +++++++++ .../oracle/function/OracleFunction.java | 49 ++++ .../OracleToMySqlFunctionTransform.java | 18 ++ .../util/OracleSQLDataTypeTransformUtil.java | 268 ++++++++++++++++++ .../doc/db/framework/utils/MapCacheUtil.java | 52 ++++ .../db/framework/utils/SQLTransformUtils.java | 63 ++++ .../db/service/database/HiveServiceImpl.java | 20 +- .../db/service/database/MysqlServiceImpl.java | 2 +- .../service/database/OracleServiceImpl.java | 41 +++ 16 files changed, 779 insertions(+), 26 deletions(-) create mode 100644 zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/MethodInvoke.java create mode 100644 zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/MySqlToOracleOutputVisitor.java create mode 100644 zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/function/MySqlFunction.java create mode 100644 zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/function/MySqlToOracleFunctionTransform.java create mode 100644 zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/util/MySqlUtil.java create mode 100644 zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/oracle/OracleToMySqlOutputVisitor.java create mode 100644 zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/oracle/function/OracleFunction.java create mode 100644 zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/oracle/function/OracleToMySqlFunctionTransform.java create mode 100644 zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/oracle/util/OracleSQLDataTypeTransformUtil.java create mode 100644 zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/MapCacheUtil.java create mode 100644 zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/SQLTransformUtils.java diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/mapper/base/BaseMapper.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/mapper/base/BaseMapper.java index f94955b9..4a5f9447 100644 --- a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/mapper/base/BaseMapper.java +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/mapper/base/BaseMapper.java @@ -16,7 +16,7 @@ import java.util.Map; * @since 2018年8月8日 */ public interface BaseMapper { - + /** * 获取库列表 * @@ -24,8 +24,8 @@ public interface BaseMapper { * @author 暮光:城中城 * @since 2018年8月8日 */ - List> getTableDdl(@Param("dbName") String dbName, @Param("tableName") String tableName); - + List> getTableDdl(@Param("dbName") String dbName, @Param("tableName") String tableName); + /** * 获取库列表 * @@ -34,7 +34,7 @@ public interface BaseMapper { * @since 2018年8月8日 */ List getDatabaseList(); - + /** * 获取表列表 * @@ -44,7 +44,7 @@ public interface BaseMapper { * @since 2018年8月8日 */ List getTableList(@Param("dbName") String dbName); - + /** * 获取字段列表 * @@ -55,7 +55,7 @@ public interface BaseMapper { * @since 2018年8月8日 */ List getTableColumnList(@Param("dbName") String dbName, @Param("tableName") String tableName); - + /** * 模糊搜索表和字段 * @@ -66,7 +66,7 @@ public interface BaseMapper { * @since 2018年8月8日 */ List getTableAndColumnBySearch(@Param("dbName") String dbName, @Param("searchText") String searchText); - + /** * 获取表注释 * @@ -76,7 +76,7 @@ public interface BaseMapper { * @since 2018年8月8日 */ List getTableDescList(@Param("dbName") String dbName, @Param("tableName") String tableName); - + /** * 增加表注释 * @@ -86,7 +86,7 @@ public interface BaseMapper { * @since 2018年8月8日 */ void updateTableDesc(@Param("dbName") String dbName, @Param("tableName") String tableName, @Param("newDesc") String newDesc); - + /** * 增加字段注释 * @@ -101,7 +101,7 @@ public interface BaseMapper { void updateTableColumnDesc(@Param("dbName") String dbName, @Param("tableName") String tableName, @Param("columnName") String columnName, @Param("newDesc") String newDesc, @Param("columnInfo") ColumnInfoDto columnInfo); - + /** * 获取表基本信息 * @@ -111,7 +111,7 @@ public interface BaseMapper { * @since 2019年9月1日 */ TableStatusVo getTableStatus(@Param("dbName") String dbName, @Param("tableName") String tableName); - + /** * 获取存储过程总条数 * @@ -120,7 +120,7 @@ public interface BaseMapper { * @since 2020年4月24日 */ Long getProcedureCount(@Param("param") ProcedureListParam procedureParam); - + /** * 获取存储过程列表 * @@ -129,7 +129,7 @@ public interface BaseMapper { * @since 2020年4月24日 */ List getProcedureList(@Param("param") ProcedureListParam procedureParam); - + /** * 获取存储过程详情 * @@ -140,7 +140,7 @@ public interface BaseMapper { * @since 2020年4月24日 */ ProcedureDto getProcedureDetail(@Param("dbName") String dbName, @Param("typeName") String typeName, @Param("procName") String procName); - + /** * 删除存储过程 * @@ -151,7 +151,7 @@ public interface BaseMapper { * @since 2020年4月24日 */ void deleteProcedure(@Param("dbName") String dbName, @Param("typeName") String typeName, @Param("procName") String procName); - + /** * 删除行数 * @author 暮光:城中城 diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/mapper/oracle/OracleBaseMapper.xml b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/mapper/oracle/OracleBaseMapper.xml index 453cc24c..7fa9f350 100644 --- a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/mapper/oracle/OracleBaseMapper.xml +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/mapper/oracle/OracleBaseMapper.xml @@ -71,6 +71,10 @@ + + comment on table ${dbName}.${tableName} is #{new Desc} diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/MethodInvoke.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/MethodInvoke.java new file mode 100644 index 00000000..daf3cc99 --- /dev/null +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/MethodInvoke.java @@ -0,0 +1,58 @@ +package com.zyplayer.doc.db.framework.db.sql; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.ObjectUtils; +import org.springframework.util.ReflectionUtils; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Optional; + +/** + * sql方法反射实现 + * + * @author diantu + * @since 2023年1月29日 + */ +public interface MethodInvoke { + + Logger log = LoggerFactory.getLogger(MethodInvoke.class); + + /** + * 方法转换 + * @param expr + */ + default void methodInvoke(SQLMethodInvokeExpr expr){ + if (ObjectUtils.isEmpty(expr)) { + return; + } + Method method = ReflectionUtils.findMethod(this.getClass(), expr.getMethodName().toLowerCase(), SQLMethodInvokeExpr.class); + if (null != method) { + try { + method.invoke(this, new Object[]{expr}); + } catch (Exception e) { + log.error("method invoke error", e); + e.printStackTrace(); + } + } + } + + /** + * 处理嵌套函数 + * @param sqlExpr + */ + default void forEachMethod(SQLExpr sqlExpr) { + if (sqlExpr instanceof SQLMethodInvokeExpr) { + methodInvoke((SQLMethodInvokeExpr) sqlExpr); + } + Optional.ofNullable(sqlExpr.getChildren()).orElse(new ArrayList<>()).forEach(e -> { + if (e instanceof SQLMethodInvokeExpr) { + forEachMethod((SQLMethodInvokeExpr) e); + } + }); + } + +} diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/MySqlToOracleOutputVisitor.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/MySqlToOracleOutputVisitor.java new file mode 100644 index 00000000..5845772a --- /dev/null +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/MySqlToOracleOutputVisitor.java @@ -0,0 +1,22 @@ +package com.zyplayer.doc.db.framework.db.sql.dialect.mysql; + +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor; + +/** + * mysql转oracle遍历实现 + * + * @author diantu + * @since 2023年1月29日 + */ +public class MySqlToOracleOutputVisitor extends MySqlOutputVisitor { + + public MySqlToOracleOutputVisitor(Appendable appender) { + super(appender); + } + + public MySqlToOracleOutputVisitor(Appendable appender, boolean parameterized) { + super(appender, parameterized); + } + + +} diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/function/MySqlFunction.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/function/MySqlFunction.java new file mode 100644 index 00000000..3395b343 --- /dev/null +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/function/MySqlFunction.java @@ -0,0 +1,12 @@ +package com.zyplayer.doc.db.framework.db.sql.dialect.mysql.function; + +import com.zyplayer.doc.db.framework.db.sql.MethodInvoke; + +/** + * mysql2oracle需要转换的函数 + * + * @author diantu + * @since 2023年1月29日 + */ +public interface MySqlFunction extends MethodInvoke { +} diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/function/MySqlToOracleFunctionTransform.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/function/MySqlToOracleFunctionTransform.java new file mode 100644 index 00000000..df4049aa --- /dev/null +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/function/MySqlToOracleFunctionTransform.java @@ -0,0 +1,10 @@ +package com.zyplayer.doc.db.framework.db.sql.dialect.mysql.function; + +/** + * mysql2oracle需要转换的函数实现 + * + * @author diantu + * @since 2023年1月29日 + */ +public class MySqlToOracleFunctionTransform implements MySqlFunction{ +} diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/util/MySqlUtil.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/util/MySqlUtil.java new file mode 100644 index 00000000..dc34f2d0 --- /dev/null +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/mysql/util/MySqlUtil.java @@ -0,0 +1,26 @@ +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()); + } + +} diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/oracle/OracleToMySqlOutputVisitor.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/oracle/OracleToMySqlOutputVisitor.java new file mode 100644 index 00000000..694d4911 --- /dev/null +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/sql/dialect/oracle/OracleToMySqlOutputVisitor.java @@ -0,0 +1,130 @@ +package com.zyplayer.doc.db.framework.db.sql.dialect.oracle; + +import com.alibaba.druid.DbType; +import com.alibaba.druid.sql.ast.SQLExpr; +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.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.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 java.util.List; +import java.util.Objects; + +/** + * oracle转mysql遍历实现 + * + * @author diantu + * @since 2023年1月29日 + */ +public class OracleToMySqlOutputVisitor extends OracleOutputVisitor { + + private final OracleToMySqlFunctionTransform functionTransform = new OracleToMySqlFunctionTransform(); + + // 目标数据库类型 + private final DbType distDbType = DbType.mysql; + + public OracleToMySqlOutputVisitor(Appendable appender) { + super(appender); + } + + public OracleToMySqlOutputVisitor(Appendable appender, boolean printPostSemi) { + super(appender, printPostSemi); + } + + /** + * oracle建表语句遍历 + * @param x + * @return + */ + @Override + public boolean visit(OracleCreateTableStatement x) { + MySqlCreateTableStatement mySqlCreateTableStatement = new MySqlCreateTableStatement(); + mySqlCreateTableStatement.setTableSource(x.getTableSource()); + String tableName = x.getTableSource().getName().getSimpleName(); + mySqlCreateTableStatement.setName(String.valueOf(x.getName()).replaceAll("\"", "")); + for(SQLTableElement sqlTableElement : x.getTableElementList()){ + if( sqlTableElement instanceof SQLColumnDefinition) { + SQLColumnDefinition sqlColumnDefinition = ((SQLColumnDefinition)sqlTableElement); + String columnName = sqlColumnDefinition.getName().getSimpleName().replaceAll("\"", ""); + sqlColumnDefinition.setName(columnName); + if(MySqlUtil.containsKeyWords(columnName)){ + sqlColumnDefinition.setName("`"+columnName+"`"); + } + sqlColumnDefinition.setDataType(OracleSQLDataTypeTransformUtil.transformOracleToMySql(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.SYS_GUID || nameHashCode64 == FnvHash.Constants.TO_CHAR) { + sqlColumnDefinition.setDefaultExpr(null); + }else { + 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); + } + } + } + sqlColumnDefinition.setDbType(distDbType); + MapCacheUtil.getInstance().addCacheData(tableName.toUpperCase() + ":" + columnName.toUpperCase(), sqlColumnDefinition.toString().replaceAll(sqlColumnDefinition.getColumnName(), "")); + mySqlCreateTableStatement.getTableElementList().add(sqlColumnDefinition); + }else if(sqlTableElement instanceof OraclePrimaryKey){ + MySqlPrimaryKey mySqlPrimaryKey = new MySqlPrimaryKey(); + mySqlPrimaryKey.setName("primary key"); + List list = ((OraclePrimaryKey) sqlTableElement).getIndexDefinition().getColumns(); + for(int i=0;i argumentns = x.getArguments(); + SQLDataType dataType; + if (nameHash == FnvHash.Constants.UROWID) { + int len = 4000; + if (argumentns.size() == 1) { + SQLExpr arg0 = argumentns.get(0); + if (arg0 instanceof SQLIntegerExpr) { + len = ((SQLIntegerExpr) arg0).getNumber().intValue(); + } + } + dataType = new SQLDataTypeImpl("varchar", len); + } else if (nameHash == FnvHash.Constants.ROWID) { + dataType = new SQLDataTypeImpl("char", 10); + + } else if (nameHash == FnvHash.Constants.BOOLEAN) { + dataType = new SQLDataTypeImpl("tinyint"); + + } else if (nameHash == FnvHash.Constants.INTEGER) { + dataType = new SQLDataTypeImpl("int"); + + } else if (nameHash == FnvHash.Constants.FLOAT + || nameHash == FnvHash.Constants.BINARY_FLOAT) { + dataType = new SQLDataTypeImpl("float"); + + } else if (nameHash == FnvHash.Constants.REAL + || nameHash == FnvHash.Constants.BINARY_DOUBLE + || nameHash == FnvHash.Constants.DOUBLE_PRECISION) { + dataType = new SQLDataTypeImpl("double"); + + } else if (nameHash == FnvHash.Constants.NUMBER) { + if (argumentns.size() == 0) { + dataType = new SQLDataTypeImpl("decimal", 38); + } else { + SQLExpr arg0 = argumentns.get(0); + + int precision, scale = 0; + if (arg0 instanceof SQLAllColumnExpr) { + precision = 9; + } else { + precision = ((SQLIntegerExpr) arg0).getNumber().intValue(); + } + + if (argumentns.size() > 1) { + scale = ((SQLIntegerExpr) argumentns.get(1)).getNumber().intValue(); + } + + if (scale > precision) { + if (arg0 instanceof SQLAllColumnExpr) { + precision = 19; + if (scale > precision) { + precision = scale; + } + } else { + precision = scale; + } + } + + if (scale == 0) { + if (precision < 3) { + dataType = new SQLDataTypeImpl("tinyint"); + } else if (precision < 5) { + dataType = new SQLDataTypeImpl("smallint"); + } else if (precision < 9) { + dataType = new SQLDataTypeImpl("int"); + } else if (precision <= 20) { + dataType = new SQLDataTypeImpl("bigint"); + } else { + dataType = new SQLDataTypeImpl("decimal", precision); + } + } else { + dataType = new SQLDataTypeImpl("decimal", precision, scale); + } + } + + } else if (nameHash == FnvHash.Constants.DEC + || nameHash == FnvHash.Constants.DECIMAL) { + + dataType = x.clone(); + dataType.setName("decimal"); + + int precision = 0; + if (argumentns.size() > 0) { + precision = ((SQLIntegerExpr) argumentns.get(0)).getNumber().intValue(); + } + + int scale = 0; + if (argumentns.size() > 1) { + scale = ((SQLIntegerExpr) argumentns.get(1)).getNumber().intValue(); + if (precision < scale) { + ((SQLIntegerExpr) dataType.getArguments().get(1)).setNumber(precision); + } + } + } else if (nameHash == FnvHash.Constants.RAW) { + int len; + + if (argumentns.size() == 0) { + len = -1; + } else if (argumentns.size() == 1) { + SQLExpr arg0 = argumentns.get(0); + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + if (len == -1) { + dataType = new SQLDataTypeImpl("binary"); + } else if (len <= 255) { + dataType = new SQLDataTypeImpl("binary", len); + } else { + dataType = new SQLDataTypeImpl("varbinary", len); + } + } else if (nameHash == FnvHash.Constants.CHAR + || nameHash == FnvHash.Constants.CHARACTER) { + if (argumentns.size() == 1) { + SQLExpr arg0 = argumentns.get(0); + + int len; + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + if (len <= 255) { + dataType = new SQLCharacterDataType("char", len); + } else { + dataType = new SQLCharacterDataType("varchar", len); + } + } else if (argumentns.size() == 0) { + dataType = new SQLCharacterDataType("char"); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + } else if (nameHash == FnvHash.Constants.NCHAR) { + if (argumentns.size() == 1) { + SQLExpr arg0 = argumentns.get(0); + + int len; + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + if (len <= 255) { + dataType = new SQLCharacterDataType("nchar", len); + } else { + dataType = new SQLCharacterDataType("nvarchar", len); + } + } else if (argumentns.size() == 0) { + dataType = new SQLCharacterDataType("nchar"); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + } else if (nameHash == FnvHash.Constants.VARCHAR2) { + 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.toOracleString(x)); + } + if(len >= 4000) { + dataType = new SQLCharacterDataType("text"); + }else { + dataType = new SQLCharacterDataType("varchar", len); + } + } else { + dataType = new SQLCharacterDataType("varchar"); + } + + } else if (nameHash == FnvHash.Constants.NVARCHAR2) { + 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.toOracleString(x)); + } + dataType = new SQLCharacterDataType("nvarchar", len); + } else { + dataType = new SQLCharacterDataType("nvarchar"); + } + + } else if (nameHash == FnvHash.Constants.BFILE) { + dataType = new SQLCharacterDataType("varchar", 255); + + } else if (nameHash == FnvHash.Constants.DATE + || nameHash == FnvHash.Constants.TIMESTAMP) { + int len = -1; + if (argumentns.size() > 0) { + SQLExpr arg0 = argumentns.get(0); + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + } + + /*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(); + dataType = new SQLDataTypeImpl("LONGBLOB"); + + } else if (nameHash == FnvHash.Constants.CLOB + || nameHash == FnvHash.Constants.NCLOB + || nameHash == FnvHash.Constants.LONG + || nameHash == FnvHash.Constants.XMLTYPE) { + argumentns.clear(); + dataType = new SQLCharacterDataType("LONGTEXT"); + } else { + dataType = x; + } + + if (dataType != x) { + dataType.setParent(x.getParent()); + } + + return dataType; + } + +} diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/MapCacheUtil.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/MapCacheUtil.java new file mode 100644 index 00000000..6ccb90a6 --- /dev/null +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/MapCacheUtil.java @@ -0,0 +1,52 @@ +package com.zyplayer.doc.db.framework.utils; + +import java.util.HashMap; +import java.util.Map; + +/** + * 基于Map实现内存缓存 + * + * @author diantu + * @since 2023年1月29日 + */ +public class MapCacheUtil { + + private static MapCacheUtil cacheUtil; + private static Map cacheMap; + + private MapCacheUtil(){ + cacheMap = new HashMap(); + } + + public static MapCacheUtil getInstance(){ + if (cacheUtil == null){ + cacheUtil = new MapCacheUtil(); + } + return cacheUtil; + } + + /** + * 添加缓存 + */ + public void addCacheData(String key,Object obj){ + cacheMap.put(key,obj); + } + + /** + * 取出缓存 + */ + public Object getCacheData(String key){ + return cacheMap.get(key); + } + + /** + * 清楚缓存 + */ + public void removeCacheData(String key){ + cacheMap.remove(key); + } + + public Map cacheMap() { + return cacheMap; + } +} diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/SQLTransformUtils.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/SQLTransformUtils.java new file mode 100644 index 00000000..a97f7379 --- /dev/null +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/SQLTransformUtils.java @@ -0,0 +1,63 @@ +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.oracle.OracleToMySqlOutputVisitor; + +import java.io.BufferedReader; +import java.io.IOException; +import java.sql.Clob; +import java.sql.SQLException; +import java.util.List; + +/** + * sql语句转换工具类 + * + * @author diantu + * @since 2023年1月29日 + */ +public class SQLTransformUtils { + + /** + * oracle sql语句转换为mysql sql语句 + * @param sql + * @return + */ + public static String translateOracleToMySql(String sql) { + List stmtList = SQLUtils.toStatementList(sql, DbType.oracle); + StringBuilder out = new StringBuilder(); + OracleToMySqlOutputVisitor visitor = new OracleToMySqlOutputVisitor(out, false); + + for(int i = 0; i < stmtList.size(); ++i) { + ((SQLStatement)stmtList.get(i)).accept(visitor); + } + + String mysqlSql = out.toString(); + return mysqlSql; + } + + /** + * 将字CLOB转成STRING类型 + * @param clob + * @return + * @throws SQLException + * @throws IOException + */ + public static String ClobToString(Clob clob) throws SQLException, IOException { + + String reString = ""; + // 得到流 + java.io.Reader is = clob.getCharacterStream(); + BufferedReader br = new BufferedReader(is); + String s = br.readLine(); + StringBuffer sb = new StringBuffer(); + // 执行循环将字符串全部取出付值给StringBuffer由StringBuffer转成STRING + while (s != null) { + sb.append(s); + s = br.readLine(); + } + reString = sb.toString(); + return reString; + } +} diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/HiveServiceImpl.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/HiveServiceImpl.java index 59dfbab2..929cda98 100644 --- a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/HiveServiceImpl.java +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/HiveServiceImpl.java @@ -22,12 +22,12 @@ import java.util.stream.Collectors; */ @Service public class HiveServiceImpl extends DbBaseService { - + @Override public DatabaseProductEnum getDatabaseProduct() { return DatabaseProductEnum.HIVE; } - + @Override public List getTableList(Long sourceId, String dbName) { BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId); @@ -37,40 +37,40 @@ public class HiveServiceImpl extends DbBaseService { } return tableList; } - + @Override public TableDdlVo getTableDdl(Long sourceId, String dbName, String tableName) { BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId); - List> tableDdlList = baseMapper.getTableDdl(dbName, tableName); + List> tableDdlList = baseMapper.getTableDdl(dbName, tableName); TableDdlVo tableDdlVo = new TableDdlVo(); tableDdlVo.setCurrent(DatabaseProductEnum.HIVE.name().toLowerCase()); if (CollectionUtils.isNotEmpty(tableDdlList)) { // hive和impala结果集不一样 if (tableDdlList.size() == 1) { - tableDdlVo.setHive(tableDdlList.get(0).get("result")); + tableDdlVo.setHive(tableDdlList.get(0).get("result").toString()); } else { - String createTabStmt = tableDdlList.stream().map(map -> map.get("createtab_stmt")).collect(Collectors.joining("\n")); + String createTabStmt = tableDdlList.stream().map(map -> map.get("createtab_stmt").toString()).collect(Collectors.joining("\n")); tableDdlVo.setHive(createTabStmt); } } return tableDdlVo; } - + @Override public List getTableAndColumnBySearch(Long sourceId, String dbName, String searchText) { throw new ConfirmException("不支持的操作"); } - + @Override public List getTableDescList(Long sourceId, String dbName, String tableName) { throw new ConfirmException("不支持的操作"); } - + @Override public void updateTableDesc(Long sourceId, String dbName, String tableName, String newDesc) { throw new ConfirmException("不支持的操作"); } - + @Override public void updateTableColumnDesc(Long sourceId, String dbName, String tableName, String columnName, String newDesc) { throw new ConfirmException("不支持的操作"); diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/MysqlServiceImpl.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/MysqlServiceImpl.java index d02e585c..4336a26f 100644 --- a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/MysqlServiceImpl.java +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/MysqlServiceImpl.java @@ -106,7 +106,7 @@ public class MysqlServiceImpl extends DbBaseService { @Override public TableDdlVo getTableDdl(Long sourceId, String dbName, String tableName) { BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId); - List> tableDdlList = baseMapper.getTableDdl(dbName, tableName); + List> tableDdlList = baseMapper.getTableDdl(dbName, tableName); TableDdlVo tableDdlVo = new TableDdlVo(); tableDdlVo.setCurrent(DatabaseProductEnum.MYSQL.name().toLowerCase()); tableDdlVo.setMysql("// 生成失败"); diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/OracleServiceImpl.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/OracleServiceImpl.java index d8414118..daeacf61 100644 --- a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/OracleServiceImpl.java +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/OracleServiceImpl.java @@ -1,10 +1,20 @@ package com.zyplayer.doc.db.service.database; import com.zyplayer.doc.db.controller.param.DataViewParam; +import com.zyplayer.doc.db.controller.vo.TableDdlVo; 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.utils.SQLTransformUtils; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; +import java.io.IOException; +import java.sql.Clob; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + /** * Oracle数据查询服务实现类 * @@ -52,4 +62,35 @@ public class OracleServiceImpl extends DbBaseService { sqlSbFinal.append(String.format("select * from ( select %s from %s", queryColumns + ",rownum rn", "(" + sqlSb + ") where rownum<=" + pageSize + " ) t2 where t2.rn >=" + pageNum)); return sqlSbFinal.toString(); } + + /** + * 获取建表语句 + * + * @author diantu + * @since 2023年1月29日 + */ + @Override + public TableDdlVo getTableDdl(Long sourceId, String dbName, String tableName) { + BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId); + List> tableDdlList = baseMapper.getTableDdl(dbName, tableName); + TableDdlVo tableDdlVo = new TableDdlVo(); + tableDdlVo.setCurrent(DatabaseProductEnum.MYSQL.name().toLowerCase()); + if (CollectionUtils.isNotEmpty(tableDdlList)) { + String oracleSql = ""; + try { + oracleSql = SQLTransformUtils.ClobToString((Clob)tableDdlList.get(0).get("CREATETABLE")); + } catch (SQLException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + //String oracleSql = tableDdlList.get(0).get("CREATETABLE") + ";"; + tableDdlVo.setOracle(oracleSql); + //oracle建表语句转换为mysql建表语句 + String mysqlSql = SQLTransformUtils.translateOracleToMySql(oracleSql); + tableDdlVo.setMysql(mysqlSql); + // TODO sqlserver等数据库同理 + } + return tableDdlVo; + } }