diff --git a/lib/Dm7JdbcDriver-16.jar b/lib/Dm7JdbcDriver-16.jar new file mode 100644 index 0000000..5132f3f Binary files /dev/null and b/lib/Dm7JdbcDriver-16.jar differ diff --git a/screw-core/src/main/java/cn/smallbun/screw/core/query/DatabaseType.java b/screw-core/src/main/java/cn/smallbun/screw/core/query/DatabaseType.java index fe37e9b..da14c7a 100644 --- a/screw-core/src/main/java/cn/smallbun/screw/core/query/DatabaseType.java +++ b/screw-core/src/main/java/cn/smallbun/screw/core/query/DatabaseType.java @@ -19,7 +19,6 @@ package cn.smallbun.screw.core.query; import cn.smallbun.screw.core.query.cachedb.CacheDbDataBaseQuery; import cn.smallbun.screw.core.query.db2.Db2DataBaseQuery; -import cn.smallbun.screw.core.query.dm.DmDataBaseQuery; import cn.smallbun.screw.core.query.h2.H2DataBaseQuery; import cn.smallbun.screw.core.query.highgo.HigHgoDataBaseQuery; import cn.smallbun.screw.core.query.hsql.HsqlDataBaseQuery; diff --git a/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/DmDataBaseQuery.java b/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/DmDataBaseQuery.java index 339f293..efe00b8 100644 --- a/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/DmDataBaseQuery.java +++ b/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/DmDataBaseQuery.java @@ -17,27 +17,94 @@ */ package cn.smallbun.screw.core.query.dm; +import static cn.smallbun.screw.core.constant.DefaultConstants.PERCENT_SIGN; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.stream.Collectors; + +import javax.sql.DataSource; + import cn.smallbun.screw.core.exception.QueryException; +import cn.smallbun.screw.core.mapping.Mapping; import cn.smallbun.screw.core.metadata.Column; import cn.smallbun.screw.core.metadata.Database; import cn.smallbun.screw.core.metadata.PrimaryKey; -import cn.smallbun.screw.core.metadata.Table; import cn.smallbun.screw.core.query.AbstractDatabaseQuery; +import cn.smallbun.screw.core.query.dm.model.DmColumnModel; +import cn.smallbun.screw.core.query.dm.model.DmDatabaseModel; +import cn.smallbun.screw.core.query.dm.model.DmPrimaryKeyModel; +import cn.smallbun.screw.core.query.dm.model.DmTableModel; import cn.smallbun.screw.core.util.Assert; +import cn.smallbun.screw.core.util.CollectionUtils; import cn.smallbun.screw.core.util.ExceptionUtils; - -import javax.sql.DataSource; -import java.util.List; - -import static cn.smallbun.screw.core.constant.DefaultConstants.NOT_SUPPORTED; +import cn.smallbun.screw.core.util.JdbcUtils; +import dm.jdbc.driver.DmdbConnection; /** * 达梦数据库查询 * * @author SanLi - * Created by qinggang.zuo@gmail.com / 2689170096@qq.com on 2020/3/20 17:40 + * Created by jincy@neusoft.com + qinggang.zuo@gmail.com / 2689170096@qq.com on 2020/9/17 17:40 */ +@SuppressWarnings("serial") public class DmDataBaseQuery extends AbstractDatabaseQuery { + private ConcurrentMap> tablesMap = new ConcurrentHashMap<>(); + private static String DM_QUERY_TABLE_SQL = "" + + "select " + + " ut.table_name TABLE_NAME, " + + " utc.comments COMMENTS " + + "from " + + " user_tables ut " + + "left join USER_TAB_COMMENTS utc " + + "on " + + " ut.table_name=utc.table_name "; + + private static String DM_QUERY_COLUMNS_SQL = "" + "select " + + " ut.table_name TABLE_NAME , " + + " uc.column_name COLUMN_NAME , " + //+ " case uc.data_type when 'INT' then uc.data_type when 'CLOB' then uc.data_type when 'BLOB' then uc.data_type when 'INTEGER' then uc.data_type else concat(concat(concat(uc.data_type, '('), uc.data_length), ')') end case AS COLUMN_TYPE , " + + " case uc.data_type when 'CLOB' then uc.data_type when 'BLOB' then uc.data_type else concat(concat(concat(uc.data_type, '('), uc.data_length), ')') end case AS COLUMN_TYPE , " + + " uc.data_length COLUMN_LENGTH , " + + " uc.DATA_PRECISION DATA_PRECISION, " + + " uc.DATA_SCALE DECIMAL_DIGITS, " + + " case uc.NULLABLE when 'Y' then '1' else '0' end case NULLABLE," + + " uc.DATA_DEFAULT COLUMN_DEF, " + + " ucc.comments REMARKS " + + "from " + + " user_tables ut " + + "left join USER_TAB_COMMENTS utc " + + "on " + + " ut.table_name=utc.table_name " + + "left join user_tab_columns uc " + + "on " + + " ut.table_name=uc.table_name " + + "left join user_col_comments ucc " + + "on " + + " uc.table_name =ucc.table_name " + + " and uc.column_name=ucc.column_name " + + "where 1=1 "; + + private static String DM_QUERY_PK_SQL = "" + "SELECT " + + "C.OWNER AS TABLE_SCHEM, " + + "C.TABLE_NAME , " + + "C.COLUMN_NAME , " + + "C.POSITION AS KEY_SEQ , " + + "C.CONSTRAINT_NAME AS PK_NAME " + + "FROM " + + " ALL_CONS_COLUMNS C, " + + " ALL_CONSTRAINTS K " + + "WHERE " + + " K.CONSTRAINT_TYPE = 'P' " + + " AND K.OWNER = '%s' " + + " AND K.CONSTRAINT_NAME = C.CONSTRAINT_NAME " + + " AND K.TABLE_NAME = C.TABLE_NAME " + + " AND K.OWNER = C.OWNER "; /** * 构造函数 @@ -55,7 +122,46 @@ public class DmDataBaseQuery extends AbstractDatabaseQuery { */ @Override public Database getDataBase() throws QueryException { - throw ExceptionUtils.mpe(NOT_SUPPORTED); + DmDatabaseModel model = new DmDatabaseModel(); + //当前数据库名称 + model.setDatabase(getSchema()); + return model; + } + + /** + * 获取达梦数据库的schema + * + * @return {@link String} 达梦数据库的schema信息 + */ + @Override + public String getSchema() throws QueryException { + try { + String schema; + DmdbConnection conn = (DmdbConnection) getMetaData().getConnection(); + schema = conn.getUserName(); + return schema; + } catch (SQLException e) { + throw ExceptionUtils.mpe(e); + } + } + + /** + * 获取达梦数据库的schema + * + * @return {@link String} 达梦数据库的schema信息 + */ + public String getSchemaBak() throws QueryException { + try { + String schema = null; + ResultSet rs = getMetaData().getSchemas(); + while (rs.next()) { + schema = rs.getString(1); + break; + } + return schema; + } catch (Exception e) { + throw ExceptionUtils.mpe(e); + } } /** @@ -64,8 +170,34 @@ public class DmDataBaseQuery extends AbstractDatabaseQuery { * @return {@link List} 所有表信息 */ @Override - public List getTables() { - throw ExceptionUtils.mpe(NOT_SUPPORTED); + public List getTables() throws QueryException { + ResultSet resultSet = null; + try { + //查询 + resultSet = getMetaData().getTables(getSchema(), getSchema(), PERCENT_SIGN, + new String[] { "TABLE" }); + //映射 + List list = Mapping.convertList(resultSet, DmTableModel.class); + + resultSet = prepareStatement(DM_QUERY_TABLE_SQL).executeQuery(); + List inquires = Mapping.convertList(resultSet, DmTableModel.class); + + //处理备注信息 + list.forEach((DmTableModel model) -> { + //备注 + inquires.stream() + .filter(inquire -> model.getTableName().equals(inquire.getTableName())) + .forEachOrdered(inquire -> model.setRemarks(inquire.getRemarks())); + }); + if (!list.isEmpty()) { + tablesMap.put("AllTable", list); + } + return list; + } catch (SQLException e) { + throw ExceptionUtils.mpe(e); + } finally { + JdbcUtils.close(resultSet, this.connection); + } } /** @@ -73,12 +205,52 @@ public class DmDataBaseQuery extends AbstractDatabaseQuery { * * @param table {@link String} 表名 * @return {@link List} 表字段信息 - * @throws QueryException QueryException */ @Override - public List getTableColumns(String table) throws QueryException { + public List getTableColumns(String table) throws QueryException { Assert.notEmpty(table, "Table name can not be empty!"); - throw ExceptionUtils.mpe(NOT_SUPPORTED); + ResultSet resultSet = null; + List resultList = new ArrayList<>(); + List tableNames = new ArrayList<>(); + try { + //从缓存中获取表对象 + List tables = tablesMap.get("AllTable"); + if (tables.isEmpty()) { + tables = getTables(); + } else { + for (DmTableModel dtm : tables) { + tableNames.add(dtm.getTableName()); + } + } + /*如果表为空,则直接返回*/ + if (tableNames.isEmpty()) { + return null; + } + + if (CollectionUtils.isEmpty(columnsCaching)) { + //查询全部 + if (table.equals(PERCENT_SIGN)) { + PreparedStatement statement = prepareStatement(DM_QUERY_COLUMNS_SQL); + resultSet = statement.executeQuery(); + } else { + //查询单表的列信息 + String singleTableSql = DM_QUERY_COLUMNS_SQL.concat(" and ut.table_name='%s'"); + resultSet = prepareStatement(String.format(singleTableSql, table)) + .executeQuery(); + } + + List inquires = Mapping.convertList(resultSet, DmColumnModel.class); + //这里利用lambda表达式将多行列信息按table name 进行归类,并放入缓存 + tableNames.forEach(name -> columnsCaching.put(name, inquires.stream() + .filter(i -> i.getTableName().equals(name)).collect(Collectors.toList()))); + resultList = inquires; + } + return resultList; + } catch (SQLException e) { + throw ExceptionUtils.mpe(e); + } finally { + JdbcUtils.close(resultSet, this.connection); + } } /** @@ -89,7 +261,7 @@ public class DmDataBaseQuery extends AbstractDatabaseQuery { */ @Override public List getTableColumns() throws QueryException { - throw ExceptionUtils.mpe(NOT_SUPPORTED); + return getTableColumns(PERCENT_SIGN); } /** @@ -101,7 +273,37 @@ public class DmDataBaseQuery extends AbstractDatabaseQuery { */ @Override public List getPrimaryKeys(String table) throws QueryException { - throw ExceptionUtils.mpe(NOT_SUPPORTED); + ResultSet resultSet = null; + try { + //查询 + resultSet = getMetaData().getPrimaryKeys(getSchema(), getSchema(), table); + //映射 + return Mapping.convertList(resultSet, DmPrimaryKeyModel.class); + } catch (SQLException e) { + throw ExceptionUtils.mpe(e); + } finally { + JdbcUtils.close(resultSet, this.connection); + } } + /** + * 根据表名获取主键 + * + * @return {@link List} + * @throws QueryException QueryException + */ + @Override + public List getPrimaryKeys() throws QueryException { + ResultSet resultSet = null; + try { + // 由于单条循环查询存在性能问题,所以这里通过自定义SQL查询数据库主键信息 + String sql = String.format(DM_QUERY_PK_SQL, getSchema()); + resultSet = prepareStatement(sql).executeQuery(); + return Mapping.convertList(resultSet, DmPrimaryKeyModel.class); + } catch (SQLException e) { + throw new QueryException(e); + } finally { + JdbcUtils.close(resultSet); + } + } } diff --git a/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/DmColumnModel.java b/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/DmColumnModel.java new file mode 100644 index 0000000..b9cfffe --- /dev/null +++ b/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/DmColumnModel.java @@ -0,0 +1,177 @@ +/* + * screw-core - 简洁好用的数据库表结构文档生成工具 + * Copyright © 2020 SanLi (qinggang.zuo@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package cn.smallbun.screw.core.query.dm.model; + +import cn.smallbun.screw.core.mapping.MappingField; +import cn.smallbun.screw.core.metadata.Column; +import lombok.Data; + +/** + * oracle table column + * + * @author SanLi + * Created by qinggang.zuo@gmail.com / 2689170096@qq.com on 2020/3/27 8:44 + */ +@Data +public class DmColumnModel implements Column { + /** + * 表名称,它是引用属性的作用域(如果 DATA_TYPE 不是 REF,则为 null) + */ + @MappingField(value = "SCOPE_TABLE") + private Object scopeTable; + /** + * 表类别 + */ + @MappingField(value = "TABLE_CAT") + private Object tableCat; + /** + * 未被使用 + */ + @MappingField(value = "BUFFER_LENGTH") + private String bufferLength; + /** + * ISO 规则用于确定列是否包括 null。 + */ + @MappingField(value = "IS_NULLABLE") + private String isNullable; + /** + * 数据源依赖的类型名称,对于 UDT,该类型名称是完全限定的 + */ + @MappingField(value = "TABLE_NAME") + private String tableName; + /** + * 该列的默认值,当值在单引号内时应被解释为一个字符串(可为 null) + */ + @MappingField(value = "COLUMN_DEF") + private String columnDef; + /** + * 表的类别,它是引用属性的作用域(如果 DATA_TYPE 不是 REF,则为 null) + */ + @MappingField(value = "SCOPE_CATALOG") + private Object scopeCatalog; + /** + * 表模式 + */ + @MappingField(value = "TABLE_SCHEM") + private String tableSchem; + /** + * 列名称 + */ + @MappingField(value = "COLUMN_NAME") + private String columnName; + /** + * 是否允许使用 NULL。 + */ + @MappingField(value = "NULLABLE") + private String nullable; + /** + * 描述列的注释(可为 null) + */ + @MappingField(value = "REMARKS") + private String remarks; + /** + * 小数部分的位数。对于 DECIMAL_DIGITS 不适用的数据类型,则返回 Null。 + */ + @MappingField(value = "DECIMAL_DIGITS") + private String decimalDigits; + /** + * 基数(通常为 10 或 2) + */ + @MappingField(value = "NUM_PREC_RADIX") + private String numPrecRadix; + /** + * + */ + @MappingField(value = "SQL_DATETIME_SUB") + private String sqlDatetimeSub; + /** + * + */ + @MappingField(value = "IS_GENERATEDCOLUMN") + private String isGeneratedColumn; + /** + * 指示此列是否自动增加 + * YES --- 如果该列自动增加 + * NO --- 如果该列不自动增加 + */ + @MappingField(value = "IS_AUTOINCREMENT") + private String isAutoIncrement; + /** + * SQL数据类型 + */ + @MappingField(value = "SQL_DATA_TYPE") + private String sqlDataType; + /** + * 对于 char 类型,该长度是列中的最大字节数 + */ + @MappingField(value = "CHAR_OCTET_LENGTH") + private String charOctetLength; + /** + * 表中的列的索引(从 1 开始) + */ + @MappingField(value = "ORDINAL_POSITION") + private String ordinalPosition; + /** + * 表的模式,它是引用属性的作用域(如果 DATA_TYPE 不是 REF,则为 null) + */ + @MappingField(value = "SCOPE_SCHEMA") + private String scopeSchema; + /** + * 不同类型或用户生成 Ref 类型、来自 java.sql.Types 的 SQL 类型的源类型(如果 DATA_TYPE 不是 DISTINCT 或用户生成的 REF,则为 null) + */ + @MappingField(value = "SOURCE_DATA_TYPE") + private String sourceDataType; + /** + * 来自 java.sql.Types 的 SQL 类型 + */ + @MappingField(value = "DATA_TYPE") + private String dataType; + /** + * 数据源依赖的类型名称,对于 UDT,该类型名称是完全限定的 + */ + @MappingField(value = "TYPE_NAME") + private String typeName; + + /** + * 列表示给定列的指定列大小。 + * 对于数值数据,这是最大精度。 + * 对于字符数据,这是字符长度。 + * 对于日期时间数据类型,这是 String 表示形式的字符长度(假定允许的最大小数秒组件的精度)。 + * 对于二进制数据,这是字节长度。 + * 对于 ROWID 数据类型,这是字节长度。对于列大小不适用的数据类型,则返回 Null。 + */ + @MappingField(value = "COLUMN_SIZE") + private String columnSize; + + /** + * 是否主键 + */ + private String primaryKey; + /** + * 列类型(带长度) + */ + @MappingField(value = "COLUMN_TYPE") + private String columnType; + + /** + * 列长度 + */ + @MappingField(value = "COLUMN_LENGTH") + private String columnLength; + +} diff --git a/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/DmDatabaseModel.java b/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/DmDatabaseModel.java new file mode 100644 index 0000000..cf56bb0 --- /dev/null +++ b/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/DmDatabaseModel.java @@ -0,0 +1,39 @@ +/* + * screw-core - 简洁好用的数据库表结构文档生成工具 + * Copyright © 2020 SanLi (qinggang.zuo@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package cn.smallbun.screw.core.query.dm.model; + +import cn.smallbun.screw.core.mapping.MappingField; +import cn.smallbun.screw.core.metadata.Database; +import lombok.Data; + +/** + * 数据库信息 + * + * @author SanLi + * Created by qinggang.zuo@gmail.com / 2689170096@qq.com on 2020/3/17 20:26 + */ +@Data +public class DmDatabaseModel implements Database { + + private static final long serialVersionUID = 931210775266917894L; + /** + * 数据库名称 + */ + @MappingField(value = "TABLE_CAT") + private String database; +} diff --git a/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/DmPrimaryKeyModel.java b/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/DmPrimaryKeyModel.java new file mode 100644 index 0000000..a18af13 --- /dev/null +++ b/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/DmPrimaryKeyModel.java @@ -0,0 +1,58 @@ +/* + * screw-core - 简洁好用的数据库表结构文档生成工具 + * Copyright © 2020 SanLi (qinggang.zuo@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package cn.smallbun.screw.core.query.dm.model; + +import cn.smallbun.screw.core.mapping.MappingField; +import cn.smallbun.screw.core.metadata.PrimaryKey; +import lombok.Data; + +/** + * oracle table primary + * + * @author SanLi + * Created by qinggang.zuo@gmail.com / 2689170096@qq.com on 2020/3/27 11:11 + */ +@Data +public class DmPrimaryKeyModel implements PrimaryKey { + + /** + * 表名 + */ + @MappingField(value = "TABLE_NAME") + private String tableName; + /** + * pk name + */ + @MappingField(value = "PK_NAME") + private String pkName; + /** + * 表模式 + */ + @MappingField(value = "TABLE_SCHEM") + private String tableSchem; + /** + * 列名 + */ + @MappingField(value = "COLUMN_NAME") + private String columnName; + /** + * 键序列 + */ + @MappingField(value = "KEY_SEQ") + private String keySeq; +} diff --git a/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/DmTableModel.java b/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/DmTableModel.java new file mode 100644 index 0000000..a955cfb --- /dev/null +++ b/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/DmTableModel.java @@ -0,0 +1,57 @@ +/* + * screw-core - 简洁好用的数据库表结构文档生成工具 + * Copyright © 2020 SanLi (qinggang.zuo@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package cn.smallbun.screw.core.query.dm.model; + +import cn.smallbun.screw.core.mapping.MappingField; +import cn.smallbun.screw.core.metadata.Table; +import lombok.Data; + +/** + * oracle table + * + * @author SanLi + * Created by qinggang.zuo@gmail.com / 2689170096@qq.com on 2020/3/27 8:44 + */ +@Data +public class DmTableModel implements Table { + /** + * TABLE_CAT + */ + @MappingField(value = "TABLE_CAT") + private String tableCat; + /** + * 表名 + */ + @MappingField(value = "TABLE_NAME") + private String tableName; + /** + * 表模式 + */ + @MappingField(value = "TABLE_SCHEM") + private String tableSchem; + /** + * 表类型 + */ + @MappingField(value = "TABLE_TYPE") + private String tableType; + /** + * 备注 + */ + @MappingField(value = "REMARKS") + private String remarks; +} diff --git a/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/package-info.java b/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/package-info.java new file mode 100644 index 0000000..b58aac5 --- /dev/null +++ b/screw-core/src/main/java/cn/smallbun/screw/core/query/dm/model/package-info.java @@ -0,0 +1,23 @@ +/* + * screw-core - 简洁好用的数据库表结构文档生成工具 + * Copyright © 2020 SanLi (qinggang.zuo@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +/** + * DM Database query implement + * @author SanLi + * Created by qinggang.zuo@gmail.com / 2689170096@qq.com on 2020/6/19 16:00 + */ +package cn.smallbun.screw.core.query.dm.model; \ No newline at end of file