merge dev

This commit is contained in:
shanhexi
2023-09-06 21:33:04 +08:00
26 changed files with 412 additions and 313 deletions

View File

@@ -7,6 +7,8 @@ on:
push:
branches:
- "release_test"
- "release_test_2"
- "release_test_3"
# Workflow's jobs
# 一共需要3台电脑运行

View File

@@ -1,59 +1,68 @@
# 2.0.14
## 🐞 Bug Fixes
- Fix the issue of 'Oracle' query 'Blob' reporting errors
- Modify the paging logic and fix some SQL queries that cannot be queried
## 🐞 问题修复
- 修复 `Oracle` 查询 `Blob` 报错的问题
- 修改分页逻辑,修复部分 SQL 无法查询
# 2.0.13
## ⭐ New Features
## 🐞 Bug Fixes
- Fixed a bug where sql formatting was not selected
- Fixed open view lag issue
- Fixed a bug where sql formatting was not selected
- Fixed open view lag issue
- Solve the white screen problem of connected non-relational databases (non-relational databases are not supported)
## ⭐ 新特性
## 🐞 问题修复
- 修复不选中sql格式化的bug
- 修复不选中 sql 格式化的 bug
- 修复打开视图卡顿问题
- 解决已连接的非关系型数据库打开白屏问题(暂不支持非关系性数据库)
# 2.0.12
## ⭐ New Features
- 🔥Supports viewing views, functions, triggers, and procedures
- Support selected sql formatting
- 🔥Supports viewing views, functions, triggers, and procedures
- Support selected sql formatting
- Added new dark themes
## 🐞 Bug Fixes
- Fixed sql formatting failure issue
- Fixed an issue where locally stored theme colors and background colors are incompatible with the new version, causing page crashes
- Fixed an issue where locally stored theme colors and background colors are incompatible with the new version, causing
page crashes
- Logs desensitize sensitive data
- Fix the issue of 'CLOB' not displaying specific content [Issue #440](https://github.com/chat2db/Chat2DB/issues/440)
- Fix the issue of 'CLOB' not displaying specific content [Issue #440](https://github.com/chat2db/Chat2DB/issues/440)
- Fix the problem that non-Select does not display query results
- Fix the problem that Oracle cannot query without schema
- Fix the problem of special type of SQL execution error reporting
- Fix the problem that the test link is successful, but the error is reported when saving the link
## ⭐ 新特性
- 🔥支持查看视图、函数、触发器、存储过程
- 支持选中sql格式化
- 🔥 支持查看视图、函数、触发器、存储过程
- 支持选中 sql 格式化
- 增加新的暗色主题
## 🐞 问题修复
- 修复sql格式化会失败问题
- 修复 sql 格式化会失败问题
- 修复本地存储的主题色、背景色与新版本不兼容时会导致页面崩溃问题
- 日志对敏感数据进行脱敏
- 修复 `CLOB` 不展示具体内容的问题 [Issue #440](https://github.com/chat2db/Chat2DB/issues/440)
- 修复非Select不展示查询结果的问题
- 修复Oracle不带schema无法查询的问题
- 修复特殊类型的SQL执行报错的问题
- 修复 `CLOB` 不展示具体内容的问题 [Issue #440](https://github.com/chat2db/Chat2DB/issues/440)
- 修复非 Select 不展示查询结果的问题
- 修复 Oracle 不带 schema 无法查询的问题
- 修复特殊类型的 SQL 执行报错的问题
- 修复测试链接成功,但保存链接报错的问题
# 2.0.11
@@ -81,11 +90,11 @@
## 🐞 问题修复
- 新建、开打console时激活最新操作的console、记录最后一次使用的console
- edge等浏览器复制功能无法正常使用
- table搜索后导出ddl报错
- 新建、开打 console 时激活最新操作的 console、记录最后一次使用的 console
- edge 等浏览器复制功能无法正常使用
- table 搜索后导出 ddl 报错
- 增加表注释以及列字段类型和注释
- 当数据源添加了database默认选择第一个database
- 当数据源添加了 database 默认选择第一个 database
# 2.0.9
@@ -95,18 +104,18 @@
## 🐞 问题修复
- 修复windows闪退的问题
- 修复 windows 闪退的问题
# 2.0.8
## 🐞 Bug Fixes
- Repair the Scientific notation in some databases [Issue #378](https://github.com/chat2db/Chat2DB/issues/378)
- Repair the Scientific notation in some databases [Issue #378](https://github.com/chat2db/Chat2DB/issues/378)
- Fix some cases where data is not displayed
## 🐞 问题修复
- 修复部分数据库出现科学计数法的情况 [Issue #378](https://github.com/chat2db/Chat2DB/issues/378)
- 修复部分数据库出现科学计数法的情况 [Issue #378](https://github.com/chat2db/Chat2DB/issues/378)
- 修复部分情况数据不展示
# 2.0.7
@@ -125,18 +134,18 @@
## 🐞 问题修复
- 修复ai配置 [Issue #346](https://github.com/chat2db/Chat2DB/issues/346)
- 修复 ai 配置 [Issue #346](https://github.com/chat2db/Chat2DB/issues/346)
# 2.0.6
## 🐞 Bug Fixes
- Fixed: When there are too many tables under the selected library, the "New Console" button at the bottom
disappears [Issue #314](https://github.com/chat2db/Chat2DB/issues/314)
disappears [Issue #314](https://github.com/chat2db/Chat2DB/issues/314)
## 🐞 问题修复
- Fixed: 当选择的库下面表过多时最下面的“新建控制台”按钮消失 [Issue #314](https://github.com/chat2db/Chat2DB/issues/314)
- Fixed: 当选择的库下面表过多时最下面的“新建控制台”按钮消失 [Issue #314](https://github.com/chat2db/Chat2DB/issues/314)
# 2.0.5

View File

@@ -192,6 +192,8 @@ Follow our WeChat public account.
<a><img src="https://github.com/chat2db/Chat2DB/assets/22975773/e4239d29-1426-4361-bf57-f1b0b67d1281" width="40%"/></a>
Click and join <a href="https://discord.gg/dqae8nsC">discord server</a>
## ❤️ Acknowledgements
Thanks to all the students who contributed to Chat2DB~

View File

@@ -14,21 +14,15 @@
</div>
<div align="center">
<p align="center"><b>分享 Chat2DB </b></p>
<p align="center">
<a href="https://twitter.com/intent/tweet?text=Chat2DB-An%20intelligent%20and%20versatile%20general-purpose%20SQL%20client%20and%20reporting%20tool%20for%20databases%20which%20integrates%20ChatGPT%20capabilities.&url=https://github.com/chat2db/Chat2DB&hashtags=ChatGPT,AGI,SQL%20Client,Reporting%20tool" target="blank" > <img src="https://img.shields.io/twitter/follow/_Chat2DB?label=Share Repo on Twitter&style=social" alt=""/> </a>
<a href="https://t.me/share/url?text=Chat2DB-An%20intelligent%20and%20versatile%20general-purpose%20SQL%20client%20and%20reporting%20tool%20for%20databases%20which%20integrates%20ChatGPT%20capabilities.&url=https://github.com/chat2db/Chat2DB" target="_blank"><img src="https://img.shields.io/twitter/url?label=Telegram&logo=Telegram&style=social&url=https://github.com/chat2db/Chat2DB" alt="Share on Telegram"/></a>
<a href="https://api.whatsapp.com/send?text=Chat2DB-An%20intelligent%20and%20versatile%20general-purpose%20SQL%20client%20and%20reporting%20tool%20for%20databases%20which%20integrates%20ChatGPT%20capabilities.%20https://github.com/chat2db/Chat2DB"><img src="https://img.shields.io/twitter/url?label=whatsapp&logo=whatsapp&style=social&url=https://github.com/chat2db/Chat2DB" /></a>
<a href="https://www.reddit.com/submit?url=https://github.com/chat2db/Chat2DB&title=Chat2DB-An%20intelligent%20and%20versatile%20general-purpose%20SQL%20client%20and%20reporting%20tool%20for%20databases%20which%20integrates%20ChatGPT%20capabilities." target="blank"><img src="https://img.shields.io/twitter/url?label=Reddit&logo=Reddit&style=social&url=https://github.com/chat2db/Chat2DB" alt="Share on Reddit"/></a>
<a href="mailto:?subject=Check%20this%20GitHub%20repository%20out.&body=Chat2DB-An%20intelligent%20and%20versatile%20general-purpose%20SQL%20client%20and%20reporting%20tool%20for%20databases%20which%20integrates%20ChatGPT%20capabilities.%3A%0Ahttps://github.com/chat2db/Chat2DB" target="_blank"><img src="https://img.shields.io/twitter/url?label=Gmail&logo=Gmail&style=social&url=https://github.com/chat2db/Chat2DB"/></a>
</p>
**许可说明**: Chat2DB 开源内容仅供个人免费使用,如想将该项目用于商业用途,请先联系该项目作者。
Languages: 中文 [English](README.md)
Languages: 中文 [English](README.md)
如果觉得 Chat2DB 对您有帮助的话,请帮忙<a target="_blank" href='https://github.com/chat2db/Chat2db'><img src="https://img.shields.io/github/stars/chat2db/Chat2DB.svg?style=flat-square&label=Stars&logo=github" alt="github star"/></a>
的右上角点个⭐ Star 和 Fork,您的支持是 Chat2DB 变得更好最大的动力
</div>
## 案例视频
https://github.com/chat2db/Chat2DB/assets/22975773/b58db908-5768-4a71-aa30-135d202e505f

View File

@@ -34,7 +34,7 @@ public class DMMetaData extends DefaultMetaService implements MetaData {
}
private static String ROUTINES_SQL
= "SELECT OWNER, NAME, TEXT FROM ALL_SOURCE WHERE TYPE = '%s' AND NAME = '%s' AND NAME = '%s' ORDER BY LINE";
= "SELECT OWNER, NAME, TEXT FROM ALL_SOURCE WHERE TYPE = '%s' AND OWNER = '%s' AND NAME = '%s' ORDER BY LINE";
@Override
public Function function(Connection connection, @NotEmpty String databaseName, String schemaName,

View File

@@ -68,6 +68,10 @@ public class SqlServerMetaData extends DefaultMetaService implements MetaData {
= "SELECT type_desc, OBJECT_NAME(object_id) AS FunctionName, OBJECT_DEFINITION(object_id) AS "
+ "definition FROM sys.objects WHERE type_desc IN(%s) and name = '%s' ;";
private static String OBJECT_SQL
= "SELECT name FROM sys.objects WHERE type = '%s' and SCHEMA_ID = SCHEMA_ID('%s');";
@Override
public Function function(Connection connection, @NotEmpty String databaseName, String schemaName,
String functionName) {
@@ -87,8 +91,22 @@ public class SqlServerMetaData extends DefaultMetaService implements MetaData {
@Override
public List<Function> functions(Connection connection, String databaseName, String schemaName) {
List<Function> functions = SQLExecutor.getInstance().functions(connection, databaseName, schemaName);
return functions.stream().map(function -> removeVersion(function)).collect(Collectors.toList());
List<Function> functions = new ArrayList<>();
// List<Function> functions = SQLExecutor.getInstance().functions(connection, databaseName, schemaName);
// return functions.stream().map(function -> removeVersion(function)).collect(Collectors.toList());
String sql = String.format(OBJECT_SQL,"FN", schemaName);
return SQLExecutor.getInstance().execute(connection, sql, resultSet -> {
while (resultSet.next()) {
Function function = new Function();
function.setDatabaseName(databaseName);
function.setSchemaName(schemaName);
if (resultSet.next()) {
function.setFunctionName(resultSet.getString("name"));
}
functions.add(function);
}
return functions;
});
}
private Function removeVersion(Function function) {
@@ -103,8 +121,20 @@ public class SqlServerMetaData extends DefaultMetaService implements MetaData {
@Override
public List<Procedure> procedures(Connection connection, String databaseName, String schemaName) {
List<Procedure> procedures = SQLExecutor.getInstance().procedures(connection, databaseName, schemaName);
return procedures.stream().map(procedure -> removeVersion(procedure)).collect(Collectors.toList());
List<Procedure> procedures = new ArrayList<>();
String sql = String.format(OBJECT_SQL,"P", schemaName);
return SQLExecutor.getInstance().execute(connection, sql, resultSet -> {
while (resultSet.next()) {
Procedure procedure = new Procedure();
procedure.setDatabaseName(databaseName);
procedure.setSchemaName(schemaName);
if (resultSet.next()) {
procedure.setProcedureName(resultSet.getString("name"));
}
procedures.add(procedure);
}
return procedures;
});
}
private Procedure removeVersion(Procedure procedure) {

View File

@@ -87,12 +87,42 @@ public class DatabaseServiceImpl implements DatabaseService {
(key) -> param.isRefresh(), (key) -> {
Connection connection = param.getConnection() == null ? Chat2DBContext.getConnection()
: param.getConnection();
MetaData metaData = Chat2DBContext.getMetaData();
return metaData.schemas(connection, param.getDataBaseName());
return getSchemaList(param.getDataBaseName(), connection);
});
return ListResult.of(schemas);
}
private List<Schema> getSchemaList(String databaseName, Connection connection) {
MetaData metaData = Chat2DBContext.getMetaData();
List<Schema> schemas = metaData.schemas(connection,databaseName);
sortSchema(schemas,connection);
return schemas;
}
private void sortSchema(List<Schema> schemas,Connection connection) {
if (CollectionUtils.isEmpty(schemas)) {
return;
}
String ulr = null;
try {
ulr = connection.getMetaData().getURL();
} catch (SQLException e) {
log.error("get url error", e);
}
// If the database name contains the name of the current database, the current database is placed in the first place
int num = -1;
for (int i = 0; i < schemas.size(); i++) {
if (StringUtils.isNotBlank(ulr) && ulr.contains(schemas.get(i).getName())) {
num = i;
break;
}
}
if (num != -1 && num != 0) {
Collections.swap(schemas, num, 0);
}
}
@Override
public DataResult<MetaSchema> queryDatabaseSchema(MetaDataQueryParam param) {
MetaSchema metaSchema = new MetaSchema();

View File

@@ -34,7 +34,6 @@ import ai.chat2db.spi.util.SqlUtils;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@@ -67,7 +66,7 @@ public class DlTemplateServiceImpl implements DlTemplateService {
ListResult<ExecuteResult> listResult = ListResult.of(result);
// 执行sql
for (String originalSql : sqlList) {
ExecuteResult executeResult = executeSQL(originalSql,dbType,param);
ExecuteResult executeResult = executeSQL(originalSql, dbType, param);
result.add(executeResult);
if (!executeResult.getSuccess()) {
listResult.setSuccess(false);
@@ -78,53 +77,44 @@ public class DlTemplateServiceImpl implements DlTemplateService {
return listResult;
}
private ExecuteResult executeSQL(String originalSql,DbType dbType,DlExecuteParam param) {
String sql = originalSql;
int pageNo = 0;
private ExecuteResult executeSQL(String originalSql, DbType dbType, DlExecuteParam param) {
int pageNo = 1;
int pageSize = 0;
Integer offset = null;
Integer count = null;
String sqlType = SqlTypeEnum.UNKNOWN.getCode();
// 解析sql分页
SQLStatement sqlStatement;
boolean autoLimit = false;
try {
sqlStatement = SQLUtils.parseSingleStatement(sql, dbType);
sqlStatement = SQLUtils.parseSingleStatement(originalSql, dbType);
// 是否需要代码帮忙分页
if (sqlStatement instanceof SQLSelectStatement) {
// 不是查询全部数据 而且 用户自己没有传分页
autoLimit = BooleanUtils.isNotTrue(param.getPageSizeAll()) && SQLUtils.getLimit(sqlStatement,
dbType)
== null;
if (autoLimit) {
pageNo = Optional.ofNullable(param.getPageNo()).orElse(1);
pageSize = Optional.ofNullable(param.getPageSize()).orElse(EasyToolsConstant.MAX_PAGE_SIZE);
int offset = (pageNo - 1) * pageSize;
try {
sql = PagerUtils.limit(sql, dbType, offset, pageSize);
} catch (Exception e) {
autoLimit = false;
}
}
pageNo = Optional.ofNullable(param.getPageNo()).orElse(1);
pageSize = Optional.ofNullable(param.getPageSize()).orElse(EasyToolsConstant.MAX_PAGE_SIZE);
offset = (pageNo - 1) * pageSize;
count = pageSize;
sqlType = SqlTypeEnum.SELECT.getCode();
}
} catch (ParserException e) {
log.warn("解析sql失败:{}", sql, e);
log.warn("解析sql失败:{}", originalSql, e);
}
ExecuteResult executeResult = execute(sql);
ExecuteResult executeResult = execute(originalSql, offset, count);
executeResult.setSqlType(sqlType);
executeResult.setOriginalSql(originalSql);
// 自动分页
if (autoLimit) {
if (SqlTypeEnum.SELECT.getCode().equals(sqlType)) {
executeResult.setPageNo(pageNo);
executeResult.setPageSize(pageSize);
executeResult.setHasNextPage(
CollectionUtils.size(executeResult.getDataList()) >= executeResult.getPageSize());
} else {
executeResult.setPageNo(1);
executeResult.setPageNo(pageNo);
executeResult.setPageSize(CollectionUtils.size(executeResult.getDataList()));
executeResult.setHasNextPage(Boolean.FALSE);
}
// Splice row numbers
List<Header> newHeaderList = new ArrayList<>();
newHeaderList.add(Header.builder()
@@ -150,9 +140,6 @@ public class DlTemplateServiceImpl implements DlTemplateService {
return executeResult;
}
private String calculateFuzzyTotal(int pageNo, int pageSize, ExecuteResult executeResult) {
int dataSize = CollectionUtils.size(executeResult.getDataList());
if (pageSize <= 0) {
@@ -179,7 +166,7 @@ public class DlTemplateServiceImpl implements DlTemplateService {
throw new BusinessException("dataSource.sqlAnalysisError");
}
sql = PagerUtils.count(sql, dbType);
ExecuteResult executeResult = execute(sql);
ExecuteResult executeResult = execute(sql, null, null);
List<List<String>> dataList = executeResult.getDataList();
if (CollectionUtils.isEmpty(dataList)) {
@@ -194,10 +181,10 @@ public class DlTemplateServiceImpl implements DlTemplateService {
return DataResult.of(Long.valueOf(count));
}
private ExecuteResult execute(String sql) {
private ExecuteResult execute(String sql, Integer offset, Integer count) {
ExecuteResult executeResult;
try {
executeResult = SQLExecutor.getInstance().execute(Chat2DBContext.getConnection(), sql);
executeResult = SQLExecutor.getInstance().execute(sql, Chat2DBContext.getConnection(), true, offset, count);
} catch (SQLException e) {
log.warn("执行sql:{}异常", sql, e);
executeResult = ExecuteResult.builder()

View File

@@ -0,0 +1,25 @@
package ai.chat2db.server.tools.common.util;
public class EasyIntegerUtils {
/**
* 判断2个布尔值是否相同
*
* @param b1
* @param b2
* @param defaultValue 默认值 ,假设b1 b2为空的情况下 取哪个默认值
* @return
*/
public static boolean equals(Integer b1, Integer b2, Integer defaultValue) {
if (b1 == b2) {
return true;
}
if (b1 == null) {
b1 = defaultValue;
}
if (b2 == null) {
b2 = defaultValue;
}
return b1 == b2;
}
}

View File

@@ -89,7 +89,7 @@ public class ChatController {
/**
* chat的超时时间
*/
private static final Long CHAT_TIMEOUT = Duration.ofMinutes(10).toMillis();
private static final Long CHAT_TIMEOUT = Duration.ofMinutes(50).toMillis();
/**
* 提示语最大token数

View File

@@ -54,7 +54,7 @@ public class RestAIEventSourceListener extends EventSourceListener {
}
Message message = new Message();
if (StringUtils.isNotBlank(data)) {
message.setContent(data);
message.setContent(data.replace("\"", ""));
sseEmitter.send(SseEmitter.event()
.id(id)
.data(message)

View File

@@ -35,7 +35,7 @@ public class ColumnRequest {
/**
* 是否为空
*/
private Boolean nullable;
private Integer nullable;
/**
* 是否主键

View File

@@ -38,7 +38,7 @@ public class ColumnVO {
/**
* 是否为空
*/
private Boolean nullable;
private Integer nullable;
/**
* 是否主键

View File

@@ -3,7 +3,6 @@ package ai.chat2db.spi.jdbc;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import ai.chat2db.spi.MetaData;
import ai.chat2db.spi.model.Database;
@@ -15,7 +14,6 @@ import ai.chat2db.spi.model.TableColumn;
import ai.chat2db.spi.model.TableIndex;
import ai.chat2db.spi.model.Trigger;
import ai.chat2db.spi.sql.SQLExecutor;
import org.apache.commons.beanutils.BeanUtils;
/**
* @author jipengfei
@@ -24,25 +22,12 @@ import org.apache.commons.beanutils.BeanUtils;
public class DefaultMetaService implements MetaData {
@Override
public List<Database> databases(Connection connection) {
List<String> dataBases = SQLExecutor.getInstance().databases(connection);
return dataBases.stream().map(str -> Database.builder().name(str).build()).collect(Collectors.toList());
return SQLExecutor.getInstance().databases(connection);
}
@Override
public List<Schema> schemas(Connection connection,String databaseName) {
List<Map<String, String>> maps = SQLExecutor.getInstance().schemas(connection, databaseName, null);
return maps.stream().map(map -> map2Schema(map)).collect(Collectors.toList());
}
private Schema map2Schema(Map<String, String> map) {
Schema schema = new Schema();
try {
BeanUtils.populate(schema, map);
} catch (Exception e) {
}
return schema;
return SQLExecutor.getInstance().schemas(connection, databaseName, null);
}
@Override

View File

@@ -4,6 +4,7 @@ import java.io.Serializable;
import java.util.List;
import ai.chat2db.server.tools.base.constant.EasyToolsConstant;
import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -23,6 +24,7 @@ public class Database implements Serializable {
/**
* 数据库名字
*/
@JsonAlias({"TABLE_CAT"})
private String name;
/**

View File

@@ -1,6 +1,7 @@
package ai.chat2db.spi.model;
import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -26,16 +27,22 @@ public class Function {
//SPECIFIC_NAME String => the name which uniquely identifies this function within its schema. This is a user specified, or DBMS generated, name that may be different then the FUNCTION_NAME for example with overload functions
//
@JsonAlias({"FUNCTION_CAT"})
private String databaseName;
@JsonAlias({"FUNCTION_SCHEM"})
private String schemaName;
@JsonAlias({"FUNCTION_NAME"})
private String functionName;
@JsonAlias({"REMARKS"})
private String remarks;
@JsonAlias({"FUNCTION_TYPE"})
private Short functionType;
@JsonAlias({"SPECIFIC_NAME"})
private String specificName;
private String functionBody;

View File

@@ -1,6 +1,7 @@
package ai.chat2db.spi.model;
import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -26,16 +27,24 @@ public class Procedure {
//SPECIFIC_NAME String => the name which uniquely identifies this procedure within its schema. This is a user specified, or DBMS generated, name that may be different then the PROCEDURE_NAME for example with overload procedures
//
@JsonAlias({"PROCEDURE_CAT"})
private String databaseName;
@JsonAlias({"PROCEDURE_SCHEM"})
private String schemaName;
@JsonAlias({"PROCEDURE_NAME"})
private String procedureName;
@JsonAlias({"REMARKS"})
private String remarks;
@JsonAlias({"PROCEDURE_TYPE"})
private Short procedureType;
@JsonAlias({"SPECIFIC_NAME"})
private String specificName;
private String procedureBody;

View File

@@ -4,6 +4,7 @@ package ai.chat2db.spi.model;
import java.io.Serializable;
import ai.chat2db.server.tools.base.constant.EasyToolsConstant;
import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -23,9 +24,11 @@ public class Schema implements Serializable {
/**
* databaseName
*/
@JsonAlias({"TABLE_CATALOG"})
private String databaseName;
/**
* 数据名字
*/
@JsonAlias({"TABLE_SCHEM"})
private String name;
}

View File

@@ -3,6 +3,7 @@ package ai.chat2db.spi.model;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -22,16 +23,21 @@ public class Table {
/**
* 表名
*/
@JsonAlias({"TABLE_NAME"})
private String name;
/**
* 描述
*/
@JsonAlias({"REMARKS"})
private String comment;
/**
* DB 名
*/
@JsonAlias({"TABLE_SCHEM"})
private String schemaName;
/**
@@ -52,11 +58,13 @@ public class Table {
/**
* 数据库名
*/
@JsonAlias("TABLE_CAT")
private String databaseName;
/**
* 表类型
*/
@JsonAlias("TABLE_TYPE")
private String type;
/**

View File

@@ -1,5 +1,6 @@
package ai.chat2db.spi.model;
import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -24,6 +25,7 @@ public class TableColumn {
/**
* 列名
*/
@JsonAlias({"COLUMN_NAME"})
private String name;
/**
@@ -35,18 +37,24 @@ public class TableColumn {
* 列的类型
* 比如 varchar(100) ,double(10,6)
*/
@JsonAlias({"TYPE_NAME"})
private String columnType;
/**
* 列的数据类型
* 比如 varchar ,double
*/
@JsonAlias({"DATA_TYPE"})
private Integer dataType;
/**
* 默认值
*/
@JsonAlias({"COLUMN_DEF"})
private String defaultValue;
/**
@@ -58,6 +66,7 @@ public class TableColumn {
/**
* 注释
*/
@JsonAlias({"REMARKS"})
private String comment;
/**
@@ -68,11 +77,13 @@ public class TableColumn {
/**
* 空间名
*/
@JsonAlias({"TABLE_SCHEM"})
private String schemaName;
/**
* 数据库名
*/
@JsonAlias({"TABLE_CAT"})
private String databaseName;
/**
@@ -83,6 +94,8 @@ public class TableColumn {
/**
* column size.
*/
@JsonAlias({"COLUMN_SIZE"})
private Integer columnSize;
/**
@@ -93,11 +106,15 @@ public class TableColumn {
/**
* the number of fractional digits. Null is returned for data types where DECIMAL_DIGITS is not applicable.
*/
@JsonAlias({"DECIMAL_DIGITS"})
private Integer decimalDigits;
/**
* Radix (typically either 10 or 2)
*/
@JsonAlias({"NUM_PREC_RADIX"})
private Integer numPrecRadix;
/**
@@ -127,12 +144,16 @@ public class TableColumn {
/**
* index of column in table (starting at 1)
*/
@JsonAlias({"ORDINAL_POSITION"})
private Integer ordinalPosition;
/**
* ISO rules are used to determine the nullability for a column.
*/
private Boolean nullable;
@JsonAlias({"NULLABLE"})
private Integer nullable;
/**
* String => Indicates whether this is a generated column

View File

@@ -1,6 +1,7 @@
package ai.chat2db.spi.model;
import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -20,11 +21,13 @@ public class TableIndexColumn {
/**
* 索引名称
*/
@JsonAlias({"INDEX_NAME"})
private String indexName;
/**
* 表名
*/
@JsonAlias ({"TABLE_NAME"})
private String tableName;
/**
@@ -42,17 +45,18 @@ public class TableIndexColumn {
/**
* 列名
*/
@JsonAlias({"COLUMN_NAME"})
private String columnName;
/**
* 顺序
*/
@JsonAlias({"ORDINAL_POSITION"})
private Short ordinalPosition;
/**
* 排序
*
* @see CollationEnum
*/
private String collation;
@@ -60,41 +64,49 @@ public class TableIndexColumn {
/**
* 索引所属schema
*/
@JsonAlias({"TABLE_SCHEM"})
private String schemaName;
/**
* 数据库名
*/
@JsonAlias({"TABLE_CAT"})
private String databaseName;
/**
* 是否唯一
*/
@JsonAlias({"NON_UNIQUE"})
private Boolean nonUnique;
/**
* index catalog (may be null); null when TYPE is tableIndexStatistic
*/
@JsonAlias({"INDEX_QUALIFIER"})
private String indexQualifier;
/**
* ASC_OR_DESC String => column sort sequence, "A" => ascending, "D" => descending, may be null if sort sequence is not supported; null when TYPE is tableIndexStatistic
*/
@JsonAlias({"ASC_OR_DESC"})
private String ascOrDesc;
/**
* CARDINALITY long => When TYPE is tableIndexStatistic, then this is the number of rows in the table; otherwise, it is the number of unique values in the index.
*/
@JsonAlias({"CARDINALITY"})
private Long cardinality;
/**
* When TYPE is tableIndexStatistic then this is the number of pages used for the table, otherwise it is the number of pages used for the current index.
*/
@JsonAlias({"PAGES"})
private Long pages;
/**
* Filter condition, if any. (may be null)
*/
@JsonAlias({"FILTER_CONDITION"})
private String filterCondition;
}

View File

@@ -78,13 +78,16 @@ public class IDriverManager {
if (url == null) {
throw new SQLException("The url cannot be null", "08001");
}
SQLException reason = null;
DriverEntry driverEntry = DRIVER_ENTRY_MAP.get(driver.getJdbcDriver());
if (driverEntry == null) {
driverEntry = getJDBCDriver(driver);
}
try {
return driverEntry.getDriver().connect(url, info);
Connection connection = driverEntry.getDriver().connect(url, info);
if(connection == null){
throw new SQLException("driver.connect return null , No suitable driver found for url " +url ,"08001");
}
return connection;
} catch (SQLException var7) {
Connection con = tryConnectionAgain(driverEntry, url, info);
if (con != null) {

View File

@@ -5,22 +5,14 @@ import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import ai.chat2db.server.tools.base.constant.EasyToolsConstant;
import ai.chat2db.server.tools.common.util.I18nUtils;
import ai.chat2db.spi.model.ExecuteResult;
import ai.chat2db.spi.model.Header;
import ai.chat2db.spi.model.Procedure;
import ai.chat2db.spi.model.Table;
import ai.chat2db.spi.model.TableColumn;
import ai.chat2db.spi.model.TableIndex;
import ai.chat2db.spi.model.TableIndexColumn;
import ai.chat2db.spi.model.*;
import ai.chat2db.spi.util.ResultSetUtils;
import cn.hutool.core.date.TimeInterval;
import com.google.common.collect.Lists;
@@ -29,18 +21,10 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.util.Assert;
import static ai.chat2db.spi.util.ResultSetUtils.buildColumn;
import static ai.chat2db.spi.util.ResultSetUtils.buildFunction;
import static ai.chat2db.spi.util.ResultSetUtils.buildProcedure;
import static ai.chat2db.spi.util.ResultSetUtils.buildTable;
import static ai.chat2db.spi.util.ResultSetUtils.buildTableIndexColumn;
/**
* Dbhub 统一数据库连接管理
* TODO 长时间不用连接可以关闭,待优化
*
* @author jipengfei
* @version : DbhubDataSource.java
*/
@Slf4j
public class SQLExecutor {
@@ -56,10 +40,6 @@ public class SQLExecutor {
return INSTANCE;
}
//public Connection connection throws SQLException {
// return Chat2DBContext.connection;
//}
public void close() {
}
@@ -165,17 +145,23 @@ public class SQLExecutor {
* @throws SQLException
*/
public ExecuteResult execute(final String sql, Connection connection) throws SQLException {
return execute(sql, connection, true);
return execute(sql, connection, true, null, null);
}
/**
* 执行sql
*
* @param sql
* @param connection
* @param limitRowSize
* @param offset
* @param count
* @return
* @throws SQLException
*/
public ExecuteResult execute(final String sql, Connection connection, boolean limitSize) throws SQLException {
public ExecuteResult execute(final String sql, Connection connection, boolean limitRowSize, Integer offset,
Integer count)
throws SQLException {
Assert.notNull(sql, "SQL must not be null");
log.info("execute:{}", sql);
@@ -209,13 +195,22 @@ public class SQLExecutor {
List<List<String>> dataList = Lists.newArrayList();
executeResult.setDataList(dataList);
int n = 0;
while (rs.next() && n < EasyToolsConstant.MAX_PAGE_SIZE) {
n++;
if (offset == null || offset < 0) {
offset = 0;
}
int rowNumber = 0;
int rowCount = 1;
while (rs.next()) {
if (rowNumber++ < offset) {
continue;
}
List<String> row = Lists.newArrayListWithExpectedSize(col);
dataList.add(row);
for (int i = 1; i <= col; i++) {
row.add(ai.chat2db.spi.util.JdbcUtils.getResultSetValue(rs, i, limitSize));
row.add(ai.chat2db.spi.util.JdbcUtils.getResultSetValue(rs, i, limitRowSize));
}
if (count != null && count > 0 && rowCount++ >= count) {
break;
}
}
executeResult.setDuration(timeInterval.interval());
@@ -240,7 +235,7 @@ public class SQLExecutor {
* @throws SQLException
*/
public ExecuteResult execute(Connection connection, String sql) throws SQLException {
return execute(sql, connection, true);
return execute(sql, connection, true, null, null);
}
/**
@@ -249,58 +244,46 @@ public class SQLExecutor {
* @param connection
* @return
*/
public List<String> databases(Connection connection) {
List<String> tables = Lists.newArrayList();
public List<Database> databases(Connection connection) {
try (ResultSet resultSet = connection.getMetaData().getCatalogs();) {
if (resultSet != null) {
while (resultSet.next()) {
tables.add(resultSet.getString("TABLE_CAT"));
}
}
return ResultSetUtils.toObjectList(resultSet, Database.class);
} catch (SQLException e) {
throw new RuntimeException(e);
}
return tables;
}
/**
* 获取所有的schema
*
* @param connection
* @param databaseName
* @param schemaName
* @return
* Retrieves the schema names available in this database. The results are ordered by TABLE_CATALOG and TABLE_SCHEM.
* The schema columns are:
* TABLE_SCHEM String => schema name
* TABLE_CATALOG String => catalog name (may be null)
* Params:
* catalog – a catalog name; must match the catalog name as it is stored in the database;"" retrieves those without
* a catalog; null means catalog name should not be used to narrow down the search. schemaPattern – a schema name;
* must match the schema name as it is stored in the database; null means schema name should not be used to narrow
* down the search.
* Returns:
* a ResultSet object in which each row is a schema description
* Throws:
* SQLException – if a database access error occurs
* Since:
* 1.6
* See Also:
* getSearchStringEscape
*/
public List<Map<String, String>> schemas(Connection connection, String databaseName, String schemaName) {
List<Map<String, String>> schemaList = Lists.newArrayList();
public List<Schema> schemas(Connection connection, String databaseName, String schemaName) {
if (StringUtils.isEmpty(databaseName) && StringUtils.isEmpty(schemaName)) {
try (ResultSet resultSet = connection.getMetaData().getSchemas()) {
if (resultSet != null) {
while (resultSet.next()) {
Map<String, String> map = new HashMap<>();
map.put("name", resultSet.getString("TABLE_SCHEM"));
map.put("databaseName", resultSet.getString("TABLE_CATALOG"));
schemaList.add(map);
}
}
return ResultSetUtils.toObjectList(resultSet, Schema.class);
} catch (SQLException e) {
throw new RuntimeException("Get schemas error", e);
}
return schemaList;
}
try (ResultSet resultSet = connection.getMetaData().getSchemas(databaseName, schemaName)) {
if (resultSet != null) {
while (resultSet.next()) {
Map<String, String> map = new HashMap<>();
map.put("name", resultSet.getString("TABLE_SCHEM"));
map.put("databaseName", resultSet.getString("TABLE_CATALOG"));
schemaList.add(map);
}
}
return ResultSetUtils.toObjectList(resultSet, Schema.class);
} catch (SQLException e) {
throw new RuntimeException("Get schemas error", e);
}
return schemaList;
}
/**
@@ -315,23 +298,12 @@ public class SQLExecutor {
*/
public List<Table> tables(Connection connection, String databaseName, String schemaName, String tableName,
String types[]) {
List<Table> tables = Lists.newArrayList();
int n = 0;
try (ResultSet resultSet = connection.getMetaData().getTables(databaseName, schemaName, tableName,
types)) {
if (resultSet != null) {
while (resultSet.next()) {
n++;
tables.add(buildTable(resultSet));
if (n >= 1000) {// 最多只取1000条
break;
}
}
}
return ResultSetUtils.toObjectList(resultSet, Table.class);
} catch (SQLException e) {
throw new RuntimeException(e);
}
return tables;
}
/**
@@ -346,40 +318,29 @@ public class SQLExecutor {
*/
public List<TableColumn> columns(Connection connection, String databaseName, String schemaName, String tableName,
String columnName) {
List<TableColumn> tableColumns = Lists.newArrayList();
try (ResultSet resultSet = connection.getMetaData().getColumns(databaseName, schemaName, tableName,
columnName)) {
if (resultSet != null) {
while (resultSet.next()) {
tableColumns.add(buildColumn(resultSet));
}
}
return ResultSetUtils.toObjectList(resultSet, TableColumn.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
return tableColumns;
}
/**
* 获取所有的数据库表索引
* get all table index info
*
* @param connection
* @param databaseName
* @param schemaName
* @param tableName
* @return
* @param connection connection
* @param databaseName databaseName of the index
* @param schemaName schemaName of the index
* @param tableName tableName of the index
* @return List<TableIndex> table index list
*/
public List<TableIndex> indexes(Connection connection, String databaseName, String schemaName, String tableName) {
List<TableIndex> tableIndices = Lists.newArrayList();
try (ResultSet resultSet = connection.getMetaData().getIndexInfo(databaseName, schemaName, tableName,
false,
false)) {
List<TableIndexColumn> tableIndexColumns = Lists.newArrayList();
while (resultSet != null && resultSet.next()) {
tableIndexColumns.add(buildTableIndexColumn(resultSet));
}
List<TableIndexColumn> tableIndexColumns = ResultSetUtils.toObjectList(resultSet, TableIndexColumn.class);
tableIndexColumns.stream().filter(c -> c.getIndexName() != null).collect(
Collectors.groupingBy(TableIndexColumn::getIndexName)).entrySet()
.stream().forEach(entry -> {
@@ -400,44 +361,36 @@ public class SQLExecutor {
}
/**
* 获取所有的函数
* Get all functions available in a catalog.
*
* @param connection
* @param databaseName
* @param schemaName
* @return
* @param connection connection
* @param databaseName databaseName of the function
* @param schemaName schemaName of the function
* @return List<Function>
*/
public List<ai.chat2db.spi.model.Function> functions(Connection connection, String databaseName,
String schemaName) {
List<ai.chat2db.spi.model.Function> functions = Lists.newArrayList();
try (ResultSet resultSet = connection.getMetaData().getFunctions(databaseName, schemaName, null);) {
while (resultSet != null && resultSet.next()) {
functions.add(buildFunction(resultSet));
}
return ResultSetUtils.toObjectList(resultSet, ai.chat2db.spi.model.Function.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
return functions;
}
/**
* 获取所有的存储过程
* procedure list
*
* @param connection
* @param databaseName
* @param schemaName
* @return
* @param connection connection
* @param databaseName databaseName
* @param schemaName schemaName
* @return List<Procedure>
*/
public List<Procedure> procedures(Connection connection, String databaseName, String schemaName) {
List<Procedure> procedures = Lists.newArrayList();
try (ResultSet resultSet = connection.getMetaData().getProcedures(databaseName, schemaName, null)) {
while (resultSet != null && resultSet.next()) {
procedures.add(buildProcedure(resultSet));
}
return ResultSetUtils.toObjectList(resultSet, Procedure.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
return procedures;
}
}

View File

@@ -1,6 +1,7 @@
package ai.chat2db.spi.util;
import java.math.BigDecimal;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.ResultSet;
@@ -144,24 +145,51 @@ public class JdbcUtils {
if (obj == null) {
return null;
}
if (obj instanceof BigDecimal bigDecimal) {
return bigDecimal.toPlainString();
} else if (obj instanceof Double d) {
return BigDecimal.valueOf(d).toPlainString();
} else if (obj instanceof Float f) {
return BigDecimal.valueOf(f).toPlainString();
} else if (obj instanceof Clob) {
return largeString(rs, index, limitSize);
} else if (obj instanceof byte[]) {
return largeString(rs, index, limitSize);
try {
if (obj instanceof BigDecimal bigDecimal) {
return bigDecimal.toPlainString();
} else if (obj instanceof Double d) {
return BigDecimal.valueOf(d).toPlainString();
} else if (obj instanceof Float f) {
return BigDecimal.valueOf(f).toPlainString();
} else if (obj instanceof Clob) {
return largeString(rs, index, limitSize);
} else if (obj instanceof byte[]) {
return largeString(rs, index, limitSize);
} else if (obj instanceof Blob blob) {
return largeStringBlob(blob, limitSize);
}
return rs.getString(index);
} catch (Exception e) {
log.warn("解析数失败:{},{}", index, obj, e);
return obj.toString();
}
return rs.getString(index);
}
private static String largeStringBlob(Blob blob, boolean limitSize) throws SQLException {
if (blob == null) {
return null;
}
int length = Math.toIntExact(blob.length());
if (limitSize && length > MAX_RESULT_SIZE) {
length = Math.toIntExact(MAX_RESULT_SIZE);
}
byte[] data = blob.getBytes(1, length);
String result = new String(data);
if (length > MAX_RESULT_SIZE) {
return "[ " + DataSizeUtil.format(MAX_RESULT_SIZE) + " of " + DataSizeUtil.format(length)
+ " ,"
+ I18nUtils.getMessage("execute.exportCsv") + " ] " + result;
}
return result;
}
private static String largeString(ResultSet rs, int index, boolean limitSize) throws SQLException {
String result = rs.getString(index);
if (result == null) {
return null;
}
if (!limitSize) {
return result;

View File

@@ -4,8 +4,16 @@ package ai.chat2db.spi.util;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ai.chat2db.spi.model.*;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.google.common.collect.Lists;
import static ai.chat2db.spi.util.JdbcUtils.getResultSetValue;
/**
* @author jipengfei
@@ -13,99 +21,79 @@ import ai.chat2db.spi.model.*;
*/
public class ResultSetUtils {
public static ai.chat2db.spi.model.Function buildFunction(ResultSet resultSet) {
ai.chat2db.spi.model.Function function
= new ai.chat2db.spi.model.Function();
public static <T> T toObject(ResultSet rs, Class<T> clazz) {
try {
function.setDatabaseName(getString(resultSet, "FUNCTION_CAT"));
function.setSchemaName(getString(resultSet, "FUNCTION_SCHEM"));
function.setFunctionName(getString(resultSet, "FUNCTION_NAME"));
function.setRemarks(getString(resultSet, "REMARKS"));
function.setFunctionType(resultSet.getShort("FUNCTION_TYPE"));
function.setSpecificName(getString(resultSet, "SPECIFIC_NAME"));
if (rs == null || clazz == null) {
return null;
}
ResultSetMetaData resultSetMetaData = rs.getMetaData();
int col = resultSetMetaData.getColumnCount();
List<String> headerList = getRsHeader(rs);
Map<String, Object> map = new HashMap<>();
for (int i = 1; i <= col; i++) {
map.put(headerList.get(i), getResultSetValue(rs, i, true));
}
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//mapper.configure(DeserializationFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
return mapper.convertValue(map, clazz);
} catch (SQLException e) {
throw new RuntimeException(e);
}
return function;
}
public static Procedure buildProcedure(ResultSet resultSet) {
Procedure procedure = new Procedure();
private static List<String> getRsHeader(ResultSet rs) {
try {
procedure.setDatabaseName(getString(resultSet, "PROCEDURE_CAT"));
procedure.setSchemaName(getString(resultSet, "PROCEDURE_SCHEM"));
procedure.setProcedureName(getString(resultSet, "PROCEDURE_NAME"));
procedure.setRemarks(getString(resultSet, "REMARKS"));
procedure.setProcedureType(resultSet.getShort("PROCEDURE_TYPE"));
procedure.setSpecificName(getString(resultSet, "SPECIFIC_NAME"));
ResultSetMetaData resultSetMetaData = rs.getMetaData();
int col = resultSetMetaData.getColumnCount();
List<String> headerList = Lists.newArrayListWithExpectedSize(col);
for (int i = 1; i <= col; i++) {
headerList.add(getColumnName(resultSetMetaData, i));
}
return headerList;
} catch (SQLException e) {
throw new RuntimeException(e);
}
return procedure;
}
public static TableIndexColumn buildTableIndexColumn(ResultSet resultSet) throws SQLException {
TableIndexColumn tableIndexColumn = new TableIndexColumn();
tableIndexColumn.setColumnName(getString(resultSet, "COLUMN_NAME"));
tableIndexColumn.setIndexName(getString(resultSet, "INDEX_NAME"));
tableIndexColumn.setAscOrDesc(getString(resultSet, "ASC_OR_DESC"));
tableIndexColumn.setCardinality(resultSet.getLong("CARDINALITY"));
tableIndexColumn.setPages(resultSet.getLong("PAGES"));
tableIndexColumn.setFilterCondition(getString(resultSet, "FILTER_CONDITION"));
tableIndexColumn.setIndexQualifier(getString(resultSet, "INDEX_QUALIFIER"));
// tableIndexColumn.setIndexType(resultSet.getShort("TYPE"));
tableIndexColumn.setNonUnique(resultSet.getBoolean("NON_UNIQUE"));
tableIndexColumn.setOrdinalPosition(resultSet.getShort("ORDINAL_POSITION"));
tableIndexColumn.setDatabaseName(getString(resultSet, "TABLE_CAT"));
tableIndexColumn.setSchemaName(getString(resultSet, "TABLE_SCHEM"));
tableIndexColumn.setTableName(getString(resultSet, "TABLE_NAME"));
return tableIndexColumn;
}
public static TableColumn buildColumn(ResultSet resultSet) throws SQLException {
TableColumn tableColumn = new TableColumn();
tableColumn.setDatabaseName(getString(resultSet, "TABLE_CAT"));
tableColumn.setSchemaName(getString(resultSet, "TABLE_SCHEM"));
tableColumn.setTableName(getString(resultSet, "TABLE_NAME"));
tableColumn.setName(getString(resultSet, "COLUMN_NAME"));
tableColumn.setComment(getString(resultSet, "REMARKS"));
tableColumn.setDefaultValue(getString(resultSet, "COLUMN_DEF"));
tableColumn.setColumnType(getString(resultSet, "TYPE_NAME"));
tableColumn.setColumnSize(resultSet.getInt("COLUMN_SIZE"));
tableColumn.setDataType(resultSet.getInt("DATA_TYPE"));
tableColumn.setNullable(resultSet.getInt("NULLABLE") == 1);
tableColumn.setOrdinalPosition(resultSet.getInt("ORDINAL_POSITION"));
//tableColumn.setAutoIncrement("YES".equals(getString,resultSet,"IS_AUTOINCREMENT")));
//tableColumn.setGeneratedColumn("YES".equals(getString,resultSet,"IS_GENERATEDCOLUMN")));
tableColumn.setOrdinalPosition(resultSet.getInt("ORDINAL_POSITION"));
tableColumn.setDecimalDigits(resultSet.getInt("DECIMAL_DIGITS"));
tableColumn.setNumPrecRadix(resultSet.getInt("NUM_PREC_RADIX"));
tableColumn.setCharOctetLength(resultSet.getInt("CHAR_OCTET_LENGTH"));
return tableColumn;
}
public static Table buildTable(ResultSet resultSet) throws SQLException {
Table table = new Table();
table.setName(getString(resultSet, "TABLE_NAME"));
table.setComment(getString(resultSet, "REMARKS"));
table.setDatabaseName(getString(resultSet, "TABLE_CAT"));
table.setSchemaName(getString(resultSet, "TABLE_SCHEM"));
table.setType(getString(resultSet, "TABLE_TYPE"));
return table;
}
private static String getString(ResultSet resultSet, String name) {
if (resultSet == null) {
return null;
}
/**
*
* @param rs
* @param clazz
* @return
* @param <T>
*/
public static <T> List<T> toObjectList(ResultSet rs, Class<T> clazz) {
try {
return resultSet.getString(name);
} catch (Exception e) {
return null;
if (rs == null || clazz == null) {
return Lists.newArrayList();
}
List<T> list = Lists.newArrayList();
ResultSetMetaData rsMetaData = rs.getMetaData();
int col = rsMetaData.getColumnCount();
List<String> headerList = getRsHeader(rs);
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
while (rs.next()) {
Map<String, Object> map = new HashMap<>();
for (int i = 1; i <= col; i++) {
map.put(headerList.get(i-1), rs.getObject(i));
}
T obj = mapper.convertValue(map, clazz);
list.add(obj);
}
return list;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static String getColumnName(ResultSetMetaData resultSetMetaData, int column) throws SQLException {
String columnLabel = resultSetMetaData.getColumnLabel(column);
if (columnLabel != null) {

View File

@@ -8,6 +8,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import ai.chat2db.server.tools.common.util.EasyIntegerUtils;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLDataTypeImpl;
@@ -85,7 +86,7 @@ public class SqlUtils {
mySqlCreateTableStatement.addColumn(sqlColumnDefinition);
sqlColumnDefinition.setName(tableColumn.getName());
sqlColumnDefinition.setDataType(new SQLDataTypeImpl(tableColumn.getColumnType()));
if (BooleanUtils.isNotFalse(tableColumn.getNullable())) {
if (tableColumn.getNullable()==1) {
sqlColumnDefinition.addConstraint(new SQLNullConstraint());
} else {
sqlColumnDefinition.addConstraint(new SQLNotNullConstraint());
@@ -221,7 +222,7 @@ public class SqlUtils {
sqlAlterTableAddColumn.addColumn(sqlColumnDefinition);
sqlColumnDefinition.setName(newTableColumn.getName());
sqlColumnDefinition.setDataType(new SQLDataTypeImpl(newTableColumn.getColumnType()));
if (BooleanUtils.isNotTrue(newTableColumn.getNullable())) {
if (newTableColumn.getNullable()!=1) {
sqlColumnDefinition.addConstraint(new SQLNotNullConstraint());
}
if (!Objects.isNull(newTableColumn.getDefaultValue())) {
@@ -236,7 +237,7 @@ public class SqlUtils {
// 代表可能修改字段 或者没变
boolean hasChange = !StringUtils.equals(oldTableColumn.getName(), newTableColumn.getName())
|| !StringUtils.equals(oldTableColumn.getColumnType(), newTableColumn.getColumnType())
|| !EasyBooleanUtils.equals(oldTableColumn.getNullable(), newTableColumn.getNullable(), Boolean.TRUE)
|| !EasyIntegerUtils.equals(oldTableColumn.getNullable(), newTableColumn.getNullable(), 1)
|| !StringUtils.equals(oldTableColumn.getDefaultValue(), newTableColumn.getDefaultValue())
|| !EasyBooleanUtils.equals(oldTableColumn.getAutoIncrement(), newTableColumn.getAutoIncrement(),
Boolean.FALSE)
@@ -256,7 +257,7 @@ public class SqlUtils {
mySqlAlterTableChangeColumn.setNewColumnDefinition(sqlColumnDefinition);
sqlColumnDefinition.setName(newTableColumn.getName());
sqlColumnDefinition.setDataType(new SQLDataTypeImpl(newTableColumn.getColumnType()));
if (BooleanUtils.isNotTrue(newTableColumn.getNullable())) {
if (newTableColumn.getNullable()!=1) {
sqlColumnDefinition.addConstraint(new SQLNotNullConstraint());
}
if (!Objects.isNull(newTableColumn.getDefaultValue())) {
@@ -274,7 +275,7 @@ public class SqlUtils {
mySqlAlterTableModifyColumn.setNewColumnDefinition(sqlColumnDefinition);
sqlColumnDefinition.setName(newTableColumn.getName());
sqlColumnDefinition.setDataType(new SQLDataTypeImpl(newTableColumn.getColumnType()));
if (BooleanUtils.isNotTrue(newTableColumn.getNullable())) {
if (newTableColumn.getNullable()!=1) {
sqlColumnDefinition.addConstraint(new SQLNotNullConstraint());
}
if (!Objects.isNull(newTableColumn.getDefaultValue())) {