mirror of
https://github.com/CodePhiliaX/Chat2DB.git
synced 2025-07-29 02:32:33 +08:00
Auto Upgrade
This commit is contained in:
@ -1,19 +1,52 @@
|
||||
package ai.chat2db.plugin.postgresql;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import ai.chat2db.spi.DBManage;
|
||||
import ai.chat2db.spi.jdbc.DefaultDBManage;
|
||||
import ai.chat2db.spi.sql.SQLExecutor;
|
||||
import ai.chat2db.spi.sql.ConnectInfo;
|
||||
|
||||
public class PostgreSQLDBManage extends DefaultDBManage implements DBManage {
|
||||
@Override
|
||||
public void connectDatabase(Connection connection, String database) {
|
||||
try {
|
||||
SQLExecutor.getInstance().execute(connection,"SELECT pg_database_size('"+database+"');");
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
//try {
|
||||
// SQLExecutor.getInstance().execute(connection,"SELECT pg_database_size('"+database+"');");
|
||||
//} catch (SQLException e) {
|
||||
// throw new RuntimeException(e);
|
||||
//}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection(ConnectInfo connectInfo) {
|
||||
String url = connectInfo.getUrl();
|
||||
String database = connectInfo.getDatabaseName();
|
||||
if (database != null && !database.isEmpty()) {
|
||||
url = replaceDatabaseInJdbcUrl(url, database);
|
||||
}
|
||||
connectInfo.setUrl(url);
|
||||
|
||||
return super.getConnection(connectInfo);
|
||||
}
|
||||
|
||||
|
||||
public String replaceDatabaseInJdbcUrl(String url, String newDatabase) {
|
||||
// 先在"?"字符处分割字符串,处理查询参数
|
||||
String[] urlAndParams = url.split("\\?");
|
||||
String urlWithoutParams = urlAndParams[0];
|
||||
|
||||
// 在URL中的"/"字符处分割字符串
|
||||
String[] parts = urlWithoutParams.split("/");
|
||||
|
||||
// 取最后一部分,即数据库名,并替换为新的数据库名
|
||||
parts[parts.length - 1] = newDatabase;
|
||||
|
||||
// 将修改后的部分重新组合成URL
|
||||
String newUrlWithoutParams = String.join("/", parts);
|
||||
|
||||
// 如果存在查询参数,重新添加
|
||||
String newUrl = urlAndParams.length > 1 ? newUrlWithoutParams + "?" + urlAndParams[1] : newUrlWithoutParams;
|
||||
|
||||
return newUrl;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,172 +2,25 @@ package ai.chat2db.plugin.postgresql;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ai.chat2db.spi.MetaData;
|
||||
import ai.chat2db.spi.jdbc.DefaultMetaService;
|
||||
import ai.chat2db.spi.model.Database;
|
||||
import ai.chat2db.spi.model.Schema;
|
||||
import ai.chat2db.spi.sql.SQLExecutor;
|
||||
|
||||
import static ai.chat2db.plugin.postgresql.consts.SQLConst.FUNCTION_SQL;
|
||||
|
||||
public class PostgreSQLMetaData extends DefaultMetaService implements MetaData {
|
||||
private String functionSQL =
|
||||
" CREATE OR REPLACE FUNCTION showcreatetable(namespace character varying, tablename character "
|
||||
+ "varying)\n"
|
||||
+ " RETURNS character varying AS\n"
|
||||
+ "\n"
|
||||
+ " $BODY$\n"
|
||||
+ " declare\n"
|
||||
+ " tableScript character varying default '';\n"
|
||||
+ "\n"
|
||||
+ " begin\n"
|
||||
+ " -- columns\n"
|
||||
+ " tableScript:=tableScript || ' CREATE TABLE '|| tablename|| ' ( '|| chr(13)||chr(10) || "
|
||||
+ "array_to_string"
|
||||
+ "(\n"
|
||||
+ " array(\n"
|
||||
+ " select ' ' || concat_ws(' ',fieldName, fieldType, fieldLen, indexType, isNullStr, fieldComment"
|
||||
+ " ) as "
|
||||
+ "column_line\n"
|
||||
+ " from (\n"
|
||||
+ " select a.attname as fieldName,format_type(a.atttypid,a.atttypmod) as fieldType,(case when "
|
||||
+ "atttypmod-4>0 then\n"
|
||||
+ " atttypmod-4 else 0 end) as fieldLen,\n"
|
||||
+ " (case when (select count(*) from pg_constraint where conrelid = a.attrelid and conkey[1]=attnum "
|
||||
+ "and\n"
|
||||
+ " contype='p')>0 then 'PRI'\n"
|
||||
+ " when (select count(*) from pg_constraint where conrelid = a.attrelid and conkey[1]=attnum and "
|
||||
+ "contype='u')>0\n"
|
||||
+ " then 'UNI'\n"
|
||||
+ " when (select count(*) from pg_constraint where conrelid = a.attrelid and conkey[1]=attnum and "
|
||||
+ "contype='f')>0\n"
|
||||
+ " then 'FRI'\n"
|
||||
+ " else '' end) as indexType,\n"
|
||||
+ " (case when a.attnotnull=true then 'not null' else 'null' end) as isNullStr,\n"
|
||||
+ " ' comment ' || col_description(a.attrelid,a.attnum) as fieldComment\n"
|
||||
+ " from pg_attribute a where attstattarget=-1 and attrelid = (select c.oid from pg_class c,"
|
||||
+ "pg_namespace n"
|
||||
+ " where\n"
|
||||
+ " c.relnamespace=n.oid and n.nspname =namespace and relname =tablename)\n"
|
||||
+ "\n"
|
||||
+ " ) as string_columns\n"
|
||||
+ " ),','||chr(13)||chr(10)) || ',';\n"
|
||||
+ "\n"
|
||||
+ "\n"
|
||||
+ " -- 约束\n"
|
||||
+ " tableScript:= tableScript || chr(13)||chr(10) || array_to_string(\n"
|
||||
+ " array(\n"
|
||||
+ " select concat(' CONSTRAINT ',conname ,c ,u,p,f) from (\n"
|
||||
+ " select conname,\n"
|
||||
+ " case when contype='c' then ' CHECK('|| ( select findattname(namespace,tablename,'c') ) ||')' "
|
||||
+ "end "
|
||||
+ "as c "
|
||||
+ ",\n"
|
||||
+ " case when contype='u' then ' UNIQUE('|| ( select findattname(namespace,tablename,'u') ) ||')' "
|
||||
+ "end "
|
||||
+ "as u"
|
||||
+ " ,\n"
|
||||
+ " case when contype='p' then ' PRIMARY KEY ('|| ( select findattname(namespace,tablename,'p') ) "
|
||||
+ "||')' "
|
||||
+ "end as p ,\n"
|
||||
+ " case when contype='f' then ' FOREIGN KEY('|| ( select findattname(namespace,tablename,'u') ) "
|
||||
+ "||') "
|
||||
+ "REFERENCES '||\n"
|
||||
+ " (select p.relname from pg_class p where p.oid=c.confrelid ) || '('|| ( select\n"
|
||||
+ " findattname(namespace,tablename,'u') ) ||')' end as f\n"
|
||||
+ " from pg_constraint c\n"
|
||||
+ " where contype in('u','c','f','p') and conrelid=(\n"
|
||||
+ " select oid from pg_class where relname=tablename and relnamespace =(\n"
|
||||
+ " select oid from pg_namespace where nspname = namespace\n"
|
||||
+ " )\n"
|
||||
+ " )\n"
|
||||
+ " ) as t\n"
|
||||
+ " ) ,',' || chr(13)||chr(10) ) || chr(13)||chr(10) ||' ); ';\n"
|
||||
+ "\n"
|
||||
+ " -- indexs\n"
|
||||
+ " -- CREATE UNIQUE INDEX pg_language_oid_index ON pg_language USING btree (oid); -- table "
|
||||
+ "pg_language\n"
|
||||
+ "\n"
|
||||
+ "\n"
|
||||
+ " --\n"
|
||||
+ " /** **/\n"
|
||||
+ " --- 获取非约束索引 column\n"
|
||||
+ " -- CREATE UNIQUE INDEX pg_language_oid_index ON pg_language USING btree (oid); -- table "
|
||||
+ "pg_language\n"
|
||||
+ " tableScript:= tableScript || chr(13)||chr(10) || chr(13)||chr(10) || array_to_string(\n"
|
||||
+ " array(\n"
|
||||
+ " select 'CREATE INDEX ' || indexrelname || ' ON ' || tablename || ' USING btree '|| '(' || "
|
||||
+ "attname "
|
||||
+ "|| "
|
||||
+ "');' from (\n"
|
||||
+ " SELECT\n"
|
||||
+ " i.relname AS indexrelname , x.indkey,\n"
|
||||
+ "\n"
|
||||
+ " ( select array_to_string (\n"
|
||||
+ " array(\n"
|
||||
+ " select a.attname from pg_attribute a where attrelid=c.oid and a.attnum in ( select unnest(x"
|
||||
+ ".indkey) )\n"
|
||||
+ "\n"
|
||||
+ " )\n"
|
||||
+ " ,',' ) )as attname\n"
|
||||
+ "\n"
|
||||
+ " FROM pg_class c\n"
|
||||
+ " JOIN pg_index x ON c.oid = x.indrelid\n"
|
||||
+ " JOIN pg_class i ON i.oid = x.indexrelid\n"
|
||||
+ " LEFT JOIN pg_namespace n ON n.oid = c.relnamespace\n"
|
||||
+ " WHERE c.relname=tablename and i.relname not in\n"
|
||||
+ " ( select constraint_name from information_schema.key_column_usage where table_name=tablename )\n"
|
||||
+ " )as t\n"
|
||||
+ " ) ,','|| chr(13)||chr(10));\n"
|
||||
+ "\n"
|
||||
+ "\n"
|
||||
+ " -- COMMENT COMMENT ON COLUMN sys_activity.id IS '主键';\n"
|
||||
+ " tableScript:= tableScript || chr(13)||chr(10) || chr(13)||chr(10) || array_to_string(\n"
|
||||
+ " array(\n"
|
||||
+ " SELECT 'COMMENT ON COLUMN' || tablename || '.' || a.attname ||' IS '|| ''''|| d.description "
|
||||
+ "||''''\n"
|
||||
+ " FROM pg_class c\n"
|
||||
+ " JOIN pg_description d ON c.oid=d.objoid\n"
|
||||
+ " JOIN pg_attribute a ON c.oid = a.attrelid\n"
|
||||
+ " WHERE c.relname=tablename\n"
|
||||
+ " AND a.attnum = d.objsubid),','|| chr(13)||chr(10)) ;\n"
|
||||
+ "\n"
|
||||
+ " return tableScript;\n"
|
||||
+ "\n"
|
||||
+ " end\n"
|
||||
+ " $BODY$ LANGUAGE plpgsql;\n"
|
||||
+ "\n"
|
||||
+ " CREATE OR REPLACE FUNCTION findattname(namespace character varying, tablename character "
|
||||
+ "varying, "
|
||||
+ "ctype"
|
||||
+ " character\n"
|
||||
+ " varying)\n"
|
||||
+ " RETURNS character varying as $BODY$\n"
|
||||
+ "\n"
|
||||
+ " declare\n"
|
||||
+ " tt oid ;\n"
|
||||
+ " aname character varying default '';\n"
|
||||
+ "\n"
|
||||
+ " begin\n"
|
||||
+ " tt := oid from pg_class where relname= tablename and relnamespace =(select oid from "
|
||||
+ "pg_namespace "
|
||||
+ "where\n"
|
||||
+ " nspname=namespace) ;\n"
|
||||
+ " aname:= array_to_string(\n"
|
||||
+ " array(\n"
|
||||
+ " select a.attname from pg_attribute a\n"
|
||||
+ " where a.attrelid=tt and a.attnum in (\n"
|
||||
+ " select unnest(conkey) from pg_constraint c where contype=ctype\n"
|
||||
+ " and conrelid=tt and array_to_string(conkey,',') is not null\n"
|
||||
+ " )\n"
|
||||
+ " ),',');\n"
|
||||
+ "\n"
|
||||
+ " return aname;\n"
|
||||
+ " end\n"
|
||||
+ " $BODY$ LANGUAGE plpgsql";
|
||||
|
||||
@Override
|
||||
public String tableDDL(Connection connection, String databaseName, String schemaName, String tableName) {
|
||||
SQLExecutor.getInstance().executeSql(connection,functionSQL.replaceFirst("tableSchema", schemaName), resultSet -> null);
|
||||
SQLExecutor.getInstance().executeSql(connection, FUNCTION_SQL.replaceFirst("tableSchema", schemaName),
|
||||
resultSet -> null);
|
||||
String ddlSql = "select showcreatetable('" + schemaName + "','" + tableName + "') as sql";
|
||||
return SQLExecutor.getInstance().executeSql(connection,ddlSql, resultSet -> {
|
||||
return SQLExecutor.getInstance().executeSql(connection, ddlSql, resultSet -> {
|
||||
try {
|
||||
if (resultSet.next()) {
|
||||
return resultSet.getString("sql");
|
||||
@ -179,4 +32,46 @@ public class PostgreSQLMetaData extends DefaultMetaService implements MetaData {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Database> databases(Connection connection) {
|
||||
return SQLExecutor.getInstance().executeSql(connection, "SELECT datname FROM pg_database;", resultSet -> {
|
||||
List<Database> databases = new ArrayList<>();
|
||||
try {
|
||||
while (resultSet.next()) {
|
||||
String dbName = resultSet.getString("datname");
|
||||
if ("template0".equals(dbName) || "template1".equals(dbName)) {
|
||||
continue;
|
||||
}
|
||||
Database database = new Database();
|
||||
database.setName(dbName);
|
||||
databases.add(database);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return databases;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Schema> schemas(Connection connection, String databaseName) {
|
||||
return SQLExecutor.getInstance().executeSql(connection,
|
||||
"SELECT catalog_name, schema_name FROM information_schema.schemata;", resultSet -> {
|
||||
List<Schema> databases = new ArrayList<>();
|
||||
try {
|
||||
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);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return databases;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,158 @@
|
||||
package ai.chat2db.plugin.postgresql.consts;
|
||||
|
||||
public class SQLConst {
|
||||
public static String FUNCTION_SQL =
|
||||
" CREATE OR REPLACE FUNCTION showcreatetable(namespace character varying, tablename character "
|
||||
+ "varying)\n"
|
||||
+ " RETURNS character varying AS\n"
|
||||
+ "\n"
|
||||
+ " $BODY$\n"
|
||||
+ " declare\n"
|
||||
+ " tableScript character varying default '';\n"
|
||||
+ "\n"
|
||||
+ " begin\n"
|
||||
+ " -- columns\n"
|
||||
+ " tableScript:=tableScript || ' CREATE TABLE '|| tablename|| ' ( '|| chr(13)||chr(10) || "
|
||||
+ "array_to_string"
|
||||
+ "(\n"
|
||||
+ " array(\n"
|
||||
+ " select ' ' || concat_ws(' ',fieldName, fieldType, fieldLen, indexType, isNullStr, fieldComment"
|
||||
+ " ) as "
|
||||
+ "column_line\n"
|
||||
+ " from (\n"
|
||||
+ " select a.attname as fieldName,format_type(a.atttypid,a.atttypmod) as fieldType,(case when "
|
||||
+ "atttypmod-4>0 then\n"
|
||||
+ " atttypmod-4 else 0 end) as fieldLen,\n"
|
||||
+ " (case when (select count(*) from pg_constraint where conrelid = a.attrelid and conkey[1]=attnum "
|
||||
+ "and\n"
|
||||
+ " contype='p')>0 then 'PRI'\n"
|
||||
+ " when (select count(*) from pg_constraint where conrelid = a.attrelid and conkey[1]=attnum and "
|
||||
+ "contype='u')>0\n"
|
||||
+ " then 'UNI'\n"
|
||||
+ " when (select count(*) from pg_constraint where conrelid = a.attrelid and conkey[1]=attnum and "
|
||||
+ "contype='f')>0\n"
|
||||
+ " then 'FRI'\n"
|
||||
+ " else '' end) as indexType,\n"
|
||||
+ " (case when a.attnotnull=true then 'not null' else 'null' end) as isNullStr,\n"
|
||||
+ " ' comment ' || col_description(a.attrelid,a.attnum) as fieldComment\n"
|
||||
+ " from pg_attribute a where attstattarget=-1 and attrelid = (select c.oid from pg_class c,"
|
||||
+ "pg_namespace n"
|
||||
+ " where\n"
|
||||
+ " c.relnamespace=n.oid and n.nspname =namespace and relname =tablename)\n"
|
||||
+ "\n"
|
||||
+ " ) as string_columns\n"
|
||||
+ " ),','||chr(13)||chr(10)) || ',';\n"
|
||||
+ "\n"
|
||||
+ "\n"
|
||||
+ " -- 约束\n"
|
||||
+ " tableScript:= tableScript || chr(13)||chr(10) || array_to_string(\n"
|
||||
+ " array(\n"
|
||||
+ " select concat(' CONSTRAINT ',conname ,c ,u,p,f) from (\n"
|
||||
+ " select conname,\n"
|
||||
+ " case when contype='c' then ' CHECK('|| ( select findattname(namespace,tablename,'c') ) ||')' "
|
||||
+ "end "
|
||||
+ "as c "
|
||||
+ ",\n"
|
||||
+ " case when contype='u' then ' UNIQUE('|| ( select findattname(namespace,tablename,'u') ) ||')' "
|
||||
+ "end "
|
||||
+ "as u"
|
||||
+ " ,\n"
|
||||
+ " case when contype='p' then ' PRIMARY KEY ('|| ( select findattname(namespace,tablename,'p') ) "
|
||||
+ "||')' "
|
||||
+ "end as p ,\n"
|
||||
+ " case when contype='f' then ' FOREIGN KEY('|| ( select findattname(namespace,tablename,'u') ) "
|
||||
+ "||') "
|
||||
+ "REFERENCES '||\n"
|
||||
+ " (select p.relname from pg_class p where p.oid=c.confrelid ) || '('|| ( select\n"
|
||||
+ " findattname(namespace,tablename,'u') ) ||')' end as f\n"
|
||||
+ " from pg_constraint c\n"
|
||||
+ " where contype in('u','c','f','p') and conrelid=(\n"
|
||||
+ " select oid from pg_class where relname=tablename and relnamespace =(\n"
|
||||
+ " select oid from pg_namespace where nspname = namespace\n"
|
||||
+ " )\n"
|
||||
+ " )\n"
|
||||
+ " ) as t\n"
|
||||
+ " ) ,',' || chr(13)||chr(10) ) || chr(13)||chr(10) ||' ); ';\n"
|
||||
+ "\n"
|
||||
+ " -- indexs\n"
|
||||
+ " -- CREATE UNIQUE INDEX pg_language_oid_index ON pg_language USING btree (oid); -- table "
|
||||
+ "pg_language\n"
|
||||
+ "\n"
|
||||
+ "\n"
|
||||
+ " --\n"
|
||||
+ " /** **/\n"
|
||||
+ " --- 获取非约束索引 column\n"
|
||||
+ " -- CREATE UNIQUE INDEX pg_language_oid_index ON pg_language USING btree (oid); -- table "
|
||||
+ "pg_language\n"
|
||||
+ " tableScript:= tableScript || chr(13)||chr(10) || chr(13)||chr(10) || array_to_string(\n"
|
||||
+ " array(\n"
|
||||
+ " select 'CREATE INDEX ' || indexrelname || ' ON ' || tablename || ' USING btree '|| '(' || "
|
||||
+ "attname "
|
||||
+ "|| "
|
||||
+ "');' from (\n"
|
||||
+ " SELECT\n"
|
||||
+ " i.relname AS indexrelname , x.indkey,\n"
|
||||
+ "\n"
|
||||
+ " ( select array_to_string (\n"
|
||||
+ " array(\n"
|
||||
+ " select a.attname from pg_attribute a where attrelid=c.oid and a.attnum in ( select unnest(x"
|
||||
+ ".indkey) )\n"
|
||||
+ "\n"
|
||||
+ " )\n"
|
||||
+ " ,',' ) )as attname\n"
|
||||
+ "\n"
|
||||
+ " FROM pg_class c\n"
|
||||
+ " JOIN pg_index x ON c.oid = x.indrelid\n"
|
||||
+ " JOIN pg_class i ON i.oid = x.indexrelid\n"
|
||||
+ " LEFT JOIN pg_namespace n ON n.oid = c.relnamespace\n"
|
||||
+ " WHERE c.relname=tablename and i.relname not in\n"
|
||||
+ " ( select constraint_name from information_schema.key_column_usage where table_name=tablename )\n"
|
||||
+ " )as t\n"
|
||||
+ " ) ,','|| chr(13)||chr(10));\n"
|
||||
+ "\n"
|
||||
+ "\n"
|
||||
+ " -- COMMENT COMMENT ON COLUMN sys_activity.id IS '主键';\n"
|
||||
+ " tableScript:= tableScript || chr(13)||chr(10) || chr(13)||chr(10) || array_to_string(\n"
|
||||
+ " array(\n"
|
||||
+ " SELECT 'COMMENT ON COLUMN' || tablename || '.' || a.attname ||' IS '|| ''''|| d.description "
|
||||
+ "||''''\n"
|
||||
+ " FROM pg_class c\n"
|
||||
+ " JOIN pg_description d ON c.oid=d.objoid\n"
|
||||
+ " JOIN pg_attribute a ON c.oid = a.attrelid\n"
|
||||
+ " WHERE c.relname=tablename\n"
|
||||
+ " AND a.attnum = d.objsubid),','|| chr(13)||chr(10)) ;\n"
|
||||
+ "\n"
|
||||
+ " return tableScript;\n"
|
||||
+ "\n"
|
||||
+ " end\n"
|
||||
+ " $BODY$ LANGUAGE plpgsql;\n"
|
||||
+ "\n"
|
||||
+ " CREATE OR REPLACE FUNCTION findattname(namespace character varying, tablename character "
|
||||
+ "varying, "
|
||||
+ "ctype"
|
||||
+ " character\n"
|
||||
+ " varying)\n"
|
||||
+ " RETURNS character varying as $BODY$\n"
|
||||
+ "\n"
|
||||
+ " declare\n"
|
||||
+ " tt oid ;\n"
|
||||
+ " aname character varying default '';\n"
|
||||
+ "\n"
|
||||
+ " begin\n"
|
||||
+ " tt := oid from pg_class where relname= tablename and relnamespace =(select oid from "
|
||||
+ "pg_namespace "
|
||||
+ "where\n"
|
||||
+ " nspname=namespace) ;\n"
|
||||
+ " aname:= array_to_string(\n"
|
||||
+ " array(\n"
|
||||
+ " select a.attname from pg_attribute a\n"
|
||||
+ " where a.attrelid=tt and a.attnum in (\n"
|
||||
+ " select unnest(conkey) from pg_constraint c where contype=ctype\n"
|
||||
+ " and conrelid=tt and array_to_string(conkey,',') is not null\n"
|
||||
+ " )\n"
|
||||
+ " ),',');\n"
|
||||
+ "\n"
|
||||
+ " return aname;\n"
|
||||
+ " end\n"
|
||||
+ " $BODY$ LANGUAGE plpgsql";
|
||||
}
|
Reference in New Issue
Block a user