diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/OracleDBManage.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/OracleDBManage.java index b32d09ca..62ab5433 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/OracleDBManage.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/OracleDBManage.java @@ -1,20 +1,21 @@ package ai.chat2db.plugin.oracle; -import ai.chat2db.server.tools.common.util.EasyStringUtils; import ai.chat2db.spi.DBManage; import ai.chat2db.spi.jdbc.DefaultDBManage; -import ai.chat2db.spi.model.AsyncContext; +import ai.chat2db.spi.model.*; import ai.chat2db.spi.sql.Chat2DBContext; import ai.chat2db.spi.sql.ConnectInfo; import ai.chat2db.spi.sql.SQLExecutor; import ai.chat2db.spi.util.SqlUtils; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.List; @Slf4j public class OracleDBManage extends DefaultDBManage implements DBManage { @@ -23,12 +24,6 @@ public class OracleDBManage extends DefaultDBManage implements DBManage { "FROM user_col_comments " + "WHERE table_name = '%s' " + "AND comments IS NOT NULL"; - private static String VIEW_DDL_SQL = "SELECT DBMS_METADATA.GET_DDL('VIEW', view_name) as ddl FROM all_views WHERE owner = '%s' AND view_name = '%s'"; - private String PROCEDURE_LIST_DDL = "SELECT object_name FROM all_procedures where OWNER = '%s' and OBJECT_TYPE='PROCEDURE'"; - private static String PROCEDURE_DDL_SQL = "SELECT DBMS_METADATA.GET_DDL('PROCEDURE', object_name) as ddl FROM all_procedures WHERE owner = '%s' AND object_name = '%s'"; - private static String TRIGGER_DDL_SQL = "SELECT DBMS_METADATA.GET_DDL('TRIGGER', trigger_name) AS ddl FROM all_triggers WHERE owner = '%s' AND trigger_name = '%s'"; - private static String FUNCTION_DDL_SQL = "SELECT DBMS_METADATA.GET_DDL('FUNCTION', object_name) as ddl FROM all_procedures WHERE owner = '%s' AND object_name = '%s'"; - public void exportDatabase(Connection connection, String databaseName, String schemaName, AsyncContext asyncContext) throws SQLException { exportTables(connection, databaseName, schemaName, asyncContext); exportViews(connection, asyncContext, schemaName); @@ -93,36 +88,26 @@ public class OracleDBManage extends DefaultDBManage implements DBManage { } } - private void exportView(Connection connection, AsyncContext asyncContext, String schemaName, String viewName) throws SQLException { - String sql = String.format(VIEW_DDL_SQL, schemaName, viewName); - try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) { - if (resultSet.next()) { - StringBuilder sqlBuilder = new StringBuilder(); - sqlBuilder.append(resultSet.getString("ddl")).append(";").append("\n"); - asyncContext.write(sqlBuilder.toString()); - } - } + private void exportView(Connection connection, AsyncContext asyncContext, String schemaName, String viewName) { + Table view = Chat2DBContext.getMetaData().view(connection, null, schemaName, viewName); + asyncContext.write(view.getDdl() + ";" + "\n"); } - private void exportProcedures(Connection connection, String schemaName, AsyncContext asyncContext) throws SQLException { - String sql = String.format(PROCEDURE_LIST_DDL, schemaName); - try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) { - while (resultSet.next()) { - String procedureName = resultSet.getString("object_name"); + private void exportProcedures(Connection connection, String schemaName, AsyncContext asyncContext) { + List procedures = Chat2DBContext.getMetaData().procedures(connection, null, schemaName); + if (CollectionUtils.isNotEmpty(procedures)) { + for (Procedure procedure : procedures) { + String procedureName = procedure.getProcedureName(); exportProcedure(connection, schemaName, procedureName, asyncContext); } } + } - private void exportProcedure(Connection connection, String schemaName, String procedureName, AsyncContext asyncContext) throws SQLException { - String sql = String.format(PROCEDURE_DDL_SQL, schemaName, procedureName); - try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) { - if (resultSet.next()) { - StringBuilder sqlBuilder = new StringBuilder(); - sqlBuilder.append(resultSet.getString("ddl")).append("\n"); - asyncContext.write(sqlBuilder.toString()); - } - } + private void exportProcedure(Connection connection, String schemaName, String procedureName, AsyncContext asyncContext) { + Procedure procedure = Chat2DBContext.getMetaData().procedure(connection, null, schemaName, procedureName); + asyncContext.write(procedure.getProcedureBody() + "\n"); + } private void exportTriggers(Connection connection, String schemaName, AsyncContext asyncContext) throws SQLException { @@ -135,15 +120,10 @@ public class OracleDBManage extends DefaultDBManage implements DBManage { } } - private void exportTrigger(Connection connection, String schemaName, String triggerName, AsyncContext asyncContext) throws SQLException { - String sql = String.format(TRIGGER_DDL_SQL, schemaName, triggerName); - try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) { - if (resultSet.next()) { - StringBuilder sqlBuilder = new StringBuilder(); - sqlBuilder.append(resultSet.getString("ddl")).append(";").append("\n"); - asyncContext.write(sqlBuilder.toString()); - } - } + private void exportTrigger(Connection connection, String schemaName, String triggerName, AsyncContext asyncContext) { + Trigger trigger = Chat2DBContext.getMetaData().trigger(connection, null, schemaName, triggerName); + asyncContext.write(trigger.getTriggerBody() + ";" + "\n"); + } private void exportFunctions(Connection connection, String schemaName, AsyncContext asyncContext) throws SQLException { @@ -155,15 +135,9 @@ public class OracleDBManage extends DefaultDBManage implements DBManage { } } - private void exportFunction(Connection connection, String schemaName, String functionName, AsyncContext asyncContext) throws SQLException { - String sql = String.format(FUNCTION_DDL_SQL, schemaName, functionName); - try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) { - if (resultSet.next()) { - StringBuilder sqlBuilder = new StringBuilder(); - sqlBuilder.append(resultSet.getString("ddl")).append("\n"); - asyncContext.write(sqlBuilder.toString()); - } - } + private void exportFunction(Connection connection, String schemaName, String functionName, AsyncContext asyncContext) { + Function function = Chat2DBContext.getMetaData().function(connection, null, schemaName, functionName); + asyncContext.write(function.getFunctionBody() + "\n"); } 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 27a67b63..48cba149 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 @@ -1,12 +1,5 @@ package ai.chat2db.plugin.oracle; -import java.io.Reader; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.*; -import java.util.stream.Collectors; - import ai.chat2db.plugin.oracle.builder.OracleSqlBuilder; import ai.chat2db.plugin.oracle.type.OracleColumnTypeEnum; import ai.chat2db.plugin.oracle.type.OracleDefaultValueEnum; @@ -24,20 +17,31 @@ import jakarta.validation.constraints.NotEmpty; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import java.io.Reader; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; +import java.util.stream.Collectors; + @Slf4j 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"); + 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"); - private String PROCEDURE_LIST_DDL ="SELECT object_name FROM all_procedures where OWNER = '%s' and OBJECT_TYPE='PROCEDURE'"; + private String PROCEDURE_LIST_DDL = """ + SELECT OBJECT_NAME, OBJECT_TYPE + FROM ALL_OBJECTS + WHERE OBJECT_TYPE IN ('PROCEDURE') + AND OWNER = '%s'"""; @Override public List procedures(Connection connection, String databaseName, String schemaName) { - String sql = String.format(PROCEDURE_LIST_DDL,schemaName); + String sql = String.format(PROCEDURE_LIST_DDL, schemaName); ArrayList procedures = new ArrayList<>(); - SQLExecutor.getInstance().execute(connection, sql, resultSet->{ + SQLExecutor.getInstance().execute(connection, sql, resultSet -> { while (resultSet.next()) { Procedure procedure = new Procedure(); procedure.setProcedureName(resultSet.getString("object_name")); @@ -108,7 +112,7 @@ public class OracleMetaData extends DefaultMetaService implements MetaData { // // Fields of the LONG type cannot be retrieved using getObject. They need to be accessed using getCharacterStream, and must be read first in the sequence. Reader reader = resultSet.getCharacterStream("DATA_DEFAULT"); - if(reader != null){ + if (reader != null) { StringBuilder sb = new StringBuilder(); int charValue; while ((charValue = reader.read()) != -1) { @@ -116,19 +120,19 @@ public class OracleMetaData extends DefaultMetaService implements MetaData { } tableColumn.setDefaultValue(sb.toString()); } - }catch (Exception e){ - log.error("getDefaultValue error",e); + } catch (Exception e) { + log.error("getDefaultValue error", e); } tableColumn.setName(resultSet.getString("COLUMN_NAME")); String dataType = resultSet.getString("DATA_TYPE"); - if(dataType.contains("(")){ - dataType = dataType.substring(0,dataType.indexOf("(")).trim(); + if (dataType.contains("(")) { + dataType = dataType.substring(0, dataType.indexOf("(")).trim(); } tableColumn.setColumnType(dataType); Integer dataPrecision = resultSet.getInt("DATA_PRECISION"); - if(resultSet.getString("DATA_PRECISION") != null) { + if (resultSet.getString("DATA_PRECISION") != null) { tableColumn.setColumnSize(dataPrecision); - }else { + } else { tableColumn.setColumnSize(resultSet.getInt("DATA_LENGTH")); } // Object dataDefault = resultSet.getObject(7); @@ -137,8 +141,6 @@ public class OracleMetaData extends DefaultMetaService implements MetaData { // } - - tableColumn.setComment(resultSet.getString("COMMENTS")); tableColumn.setNullable("Y".equalsIgnoreCase(resultSet.getString("NULLABLE")) ? 1 : 0); tableColumn.setOrdinalPosition(resultSet.getInt("COLUMN_ID")); @@ -155,18 +157,23 @@ public class OracleMetaData extends DefaultMetaService implements MetaData { }); } - private static String FUNCTION_DDL_SQL = "SELECT DBMS_METADATA.GET_DDL('FUNCTION', object_name) as ddl FROM all_procedures WHERE owner = '%s' AND object_name = '%s'"; + private static String ROUTINES_SQL + = "SELECT LINE, 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, String functionName) { - String sql = String.format(FUNCTION_DDL_SQL, schemaName, functionName); + String sql = String.format(ROUTINES_SQL, "FUNCTION", schemaName, functionName); return SQLExecutor.getInstance().execute(connection, sql, resultSet -> { Function function = new Function(); function.setDatabaseName(databaseName); function.setSchemaName(schemaName); function.setFunctionName(functionName); if (resultSet.next()) { - function.setFunctionBody(resultSet.getString("ddl")); + function.setFunctionBody("CREATE " + resultSet.getString("TEXT")); } return function; @@ -188,11 +195,11 @@ public class OracleMetaData extends DefaultMetaService implements MetaData { String pkSql = String.format(SELECT_PK_SQL, schemaName, tableName); Set pkSet = new HashSet<>(); SQLExecutor.getInstance().execute(connection, pkSql, resultSet -> { - while (resultSet.next()) { - pkSet.add(resultSet.getString("CONSTRAINT_NAME")); - } - return null; - } + while (resultSet.next()) { + pkSet.add(resultSet.getString("CONSTRAINT_NAME")); + } + return null; + } ); String sql = String.format(SELECT_TABLE_INDEX, schemaName, tableName); @@ -255,55 +262,57 @@ public class OracleMetaData extends DefaultMetaService implements MetaData { public List triggers(Connection connection, String databaseName, String schemaName) { List triggers = new ArrayList<>(); return SQLExecutor.getInstance().execute(connection, String.format(TRIGGER_SQL_LIST, schemaName), - resultSet -> { - while (resultSet.next()) { - String triggerName = resultSet.getString("TRIGGER_NAME"); - Trigger trigger = new Trigger(); - trigger.setTriggerName(triggerName==null?"":triggerName.trim()); - trigger.setSchemaName(schemaName); - trigger.setDatabaseName(databaseName); - triggers.add(trigger); - } - return triggers; - }); + resultSet -> { + while (resultSet.next()) { + String triggerName = resultSet.getString("TRIGGER_NAME"); + Trigger trigger = new Trigger(); + trigger.setTriggerName(triggerName == null ? "" : triggerName.trim()); + trigger.setSchemaName(schemaName); + trigger.setDatabaseName(databaseName); + triggers.add(trigger); + } + return triggers; + }); } - private static String TRIGGER_DDL_SQL = "SELECT DBMS_METADATA.GET_DDL('TRIGGER', trigger_name) AS ddl FROM all_triggers WHERE owner = '%s' AND trigger_name = '%s'"; + + private static final String TRIGGER_DDL_SQL = "SELECT DBMS_METADATA.GET_DDL('TRIGGER', '%s', '%s') as ddl FROM DUAL"; + @Override public Trigger trigger(Connection connection, @NotEmpty String databaseName, String schemaName, String triggerName) { - - - String sql = String.format(TRIGGER_DDL_SQL, schemaName, triggerName); + String sql = String.format(TRIGGER_DDL_SQL, triggerName, schemaName); return SQLExecutor.getInstance().execute(connection, sql, resultSet -> { Trigger trigger = new Trigger(); trigger.setDatabaseName(databaseName); trigger.setSchemaName(schemaName); trigger.setTriggerName(triggerName); - if (resultSet.next()) { + while (resultSet.next()) { trigger.setTriggerBody(resultSet.getString("ddl")); } return trigger; }); } - private static String PROCEDURE_DDL_SQL = "SELECT DBMS_METADATA.GET_DDL('PROCEDURE', object_name) as ddl FROM all_procedures WHERE owner = '%s' AND object_name = '%s'"; + @Override public Procedure procedure(Connection connection, @NotEmpty String databaseName, String schemaName, String procedureName) { - String sql = String.format(PROCEDURE_DDL_SQL, schemaName, procedureName); + String sql = String.format(ROUTINES_SQL, "PROCEDURE", schemaName, procedureName); return SQLExecutor.getInstance().execute(connection, sql, resultSet -> { Procedure procedure = new Procedure(); - if (resultSet.next()) { - procedure.setDatabaseName(databaseName); - procedure.setSchemaName(schemaName); - procedure.setProcedureName(procedureName); - procedure.setProcedureBody(resultSet.getString("ddl")); + procedure.setDatabaseName(databaseName); + procedure.setSchemaName(schemaName); + procedure.setProcedureName(procedureName); + StringBuilder bodyBuilder = new StringBuilder("CREATE "); + while (resultSet.next()) { + bodyBuilder.append(resultSet.getString("TEXT")).append("\n"); } + procedure.setProcedureBody(bodyBuilder.toString()); return procedure; }); } - private static String VIEW_DDL_SQL = "SELECT DBMS_METADATA.GET_DDL('VIEW', view_name) as ddl FROM all_views WHERE owner = '%s' AND view_name = '%s'"; + private static String VIEW_DDL_SQL = "SELECT VIEW_NAME, TEXT FROM ALL_VIEWS WHERE OWNER = '%s' AND VIEW_NAME = '%s'"; @Override public Table view(Connection connection, String databaseName, String schemaName, String viewName) { @@ -314,7 +323,7 @@ public class OracleMetaData extends DefaultMetaService implements MetaData { table.setSchemaName(schemaName); table.setName(viewName); if (resultSet.next()) { - table.setDdl(resultSet.getString("ddl")); + table.setDdl("CREATE VIEW " + viewName + " AS " + resultSet.getString("TEXT")); } return table; });