diff --git a/chat2db-server/chat2db-plugins/chat2db-db2/src/main/java/ai/chat2db/plugin/db2/DB2MetaData.java b/chat2db-server/chat2db-plugins/chat2db-db2/src/main/java/ai/chat2db/plugin/db2/DB2MetaData.java index 07a24e99..a78a0d1f 100644 --- a/chat2db-server/chat2db-plugins/chat2db-db2/src/main/java/ai/chat2db/plugin/db2/DB2MetaData.java +++ b/chat2db-server/chat2db-plugins/chat2db-db2/src/main/java/ai/chat2db/plugin/db2/DB2MetaData.java @@ -2,12 +2,26 @@ package ai.chat2db.plugin.db2; import java.sql.Connection; import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; +import ai.chat2db.plugin.db2.builder.DB2SqlBuilder; import ai.chat2db.spi.MetaData; +import ai.chat2db.spi.SqlBuilder; import ai.chat2db.spi.jdbc.DefaultMetaService; +import ai.chat2db.spi.jdbc.DefaultSqlBuilder; +import ai.chat2db.spi.model.Schema; import ai.chat2db.spi.sql.SQLExecutor; +import ai.chat2db.spi.util.SortUtils; public class DB2MetaData extends DefaultMetaService implements MetaData { + + private List systemSchemas = Arrays.asList("NULLID","SQLJ","SYSCAT","SYSFUN","SYSIBM","SYSIBMADM","SYSIBMINTERNAL","SYSIBMTS","SYSPROC","SYSPUBLIC","SYSSTAT","SYSTOOLS"); + @Override + public List schemas(Connection connection, String databaseName) { + List schemas = SQLExecutor.getInstance().schemas(connection, databaseName, null); + return SortUtils.sortSchema(schemas, systemSchemas); + } private String functionSQL = "CREATE FUNCTION tableSchema.ufn_GetCreateTableScript( @schema_name NVARCHAR(128), @table_name NVARCHAR" + "(128)) RETURNS NVARCHAR(MAX) AS BEGIN DECLARE @CreateTableScript NVARCHAR(MAX); DECLARE @IndexScripts " @@ -40,7 +54,6 @@ public class DB2MetaData extends DefaultMetaService implements MetaData { @Override public String tableDDL(Connection connection, String databaseName, String schemaName, String tableName) { try { - System.out.println(functionSQL); SQLExecutor.getInstance().executeSql(connection, functionSQL.replace("tableSchema", schemaName), resultSet -> null); } catch (Exception e) { //log.error("创建函数失败", e); @@ -59,6 +72,9 @@ public class DB2MetaData extends DefaultMetaService implements MetaData { return null; }); } - + @Override + public SqlBuilder getSqlBuilder() { + return new DB2SqlBuilder(); + } } diff --git a/chat2db-server/chat2db-plugins/chat2db-db2/src/main/java/ai/chat2db/plugin/db2/builder/DB2SqlBuilder.java b/chat2db-server/chat2db-plugins/chat2db-db2/src/main/java/ai/chat2db/plugin/db2/builder/DB2SqlBuilder.java new file mode 100644 index 00000000..6a67220e --- /dev/null +++ b/chat2db-server/chat2db-plugins/chat2db-db2/src/main/java/ai/chat2db/plugin/db2/builder/DB2SqlBuilder.java @@ -0,0 +1,23 @@ +package ai.chat2db.plugin.db2.builder; + +import ai.chat2db.spi.SqlBuilder; +import ai.chat2db.spi.jdbc.DefaultSqlBuilder; + +public class DB2SqlBuilder extends DefaultSqlBuilder { + + + + @Override + public String pageLimit(String sql, int offset, int pageNo, int pageSize) { + int startRow = offset + 1; + int endRow = offset+ pageSize; + StringBuilder sqlBuilder = new StringBuilder(sql.length() + 120); + sqlBuilder.append("SELECT * FROM (SELECT TMP_PAGE.*,ROWNUMBER() OVER() AS PAGEHELPER_ROW_ID FROM ( \n"); + sqlBuilder.append(sql); + sqlBuilder.append("\n ) AS TMP_PAGE) TMP_PAGE WHERE PAGEHELPER_ROW_ID BETWEEN "); + sqlBuilder.append(startRow); + sqlBuilder.append(" AND "); + sqlBuilder.append(endRow); + return sqlBuilder.toString(); + } +} diff --git a/chat2db-server/chat2db-plugins/chat2db-dm/src/main/java/ai/chat2db/plugin/dm/DMMetaData.java b/chat2db-server/chat2db-plugins/chat2db-dm/src/main/java/ai/chat2db/plugin/dm/DMMetaData.java index f6555f64..6ac30a9a 100644 --- a/chat2db-server/chat2db-plugins/chat2db-dm/src/main/java/ai/chat2db/plugin/dm/DMMetaData.java +++ b/chat2db-server/chat2db-plugins/chat2db-dm/src/main/java/ai/chat2db/plugin/dm/DMMetaData.java @@ -3,19 +3,26 @@ package ai.chat2db.plugin.dm; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import ai.chat2db.spi.MetaData; import ai.chat2db.spi.jdbc.DefaultMetaService; -import ai.chat2db.spi.model.Function; -import ai.chat2db.spi.model.Procedure; -import ai.chat2db.spi.model.Table; -import ai.chat2db.spi.model.Trigger; +import ai.chat2db.spi.model.*; import ai.chat2db.spi.sql.SQLExecutor; +import ai.chat2db.spi.util.SortUtils; import ai.chat2db.spi.util.SqlUtils; import jakarta.validation.constraints.NotEmpty; public class DMMetaData extends DefaultMetaService implements MetaData { + + private List systemSchemas = Arrays.asList("CTISYS", "SYS","SYSDBA","SYSSSO","SYSAUDITOR"); + + @Override + public List schemas(Connection connection, String databaseName) { + List schemas = SQLExecutor.getInstance().schemas(connection, databaseName, null); + return SortUtils.sortSchema(schemas, systemSchemas); + } public String tableDDL(Connection connection, String databaseName, String schemaName, String tableName) { String selectObjectDDLSQL = String.format( "select dbms_metadata.get_ddl(%s, %s, %s) AS \"sql\" from dual", diff --git a/chat2db-server/chat2db-plugins/chat2db-h2/src/main/java/ai/chat2db/plugin/h2/H2Meta.java b/chat2db-server/chat2db-plugins/chat2db-h2/src/main/java/ai/chat2db/plugin/h2/H2Meta.java index e063d792..181987b0 100644 --- a/chat2db-server/chat2db-plugins/chat2db-h2/src/main/java/ai/chat2db/plugin/h2/H2Meta.java +++ b/chat2db-server/chat2db-plugins/chat2db-h2/src/main/java/ai/chat2db/plugin/h2/H2Meta.java @@ -3,21 +3,24 @@ package ai.chat2db.plugin.h2; import java.sql.Connection; import java.sql.ResultSet; import java.sql.ResultSetMetaData; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import ai.chat2db.spi.MetaData; import ai.chat2db.spi.jdbc.DefaultMetaService; -import ai.chat2db.spi.model.Function; -import ai.chat2db.spi.model.Procedure; -import ai.chat2db.spi.model.Table; -import ai.chat2db.spi.model.Trigger; +import ai.chat2db.spi.model.*; import ai.chat2db.spi.sql.SQLExecutor; +import ai.chat2db.spi.util.SortUtils; import jakarta.validation.constraints.NotEmpty; public class H2Meta extends DefaultMetaService implements MetaData { + + + private List systemSchemas = Arrays.asList("INFORMATION_SCHEMA"); + @Override + public List schemas(Connection connection, String databaseName) { + List schemas = SQLExecutor.getInstance().schemas(connection, databaseName, null); + return SortUtils.sortSchema(schemas, systemSchemas); + } @Override public String tableDDL(Connection connection, @NotEmpty String databaseName, String schemaName, @NotEmpty String tableName) { @@ -69,19 +72,13 @@ public class H2Meta extends DefaultMetaService implements MetaData { createTableDDL.append(tableName).append(" (\n"); createTableDDL.append(String.join(",\n", columnDefinitions)); createTableDDL.append("\n);\n"); - - System.out.println("DDL建表语句:"); - System.out.println(createTableDDL.toString()); - // 输出索引信息 - System.out.println("\nDDL索引语句:"); for (Map.Entry> entry : indexMap.entrySet()) { String indexName = entry.getKey(); List columnList = entry.getValue(); String indexColumns = String.join(", ", columnList); String createIndexDDL = String.format("CREATE INDEX %s ON %s (%s);", indexName, tableName, indexColumns); - System.out.println(createIndexDDL); createTableDDL.append(createIndexDDL); } return createTableDDL.toString(); diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/MysqlMetaData.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/MysqlMetaData.java index 38d8b034..27c03f31 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/MysqlMetaData.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/MysqlMetaData.java @@ -5,6 +5,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import ai.chat2db.plugin.mysql.builder.MysqlSqlBuilder; import ai.chat2db.plugin.mysql.type.MysqlCharsetEnum; @@ -17,9 +18,21 @@ import ai.chat2db.spi.jdbc.DefaultMetaService; import ai.chat2db.spi.model.*; import ai.chat2db.spi.sql.SQLExecutor; import jakarta.validation.constraints.NotEmpty; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import static ai.chat2db.spi.util.SortUtils.sortDatabase; + public class MysqlMetaData extends DefaultMetaService implements MetaData { + + private List systemDatabases = Arrays.asList("information_schema", "performance_schema", "mysql", "sys"); + @Override + public List databases(Connection connection) { + List databases = SQLExecutor.getInstance().databases(connection); + return sortDatabase(databases,systemDatabases,connection); + } + + @Override public String tableDDL(Connection connection, @NotEmpty String databaseName, String schemaName, @NotEmpty String tableName) { diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/builder/MysqlSqlBuilder.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/builder/MysqlSqlBuilder.java index aa404f46..c8594bc7 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/builder/MysqlSqlBuilder.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/builder/MysqlSqlBuilder.java @@ -104,4 +104,22 @@ public class MysqlSqlBuilder implements SqlBuilder { } + + @Override + public String pageLimit(String sql, int offset, int pageNo, int pageSize) { + StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); + sqlBuilder.append(sql); + if (offset == 0) { + sqlBuilder.append("\n LIMIT "); + sqlBuilder.append(pageSize); + } else { + sqlBuilder.append("\n LIMIT "); + sqlBuilder.append(offset); + sqlBuilder.append(","); + sqlBuilder.append(pageSize); + } + return sqlBuilder.toString(); + } + + } diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/OracleMetaData.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/OracleMetaData.java index acf8552b..e2cca8ff 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/OracleMetaData.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/OracleMetaData.java @@ -14,6 +14,7 @@ import ai.chat2db.spi.SqlBuilder; import ai.chat2db.spi.jdbc.DefaultMetaService; import ai.chat2db.spi.model.*; import ai.chat2db.spi.sql.SQLExecutor; +import ai.chat2db.spi.util.SortUtils; import com.google.common.collect.Lists; import jakarta.validation.constraints.NotEmpty; import org.apache.commons.lang3.StringUtils; @@ -22,6 +23,15 @@ public class OracleMetaData extends DefaultMetaService implements MetaData { private static final String TABLE_DDL_SQL = "select dbms_metadata.get_ddl('TABLE','%s','%s') as sql from dual"; + private List systemSchemas = Arrays.asList("ANONYMOUS","APEX_030200","APEX_PUBLIC_USER","APPQOSSYS","BI","CTXSYS","DBSNMP","DIP","EXFSYS","FLOWS_FILES","HR","IX","MDDATA","MDSYS","MGMT_VIEW","OE","OLAPSYS","ORACLE_OCM","ORDDATA","ORDPLUGINS","ORDSYS","OUTLN","OWBSYS","OWBSYS_AUDIT","PM","SCOTT","SH","SI_INFORMTN_SCHEMA","SPATIAL_CSW_ADMIN_USR","SPATIAL_WFS_ADMIN_USR","SYS","SYSMAN","SYSTEM","WMSYS","XDB","XS$NULL"); + + + @Override + public List schemas(Connection connection, String databaseName) { + List schemas = SQLExecutor.getInstance().schemas(connection, databaseName, null); + return SortUtils.sortSchema(schemas, systemSchemas); + } + @Override public String tableDDL(Connection connection, String databaseName, String schemaName, String tableName) { String sql = String.format(TABLE_DDL_SQL, tableName, schemaName); diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/builder/OracleSqlBuilder.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/builder/OracleSqlBuilder.java index 85096d60..c1dbbda7 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/builder/OracleSqlBuilder.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/builder/OracleSqlBuilder.java @@ -6,6 +6,7 @@ import ai.chat2db.spi.SqlBuilder; import ai.chat2db.spi.model.Table; import ai.chat2db.spi.model.TableColumn; import ai.chat2db.spi.model.TableIndex; +import ai.chat2db.spi.sql.Chat2DBContext; import org.apache.commons.lang3.StringUtils; public class OracleSqlBuilder implements SqlBuilder { @@ -16,7 +17,7 @@ public class OracleSqlBuilder implements SqlBuilder { script.append("CREATE TABLE ").append("\"").append(table.getSchemaName()).append("\".\"").append(table.getName()).append("\" (").append("\n"); for (TableColumn column : table.getColumnList()) { - if(StringUtils.isBlank(column.getName())|| StringUtils.isBlank(column.getColumnType())){ + if (StringUtils.isBlank(column.getName()) || StringUtils.isBlank(column.getColumnType())) { continue; } OracleColumnTypeEnum typeEnum = OracleColumnTypeEnum.getByType(column.getColumnType()); @@ -27,7 +28,7 @@ public class OracleSqlBuilder implements SqlBuilder { script.append("\n);"); for (TableIndex tableIndex : table.getIndexList()) { - if(StringUtils.isBlank(tableIndex.getName())|| StringUtils.isBlank(tableIndex.getType())){ + if (StringUtils.isBlank(tableIndex.getName()) || StringUtils.isBlank(tableIndex.getType())) { continue; } OracleIndexTypeEnum oracleColumnTypeEnum = OracleIndexTypeEnum.getByType(tableIndex.getType()); @@ -35,7 +36,7 @@ public class OracleSqlBuilder implements SqlBuilder { } for (TableColumn column : table.getColumnList()) { - if(StringUtils.isBlank(column.getName())|| StringUtils.isBlank(column.getColumnType()) || StringUtils.isBlank(column.getComment())){ + if (StringUtils.isBlank(column.getName()) || StringUtils.isBlank(column.getColumnType()) || StringUtils.isBlank(column.getComment())) { continue; } script.append("\n").append(buildComment(column)).append(";"); @@ -66,7 +67,7 @@ public class OracleSqlBuilder implements SqlBuilder { StringBuilder script = new StringBuilder(); if (!StringUtils.equalsIgnoreCase(oldTable.getName(), newTable.getName())) { - script.append("ALTER TABLE "). append("\"").append(oldTable.getSchemaName()).append("\".\"").append(oldTable.getName()).append("\""); + script.append("ALTER TABLE ").append("\"").append(oldTable.getSchemaName()).append("\".\"").append(oldTable.getName()).append("\""); script.append(" ").append("RENAME TO ").append("\"").append(newTable.getName()).append("\"").append(";\n"); } if (!StringUtils.equalsIgnoreCase(oldTable.getComment(), newTable.getComment())) { @@ -79,7 +80,7 @@ public class OracleSqlBuilder implements SqlBuilder { if (StringUtils.isNotBlank(tableColumn.getEditStatus())) { OracleColumnTypeEnum typeEnum = OracleColumnTypeEnum.getByType(tableColumn.getColumnType()); script.append("\t").append(typeEnum.buildModifyColumn(tableColumn)).append(";\n"); - if(StringUtils.isNotBlank(tableColumn.getComment())){ + if (StringUtils.isNotBlank(tableColumn.getComment())) { script.append("\n").append(buildComment(tableColumn)).append(";\n"); } } @@ -92,11 +93,38 @@ public class OracleSqlBuilder implements SqlBuilder { script.append("\t").append(mysqlIndexTypeEnum.buildModifyIndex(tableIndex)).append(";\n"); } } - if(script.length()>2) { + if (script.length() > 2) { script = new StringBuilder(script.substring(0, script.length() - 2)); script.append(";"); } return script.toString(); } + + @Override + public String pageLimit(String sql, int offset, int pageNo, int pageSize) { + int startRow = offset; + int endRow = offset + pageSize; + StringBuilder sqlBuilder = new StringBuilder(sql.length() + 120); + if (startRow > 0) { + sqlBuilder.append("SELECT * FROM ( "); + } + if (endRow > 0) { + sqlBuilder.append(" SELECT TMP_PAGE.*, ROWNUM CAHT2DB_AUTO_ROW_ID FROM ( "); + } + sqlBuilder.append("\n"); + sqlBuilder.append(sql); + sqlBuilder.append("\n"); + if (endRow > 0) { + sqlBuilder.append(" ) TMP_PAGE WHERE ROWNUM <= "); + sqlBuilder.append(endRow); + } + if (startRow > 0) { + sqlBuilder.append(" ) WHERE CAHT2DB_AUTO_ROW_ID > "); + sqlBuilder.append(startRow); + } + return sqlBuilder.toString(); + + + } } diff --git a/chat2db-server/chat2db-plugins/chat2db-postgresql/src/main/java/ai/chat2db/plugin/postgresql/PostgreSQLMetaData.java b/chat2db-server/chat2db-plugins/chat2db-postgresql/src/main/java/ai/chat2db/plugin/postgresql/PostgreSQLMetaData.java index f9f9a14f..78e98656 100644 --- a/chat2db-server/chat2db-plugins/chat2db-postgresql/src/main/java/ai/chat2db/plugin/postgresql/PostgreSQLMetaData.java +++ b/chat2db-server/chat2db-plugins/chat2db-postgresql/src/main/java/ai/chat2db/plugin/postgresql/PostgreSQLMetaData.java @@ -17,22 +17,23 @@ import ai.chat2db.spi.SqlBuilder; import ai.chat2db.spi.jdbc.DefaultMetaService; import ai.chat2db.spi.model.*; import ai.chat2db.spi.sql.SQLExecutor; -import com.alibaba.druid.sql.visitor.functions.If; -import com.alibaba.fastjson2.JSON; +import ai.chat2db.spi.util.SortUtils; import com.google.common.collect.Lists; import jakarta.validation.constraints.NotEmpty; -import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import static ai.chat2db.plugin.postgresql.consts.SQLConst.FUNCTION_SQL; +import static ai.chat2db.spi.util.SortUtils.sortDatabase; public class PostgreSQLMetaData extends DefaultMetaService implements MetaData { private static final String SELECT_KEY_INDEX = "SELECT ccu.table_schema AS Foreign_schema_name, ccu.table_name AS Foreign_table_name, ccu.column_name AS Foreign_column_name, constraint_type AS Constraint_type, tc.CONSTRAINT_NAME AS Key_name, tc.TABLE_NAME, kcu.Column_name, tc.is_deferrable, tc.initially_deferred FROM information_schema.table_constraints AS tc JOIN information_schema.key_column_usage AS kcu ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name WHERE tc.TABLE_SCHEMA = '%s' AND tc.TABLE_NAME = '%s';"; + + private List systemDatabases = Arrays.asList("postgres"); @Override public List databases(Connection connection) { - return SQLExecutor.getInstance().executeSql(connection, "SELECT datname FROM pg_database;", resultSet -> { + List list = SQLExecutor.getInstance().executeSql(connection, "SELECT datname FROM pg_database;", resultSet -> { List databases = new ArrayList<>(); try { while (resultSet.next()) { @@ -49,8 +50,30 @@ public class PostgreSQLMetaData extends DefaultMetaService implements MetaData { } return databases; }); - + return sortDatabase(list, systemDatabases,connection); } + + private List systemSchemas = Arrays.asList("pg_toast","pg_temp_1","pg_toast_temp_1","pg_catalog","information_schema"); + + @Override + public List schemas(Connection connection, String databaseName) { + List schemas = SQLExecutor.getInstance().execute(connection, + "SELECT catalog_name, schema_name FROM information_schema.schemata;", resultSet -> { + List databases = new ArrayList<>(); + while (resultSet.next()) { + Schema schema = new Schema(); + String name = resultSet.getString("schema_name"); + String catalogName = resultSet.getString("catalog_name"); + schema.setName(name); + schema.setDatabaseName(catalogName); + databases.add(schema); + } + return databases; + }); + return SortUtils.sortSchema(schemas, systemSchemas); + } + + private static final String SELECT_TABLE_INDEX = "SELECT tmp.INDISPRIMARY AS Index_primary, tmp.TABLE_SCHEM, tmp.TABLE_NAME, tmp.NON_UNIQUE, tmp.INDEX_QUALIFIER, tmp.INDEX_NAME AS Key_name, tmp.indisclustered, tmp.ORDINAL_POSITION AS Seq_in_index, TRIM ( BOTH '\"' FROM pg_get_indexdef ( tmp.CI_OID, tmp.ORDINAL_POSITION, FALSE ) ) AS Column_name,CASE tmp.AM_NAME WHEN 'btree' THEN CASE tmp.I_INDOPTION [ tmp.ORDINAL_POSITION - 1 ] & 1 :: SMALLINT WHEN 1 THEN 'D' ELSE'A' END ELSE NULL END AS Collation, tmp.CARDINALITY, tmp.PAGES, tmp.FILTER_CONDITION , tmp.AM_NAME AS Index_method, tmp.DESCRIPTION AS Index_comment FROM ( SELECT n.nspname AS TABLE_SCHEM, ct.relname AS TABLE_NAME, NOT i.indisunique AS NON_UNIQUE, NULL AS INDEX_QUALIFIER, ci.relname AS INDEX_NAME,i.INDISPRIMARY , i.indisclustered , ( information_schema._pg_expandarray ( i.indkey ) ).n AS ORDINAL_POSITION, ci.reltuples AS CARDINALITY, ci.relpages AS PAGES, pg_get_expr ( i.indpred, i.indrelid ) AS FILTER_CONDITION, ci.OID AS CI_OID, i.indoption AS I_INDOPTION, am.amname AS AM_NAME , d.description FROM pg_class ct JOIN pg_namespace n ON ( ct.relnamespace = n.OID ) JOIN pg_index i ON ( ct.OID = i.indrelid ) JOIN pg_class ci ON ( ci.OID = i.indexrelid ) JOIN pg_am am ON ( ci.relam = am.OID ) left outer join pg_description d on i.indexrelid = d.objoid WHERE n.nspname = '%s' AND ct.relname = '%s' ) AS tmp ;"; private static String ROUTINES_SQL = " SELECT p.proname, p.prokind, pg_catalog.pg_get_functiondef(p.oid) as \"code\" FROM pg_catalog.pg_proc p " @@ -99,22 +122,6 @@ public class PostgreSQLMetaData extends DefaultMetaService implements MetaData { }); } - @Override - public List schemas(Connection connection, String databaseName) { - return SQLExecutor.getInstance().execute(connection, - "SELECT catalog_name, schema_name FROM information_schema.schemata;", resultSet -> { - List databases = new ArrayList<>(); - while (resultSet.next()) { - Schema schema = new Schema(); - String name = resultSet.getString("schema_name"); - String catalogName = resultSet.getString("catalog_name"); - schema.setName(name); - schema.setDatabaseName(catalogName); - databases.add(schema); - } - return databases; - }); - } @Override public Function function(Connection connection, @NotEmpty String databaseName, String schemaName, diff --git a/chat2db-server/chat2db-plugins/chat2db-postgresql/src/main/java/ai/chat2db/plugin/postgresql/builder/PostgreSQLSqlBuilder.java b/chat2db-server/chat2db-plugins/chat2db-postgresql/src/main/java/ai/chat2db/plugin/postgresql/builder/PostgreSQLSqlBuilder.java index 833c66d5..2a521d2e 100644 --- a/chat2db-server/chat2db-plugins/chat2db-postgresql/src/main/java/ai/chat2db/plugin/postgresql/builder/PostgreSQLSqlBuilder.java +++ b/chat2db-server/chat2db-plugins/chat2db-postgresql/src/main/java/ai/chat2db/plugin/postgresql/builder/PostgreSQLSqlBuilder.java @@ -156,5 +156,20 @@ public class PostgreSQLSqlBuilder implements SqlBuilder { return script.toString(); } + @Override + public String pageLimit(String sql, int offset, int pageNo, int pageSize) { + StringBuilder sqlStr = new StringBuilder(sql.length() + 17); + sqlStr.append(sql); + if (offset == 0) { + sqlStr.append(" LIMIT "); + sqlStr.append(pageSize); + } else { + sqlStr.append(" LIMIT "); + sqlStr.append(pageSize); + sqlStr.append(" OFFSET "); + sqlStr.append(offset); + } + return sqlStr.toString(); + } } diff --git a/chat2db-server/chat2db-plugins/chat2db-sqlite/src/main/java/ai/chat2db/plugin/sqlite/builder/SqliteBuilder.java b/chat2db-server/chat2db-plugins/chat2db-sqlite/src/main/java/ai/chat2db/plugin/sqlite/builder/SqliteBuilder.java index 379651fd..b648834a 100644 --- a/chat2db-server/chat2db-plugins/chat2db-sqlite/src/main/java/ai/chat2db/plugin/sqlite/builder/SqliteBuilder.java +++ b/chat2db-server/chat2db-plugins/chat2db-sqlite/src/main/java/ai/chat2db/plugin/sqlite/builder/SqliteBuilder.java @@ -18,7 +18,7 @@ public class SqliteBuilder implements SqlBuilder { // append column for (TableColumn column : table.getColumnList()) { - if(StringUtils.isBlank(column.getName())|| StringUtils.isBlank(column.getColumnType())){ + if (StringUtils.isBlank(column.getName()) || StringUtils.isBlank(column.getColumnType())) { continue; } SqliteColumnTypeEnum typeEnum = SqliteColumnTypeEnum.getByType(column.getColumnType()); @@ -27,7 +27,7 @@ public class SqliteBuilder implements SqlBuilder { // append primary key and index for (TableIndex tableIndex : table.getIndexList()) { - if(StringUtils.isBlank(tableIndex.getName())|| StringUtils.isBlank(tableIndex.getType())){ + if (StringUtils.isBlank(tableIndex.getName()) || StringUtils.isBlank(tableIndex.getType())) { continue; } SqliteIndexTypeEnum sqliteIndexTypeEnum = SqliteIndexTypeEnum.getByType(tableIndex.getType()); @@ -53,7 +53,7 @@ public class SqliteBuilder implements SqlBuilder { // append modify column for (TableColumn tableColumn : newTable.getColumnList()) { - if (StringUtils.isNotBlank(tableColumn.getEditStatus()) && StringUtils.isNotBlank(tableColumn.getColumnType())&& StringUtils.isNotBlank(tableColumn.getName())){ + if (StringUtils.isNotBlank(tableColumn.getEditStatus()) && StringUtils.isNotBlank(tableColumn.getColumnType()) && StringUtils.isNotBlank(tableColumn.getName())) { script.append("ALTER TABLE ").append("\"").append(newTable.getDatabaseName()).append("\".\"").append(newTable.getName()).append("\"").append("\n"); SqliteColumnTypeEnum typeEnum = SqliteColumnTypeEnum.getByType(tableColumn.getColumnType()); script.append("\t").append(typeEnum.buildModifyColumn(tableColumn)).append(";\n"); @@ -63,7 +63,7 @@ public class SqliteBuilder implements SqlBuilder { // append modify index for (TableIndex tableIndex : newTable.getIndexList()) { if (StringUtils.isNotBlank(tableIndex.getEditStatus()) && StringUtils.isNotBlank(tableIndex.getType())) { - // script.append("ALTER TABLE ").append("\"").append(newTable.getDatabaseName()).append("\".\"").append(newTable.getName()).append("\"").append("\n"); + // script.append("ALTER TABLE ").append("\"").append(newTable.getDatabaseName()).append("\".\"").append(newTable.getName()).append("\"").append("\n"); SqliteIndexTypeEnum sqliteIndexTypeEnum = SqliteIndexTypeEnum.getByType(tableIndex.getType()); script.append("\t").append(sqliteIndexTypeEnum.buildModifyIndex(tableIndex)).append(";\n"); } @@ -75,5 +75,8 @@ public class SqliteBuilder implements SqlBuilder { return script.toString(); } - + @Override + public String pageLimit(String sql, int offset, int pageNo, int pageSize) { + return "select * from(" + sql + ") t LIMIT " + pageNo + " OFFSET " + offset + ""; + } } diff --git a/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/SqlServerMetaData.java b/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/SqlServerMetaData.java index 53b91e37..89e3284d 100644 --- a/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/SqlServerMetaData.java +++ b/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/SqlServerMetaData.java @@ -14,10 +14,33 @@ import ai.chat2db.spi.SqlBuilder; import ai.chat2db.spi.jdbc.DefaultMetaService; import ai.chat2db.spi.model.*; import ai.chat2db.spi.sql.SQLExecutor; +import ai.chat2db.spi.util.SortUtils; import jakarta.validation.constraints.NotEmpty; import org.apache.commons.lang3.StringUtils; +import static ai.chat2db.spi.util.SortUtils.sortDatabase; + public class SqlServerMetaData extends DefaultMetaService implements MetaData { + + + + private List systemDatabases = Arrays.asList("master", "model", "msdb", "tempdb"); + @Override + public List databases(Connection connection) { + List databases = SQLExecutor.getInstance().databases(connection); + return sortDatabase(databases,systemDatabases,connection); + } + + private List systemSchemas = Arrays.asList("guest", "INFORMATION_SCHEMA", "sys", "db_owner", + "db_accessadmin", "db_securityadmin", "db_ddladmin", "db_backupoperator", "db_datareader", "db_datawriter", + "db_denydatareader", "db_denydatawriter"); + + @Override + public List schemas(Connection connection, String databaseName) { + List schemas = SQLExecutor.getInstance().schemas(connection, databaseName, null); + return SortUtils.sortSchema(schemas, systemSchemas); + } + private String functionSQL = "CREATE FUNCTION tableSchema.ufn_GetCreateTableScript( @schema_name NVARCHAR(128), @table_name NVARCHAR" + "(128)) RETURNS NVARCHAR(MAX) AS BEGIN DECLARE @CreateTableScript NVARCHAR(MAX); DECLARE @IndexScripts " @@ -49,7 +72,6 @@ public class SqlServerMetaData extends DefaultMetaService implements MetaData { @Override public String tableDDL(Connection connection, String databaseName, String schemaName, String tableName) { try { - System.out.println(functionSQL); SQLExecutor.getInstance().executeSql(connection, functionSQL.replace("tableSchema", schemaName), resultSet -> null); } catch (Exception e) { diff --git a/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/builder/SqlServerSqlBuilder.java b/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/builder/SqlServerSqlBuilder.java index 5101f8d0..22fbe67e 100644 --- a/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/builder/SqlServerSqlBuilder.java +++ b/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/builder/SqlServerSqlBuilder.java @@ -6,6 +6,7 @@ import ai.chat2db.spi.SqlBuilder; import ai.chat2db.spi.model.Table; import ai.chat2db.spi.model.TableColumn; import ai.chat2db.spi.model.TableIndex; +import ai.chat2db.spi.sql.Chat2DBContext; import org.apache.commons.lang3.StringUtils; public class SqlServerSqlBuilder implements SqlBuilder { @@ -80,9 +81,9 @@ public class SqlServerSqlBuilder implements SqlBuilder { script.append(buildRenameTable(oldTable, newTable)); } if (!StringUtils.equalsIgnoreCase(oldTable.getComment(), newTable.getComment())) { - if(oldTable.getComment() == null){ + if (oldTable.getComment() == null) { script.append("\n").append(buildTableComment(newTable)); - }else { + } else { script.append("\n").append(buildUpdateTableComment(newTable)); } } @@ -110,8 +111,8 @@ public class SqlServerSqlBuilder implements SqlBuilder { return script.toString(); } - private static String UPDATE_TABLE_COMMENT_SCRIPT = "exec sp_updateextendedproperty 'MS_Description','%s','SCHEMA','%s','TABLE','%s' \ngo"; + private String buildUpdateTableComment(Table newTable) { return String.format(UPDATE_TABLE_COMMENT_SCRIPT, newTable.getComment(), newTable.getSchemaName(), newTable.getName()); } @@ -121,4 +122,24 @@ public class SqlServerSqlBuilder implements SqlBuilder { private String buildRenameTable(Table oldTable, Table newTable) { return String.format(RENAME_TABLE_SCRIPT, oldTable.getName(), newTable.getName()); } + + @Override + public String pageLimit(String sql, int offset, int pageNo, int pageSize) { + String version = Chat2DBContext.getDbVersion(); + if (StringUtils.isNotBlank(version)) { + String[] versions = version.split("\\."); + if (versions.length > 0 && Integer.parseInt(versions[0]) >= 11) { + StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); + sqlBuilder.append(sql); + sqlBuilder.append("\n OFFSET "); + sqlBuilder.append(offset); + sqlBuilder.append(" ROWS "); + sqlBuilder.append(" FETCH NEXT "); + sqlBuilder.append(pageSize); + sqlBuilder.append(" ROWS ONLY"); + return sqlBuilder.toString(); + } + } + return ""; + } } diff --git a/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/DatabaseServiceImpl.java b/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/DatabaseServiceImpl.java index 471b7125..76f354ec 100644 --- a/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/DatabaseServiceImpl.java +++ b/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/DatabaseServiceImpl.java @@ -51,33 +51,7 @@ public class DatabaseServiceImpl implements DatabaseService { } private List getDatabases(String dbType, Connection connection) { - MetaData metaData = Chat2DBContext.getMetaData(dbType); - List databases = metaData.databases(connection); - sortDatabases(databases,connection); - return databases; - } - - private void sortDatabases(List databases,Connection connection) { - if (CollectionUtils.isEmpty(databases)) { - 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 < databases.size(); i++) { - if (StringUtils.isNotBlank(ulr) && StringUtils.isNotBlank(databases.get(i).getName())&& ulr.contains(databases.get(i).getName())) { - num = i; - break; - } - } - if (num != -1 && num != 0) { - Collections.swap(databases, num, 0); - } + return Chat2DBContext.getMetaData(dbType).databases(connection); } @Override diff --git a/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/DlTemplateServiceImpl.java b/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/DlTemplateServiceImpl.java index 7352202d..0892e1cd 100644 --- a/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/DlTemplateServiceImpl.java +++ b/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/DlTemplateServiceImpl.java @@ -146,14 +146,24 @@ public class DlTemplateServiceImpl implements DlTemplateService { } catch (ParserException e) { log.warn("解析sql失败:{}", originalSql, e); } + ExecuteResult executeResult = null; + if (SqlTypeEnum.SELECT.getCode().equals(sqlType) && !SqlUtils.hasPageLimit(originalSql,dbType)) { + String pageLimit = Chat2DBContext.getSqlBuilder().pageLimit(originalSql, offset, pageNo, pageSize); + if(StringUtils.isNotBlank(pageLimit)) { + executeResult = execute(pageLimit, 0, count); + } + } + if (executeResult == null || !executeResult.getSuccess()) { + executeResult = execute(originalSql, offset, count); + } + - ExecuteResult executeResult = execute(originalSql, offset, count); executeResult.setSqlType(sqlType); executeResult.setOriginalSql(originalSql); try { - SqlUtils.buildCanEditResult(originalSql, dbType,executeResult); + SqlUtils.buildCanEditResult(originalSql, dbType, executeResult); } catch (Exception e) { - + log.warn("buildCanEditResult error", e); } if (SqlTypeEnum.SELECT.getCode().equals(sqlType)) { executeResult.setPageNo(pageNo); @@ -258,7 +268,7 @@ public class DlTemplateServiceImpl implements DlTemplateService { private String getDeleteSql(UpdateSelectResultParam param, List row, MetaData metaSchema) { StringBuilder script = new StringBuilder(); - script.append("DELETE FROM ").append( param.getTableName()).append(""); + script.append("DELETE FROM ").append(param.getTableName()).append(""); script.append(buildWhere(param.getHeaderList(), row, metaSchema)); return script.toString(); @@ -291,7 +301,7 @@ public class DlTemplateServiceImpl implements DlTemplateService { return ""; } StringBuilder script = new StringBuilder(); - script.append("INSERT INTO ").append( param.getTableName()) + script.append("INSERT INTO ").append(param.getTableName()) .append(" ("); for (int i = 1; i < row.size(); i++) { Header header = param.getHeaderList().get(i); @@ -366,7 +376,7 @@ public class DlTemplateServiceImpl implements DlTemplateService { createParam.setSchemaName(connectInfo.getSchemaName()); createParam.setUseTime(executeResult.getDuration()); createParam.setType(connectInfo.getDbType()); - createParam.setOperationRows(executeResult.getUpdateCount() != null ? Long.valueOf(executeResult.getUpdateCount()):null); + createParam.setOperationRows(executeResult.getUpdateCount() != null ? Long.valueOf(executeResult.getUpdateCount()) : null); operationLogService.create(createParam); } catch (Exception e) { log.error("addOperationLog error:", e); diff --git a/chat2db-server/chat2db-server-domain/chat2db-server-domain-repository/src/main/java/ai/chat2db/server/domain/repository/mapper/TableCacheMapper.java b/chat2db-server/chat2db-server-domain/chat2db-server-domain-repository/src/main/java/ai/chat2db/server/domain/repository/mapper/TableCacheMapper.java index 191c85fe..7c26d0cd 100644 --- a/chat2db-server/chat2db-server-domain/chat2db-server-domain-repository/src/main/java/ai/chat2db/server/domain/repository/mapper/TableCacheMapper.java +++ b/chat2db-server/chat2db-server-domain/chat2db-server-domain-repository/src/main/java/ai/chat2db/server/domain/repository/mapper/TableCacheMapper.java @@ -1,7 +1,10 @@ package ai.chat2db.server.domain.repository.mapper; import ai.chat2db.server.domain.repository.entity.TableCacheDO; +import ai.chat2db.server.domain.repository.entity.TeamUserDO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.apache.ibatis.annotations.Param; import java.util.List; @@ -16,4 +19,6 @@ import java.util.List; public interface TableCacheMapper extends BaseMapper { void batchInsert(List list); + + IPage pageQuery(IPage page, @Param("dataSourceId") Long dataSourceId, @Param("databaseName") String databaseName, @Param("schemaName") String schemaName, @Param("searchKey") String searchKey); } diff --git a/chat2db-server/chat2db-server-domain/chat2db-server-domain-repository/src/main/resources/mapper/TableCacheMapper.xml b/chat2db-server/chat2db-server-domain/chat2db-server-domain-repository/src/main/resources/mapper/TableCacheMapper.xml index 10d8441c..c367e260 100644 --- a/chat2db-server/chat2db-server-domain/chat2db-server-domain-repository/src/main/resources/mapper/TableCacheMapper.xml +++ b/chat2db-server/chat2db-server-domain/chat2db-server-domain-repository/src/main/resources/mapper/TableCacheMapper.xml @@ -10,4 +10,23 @@ (#{item.dataSourceId},#{item.databaseName},#{item.schemaName},#{item.tableName},#{item.key},#{item.version},#{item.columns},#{item.extendInfo}) + + diff --git a/chat2db-server/chat2db-server-test/pom.xml b/chat2db-server/chat2db-server-test/pom.xml index 17551793..5874b1f5 100644 --- a/chat2db-server/chat2db-server-test/pom.xml +++ b/chat2db-server/chat2db-server-test/pom.xml @@ -35,6 +35,17 @@ 2.0.4 test + + + + + + + + + + + diff --git a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/system/AutomaticUpgrade.java b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/system/AutomaticUpgrade.java index 40833045..70238a00 100644 --- a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/system/AutomaticUpgrade.java +++ b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/system/AutomaticUpgrade.java @@ -1,21 +1,42 @@ -package ai.chat2db.server.web.api.controller.system; - -import ai.chat2db.server.tools.common.util.ConfigUtils; -import ai.chat2db.server.web.api.controller.system.util.SystemUtils; -import ai.chat2db.server.web.api.controller.system.vo.AppVersionVO; -import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -@Slf4j -@Component -public class AutomaticUpgrade { - - @Scheduled(fixedRate = 3600000) // 每小时运行一次 - public void checkVersionUpdates() { - AppVersionVO appVersion = SystemUtils.getLatestVersion(ConfigUtils.getLocalVersion(), "auto", ""); - if (appVersion != null) { - SystemUtils.upgrade(appVersion); - } - } -} +////package ai.chat2db.server.web.api.controller.system; +//// +////import ai.chat2db.server.tools.common.util.ConfigUtils; +////import ai.chat2db.server.web.api.controller.system.util.SystemUtils; +////import ai.chat2db.server.web.api.controller.system.vo.AppVersionVO; +////import lombok.extern.slf4j.Slf4j; +////import org.springframework.scheduling.annotation.Scheduled; +////import org.springframework.stereotype.Component; +//// +////@Slf4j +////@Component +////public class AutomaticUpgrade { +//// +//// @Scheduled(fixedRate = 3600000) // 每小时运行一次 +//// public void checkVersionUpdates() { +//// AppVersionVO appVersion = SystemUtils.getLatestVersion(ConfigUtils.getLocalVersion(), "auto", ""); +//// if (appVersion != null) { +//// SystemUtils.upgrade(appVersion); +//// } +//// } +////} +// +//const handleInsertText = (text, databaseCode: DatabaseTypeCode = DatabaseTypeCode.MYSQL) => { +// if ( +// [DatabaseTypeCode.POSTGRESQL, DatabaseTypeCode.ORACLE, DatabaseTypeCode.DB2, DatabaseTypeCode.SQLITE].includes( +// databaseCode, +// ) +// ) { +// return `\"${text}\"`; +// } else if ([DatabaseTypeCode.SQLSERVER].includes(databaseCode)) { +// return `[${text}]`; +// } else if ([DatabaseTypeCode.MYSQL].includes(databaseCode)) { +// return `\`${text}\``; +// } else { +// return `${text}`; +// } +// }; +// +//"" oracele sqlite postgrsql h2 dm +// ` MYSQL clickhouse MariaDB +// [ sqlserver +// diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/MetaData.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/MetaData.java index 9aa1c09b..21f1f875 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/MetaData.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/MetaData.java @@ -206,5 +206,4 @@ public interface MetaData { */ String getMetaDataName(String ...names); - } \ No newline at end of file diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/SqlBuilder.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/SqlBuilder.java index a219a40b..bb31e157 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/SqlBuilder.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/SqlBuilder.java @@ -21,4 +21,16 @@ public interface SqlBuilder { * @return */ String buildModifyTaleSql(Table oldTable, Table newTable); + + + /** + * Generate page limit sql + * + * @param sql + * @param offset + * @param pageNo + * @param pageSize + * @return + */ + String pageLimit(String sql, int offset, int pageNo, int pageSize); } diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/jdbc/DefaultSqlBuilder.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/jdbc/DefaultSqlBuilder.java index d32c5629..aad14517 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/jdbc/DefaultSqlBuilder.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/jdbc/DefaultSqlBuilder.java @@ -14,4 +14,9 @@ public class DefaultSqlBuilder implements SqlBuilder { public String buildModifyTaleSql(Table oldTable, Table newTable) { return null; } + + @Override + public String pageLimit(String sql, int offset, int pageNo, int pageSize) { + return null; + } } diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/Chat2DBContext.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/Chat2DBContext.java index de609d45..abec6ee8 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/Chat2DBContext.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/Chat2DBContext.java @@ -61,7 +61,7 @@ public class Chat2DBContext { } public static MetaData getMetaData(String dbType) { - if(StringUtils.isBlank(dbType)){ + if (StringUtils.isBlank(dbType)) { return getMetaData(); } return PLUGIN_MAP.get(dbType).getMetaData(); @@ -83,7 +83,7 @@ public class Chat2DBContext { connection = connectInfo.getConnection(); if (connection != null) { return connection; - }else { + } else { connection = getDBManage().getConnection(connectInfo); } } @@ -91,6 +91,26 @@ public class Chat2DBContext { return connection; } + public static String getDbVersion() { + ConnectInfo connectInfo = getConnectInfo(); + String dbVersion = connectInfo.getDbVersion(); + if (dbVersion == null) { + synchronized (connectInfo) { + if (connectInfo.getDbVersion() != null) { + return connectInfo.getDbVersion(); + } else { + dbVersion = SQLExecutor.getInstance().getDbVersion(getConnection()); + connectInfo.setDbVersion(dbVersion); + return connectInfo.getDbVersion(); + } + } + } else { + return dbVersion; + } + + } + + /** * 设置context * @@ -124,7 +144,7 @@ public class Chat2DBContext { Session session = connectInfo.getSession(); if (session != null && session.isConnected() && connectInfo.getSsh() != null - && connectInfo.getSsh().isUse()) { + && connectInfo.getSsh().isUse()) { try { session.delPortForwardingL(Integer.parseInt(connectInfo.getSsh().getLocalPort())); } catch (JSchException e) { diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/ConnectInfo.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/ConnectInfo.java index 6cf38075..4b96e479 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/ConnectInfo.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/ConnectInfo.java @@ -129,12 +129,23 @@ public class ConnectInfo { public Connection connection; - + /** + * Database version used for different database + */ + private String dbVersion; private DriverConfig driverConfig; + public String getDbVersion() { + return dbVersion; + } + + public void setDbVersion(String dbVersion) { + this.dbVersion = dbVersion; + } + public DriverConfig getDriverConfig() { return driverConfig; } diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/SQLExecutor.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/SQLExecutor.java index 9d20c536..7b0628eb 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/SQLExecutor.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/SQLExecutor.java @@ -17,6 +17,7 @@ import ai.chat2db.spi.util.ResultSetUtils; import cn.hutool.core.date.TimeInterval; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.jdbc.support.JdbcUtils; import org.springframework.util.Assert; @@ -158,7 +159,7 @@ public class SQLExecutor { int affectedRows = stmt.executeUpdate(sql); if (affectedRows != n) { executeResult.setSuccess(false); - executeResult.setMessage("Update error "+ sql +" update affectedRows = " + affectedRows + ", Each SQL statement should update no more than one record. Please use a unique key for updates."); + executeResult.setMessage("Update error " + sql + " update affectedRows = " + affectedRows + ", Each SQL statement should update no more than one record. Please use a unique key for updates."); connection.rollback(); } } @@ -185,6 +186,11 @@ public class SQLExecutor { ExecuteResult executeResult = ExecuteResult.builder().sql(sql).success(Boolean.TRUE).build(); try (Statement stmt = connection.createStatement()) { stmt.setFetchSize(EasyToolsConstant.MAX_PAGE_SIZE); + stmt.setQueryTimeout(30); + if (offset != null && count != null) { + stmt.setMaxRows(offset + count); + } + TimeInterval timeInterval = new TimeInterval(); boolean query = stmt.execute(sql); executeResult.setDescription(I18nUtils.getMessage("sqlResult.success")); @@ -200,11 +206,19 @@ public class SQLExecutor { // 获取header信息 List
headerList = Lists.newArrayListWithExpectedSize(col); executeResult.setHeaderList(headerList); + int chat2dbAutoRowIdIndex = -1;// chat2db自动生成的行分页ID + for (int i = 1; i <= col; i++) { + String name = ResultSetUtils.getColumnName(resultSetMetaData, i); + if ("CAHT2DB_AUTO_ROW_ID".equals(name)) { + chat2dbAutoRowIdIndex = i; + continue; + } + String dataType = ai.chat2db.spi.util.JdbcUtils.resolveDataType( + resultSetMetaData.getColumnTypeName(i), resultSetMetaData.getColumnType(i)).getCode(); headerList.add(Header.builder() - .dataType(ai.chat2db.spi.util.JdbcUtils.resolveDataType( - resultSetMetaData.getColumnTypeName(i), resultSetMetaData.getColumnType(i)).getCode()) - .name(ResultSetUtils.getColumnName(resultSetMetaData, i)) + .dataType(dataType) + .name(name) .build()); } @@ -224,6 +238,9 @@ public class SQLExecutor { List row = Lists.newArrayListWithExpectedSize(col); dataList.add(row); for (int i = 1; i <= col; i++) { + if (chat2dbAutoRowIdIndex == i) { + continue; + } row.add(ai.chat2db.spi.util.JdbcUtils.getResultSetValue(rs, i, limitRowSize)); } if (count != null && count > 0 && rowCount++ >= count) { @@ -263,7 +280,11 @@ public class SQLExecutor { */ public List databases(Connection connection) { try (ResultSet resultSet = connection.getMetaData().getCatalogs();) { - return ResultSetUtils.toObjectList(resultSet, Database.class); + List databases = ResultSetUtils.toObjectList(resultSet, Database.class); + if (CollectionUtils.isEmpty(databases)) { + return databases; + } + return databases.stream().filter(database -> database.getName() != null).collect(Collectors.toList()); } catch (SQLException e) { throw new RuntimeException(e); } @@ -428,4 +449,15 @@ public class SQLExecutor { } } + public String getDbVersion(Connection connection) { + try { + String dbVersion = connection.getMetaData().getDatabaseProductVersion(); + return dbVersion; + } catch (Exception e) { + log.error("get db version error", e); + //throw new RuntimeException(e); + } + return ""; + } + } diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/JdbcJarUtils.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/JdbcJarUtils.java index 0ca106a8..7f311d92 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/JdbcJarUtils.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/JdbcJarUtils.java @@ -42,7 +42,6 @@ public class JdbcJarUtils { String outputPath = PATH + url.substring(url.lastIndexOf("/") + 1); File file = new File(outputPath); if (file.exists()) { - System.out.println("File already exists: " + outputPath); continue; } asyncDownload(url); @@ -77,7 +76,6 @@ public class JdbcJarUtils { } fos.flush(); } - System.out.println("File downloaded: " + outputPath); } }); } @@ -105,7 +103,6 @@ public class JdbcJarUtils { } fos.flush(); } - System.out.println("File downloaded: " + outputPath); } } diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/SortUtils.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/SortUtils.java new file mode 100644 index 00000000..95ee7974 --- /dev/null +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/SortUtils.java @@ -0,0 +1,77 @@ +package ai.chat2db.spi.util; + +import ai.chat2db.spi.model.Database; +import ai.chat2db.spi.model.Schema; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class SortUtils { + + public static List sortDatabase(List databases, List list, Connection connection) { + if (CollectionUtils.isEmpty(databases)) { + return databases; + } + List systemDatabases = databases.stream() + .filter(database -> list.contains(database.getName())).collect(Collectors.toList()); + List userDatabases = databases.stream() + .filter(database -> !list.contains(database.getName())).collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(userDatabases)) { + return databases; + } + if (CollectionUtils.isEmpty(systemDatabases)) { + return userDatabases; + } + List databaseList = Stream.concat(userDatabases.stream(), systemDatabases.stream()) + .collect(Collectors.toList()); + // If the database name contains the name of the current database, the current database is placed in the first place + + String ulr; + try { + ulr = connection.getMetaData().getURL(); + } catch (SQLException e) { + return databaseList; + } + // If the database name contains the name of the current database, the current database is placed in the first place + int no = -1; + for (int i = 0; i < databases.size(); i++) { + if (StringUtils.isNotBlank(ulr) + && StringUtils.isNotBlank(databases.get(i).getName()) + && ulr.contains(databases.get(i).getName()) + && !"mysql".equalsIgnoreCase(databases.get(i).getName())) { + no = i; + break; + } + } + if (no != -1 && no != 0) { + Collections.swap(databaseList, no, 0); + } + return databaseList; + } + + public static List sortSchema(List schemas, List systemSchemas) { + if (CollectionUtils.isEmpty(schemas)) { + return schemas; + } + List systemSchema = schemas.stream() + .filter(schema -> systemSchemas.contains(schema.getName()) || "APEX_".startsWith(schema.getName())).collect(Collectors.toList()); + List userSchema = schemas.stream() + .filter(schema -> !systemSchemas.contains(schema.getName()) && !"APEX_".startsWith(schema.getName())).collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(userSchema)) { + return schemas; + } + if (CollectionUtils.isEmpty(systemSchema)) { + return userSchema; + } + return Stream.concat(userSchema.stream(), systemSchema.stream()) + .collect(Collectors.toList()); + } +} diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/SqlUtils.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/SqlUtils.java index e6aef38d..cc3e578a 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/SqlUtils.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/SqlUtils.java @@ -12,13 +12,12 @@ import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; import com.alibaba.druid.sql.ast.statement.SQLTableSource; import com.alibaba.druid.sql.parser.SQLParserUtils; +import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Function; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.Statements; -import net.sf.jsqlparser.statement.select.PlainSelect; -import net.sf.jsqlparser.statement.select.Select; -import net.sf.jsqlparser.statement.select.SelectExpressionItem; -import net.sf.jsqlparser.statement.select.SelectItem; +import net.sf.jsqlparser.statement.select.*; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; @@ -47,7 +46,18 @@ public class SqlUtils { if (expressionItem.getAlias() != null) { //canEdit = false; // 找到了一个别名 executeResult.setCanEdit(false); - return ; + return; + } + if (item instanceof SelectExpressionItem) { + SelectExpressionItem selectExpressionItem = (SelectExpressionItem) item; + // 如果表达式是一个函数 + if (selectExpressionItem.getExpression() instanceof Function) { + Function function = (Function) selectExpressionItem.getExpression(); + // 检查函数是否为 "COUNT" + if ("COUNT".equalsIgnoreCase(function.getName())) { + executeResult.setCanEdit(false); + return; } + } } } } @@ -58,6 +68,8 @@ public class SqlUtils { sqlSelectStatement.getSelect().getFirstQueryBlock().getFrom()); executeResult.setTableName(getMetaDataTableName(sqlExprTableSource.getCatalog(), sqlExprTableSource.getSchema(), sqlExprTableSource.getTableName())); } + }else { + executeResult.setCanEdit(false); } } } catch (Exception e) { @@ -66,7 +78,7 @@ public class SqlUtils { } private static String getMetaDataTableName(String... names) { - return Arrays.stream(names).filter(name -> StringUtils.isNotBlank(name)).map(name -> name ).collect(Collectors.joining(".")); + return Arrays.stream(names).filter(name -> StringUtils.isNotBlank(name)).map(name -> name).collect(Collectors.joining(".")); } public static String formatSQLString(Object para) { @@ -116,4 +128,29 @@ public class SqlUtils { DataTypeEnum dataTypeEnum = DataTypeEnum.getByCode(dataType); return dataTypeEnum.getSqlValue(value); } + + public static boolean hasPageLimit(String sql, DbType dbType) { + try { + Statement statement = CCJSqlParserUtil.parse(sql); + if (statement instanceof Select) { + Select selectStatement = (Select) statement; + SelectBody selectBody = selectStatement.getSelectBody(); + // 检查常见的分页方法 + if (selectBody instanceof PlainSelect) { + PlainSelect plainSelect = (PlainSelect) selectBody; + // 检查 LIMIT + if (plainSelect.getLimit() != null || plainSelect.getOffset() != null || plainSelect.getTop() != null || plainSelect.getFetch() != null) { + return true; + } + if (DbType.oracle.equals(dbType)) { + return sql.contains("ROWNUM") || sql.contains("rownum"); + } + } + } + } catch (Exception e) { + return false; + } + return false; + } + } \ No newline at end of file