From 9645e8a2127e94cfe1cf71061c037af10b2dff29 Mon Sep 17 00:00:00 2001 From: jingtian Date: Thu, 28 Dec 2023 11:39:23 +0800 Subject: [PATCH 1/5] implement OdcDBStructureComparator --- libs/db-browser/pom.xml | 2 +- .../tools/dbbrowser/editor/DBTableEditor.java | 6 +- .../editor/DBTablePartitionEditor.java | 4 +- .../editor/mysql/MySQLTableEditor.java | 18 +- .../editor/oracle/OracleTableEditor.java | 2 +- .../tools/dbbrowser/model/DBTableColumn.java | 2 +- .../dbbrowser/model/DBTableConstraint.java | 2 +- .../tools/dbbrowser/model/DBTableIndex.java | 3 +- .../MySQLNoGreaterThan5740SchemaAccessor.java | 3 + ...OBMySQLBetween2277And3XSchemaAccessor.java | 3 + ...BMySQLNoGreaterThan1479SchemaAccessor.java | 3 + .../editor/MySQLTableEditorTest.java | 4 +- pom.xml | 2 +- .../OdcDBStructureComparatorTest.java | 403 ++++++++++++++++++ .../structurecompare/source_drop.sql | 15 + .../structurecompare/source_schema_ddl.sql | 90 ++++ .../structurecompare/target_drop.sql | 13 + .../structurecompare/target_schema_ddl.sql | 93 ++++ .../odc/service/plugin/SchemaPluginUtil.java | 5 + .../DBStructureComparator.java | 40 ++ .../OdcDBStructureComparator.java | 146 +++++++ .../DBObjectStructureComparator.java | 57 +++ .../TableColumnStructureComparator.java | 124 ++++++ .../TableConstraintStructureComparator.java | 149 +++++++ .../TableIndexStructureComparator.java | 140 ++++++ .../TablePartitionStructureComparator.java | 93 ++++ .../TableStructureComparator.java | 282 ++++++++++++ .../model/ComparisonResult.java | 31 ++ .../model/DBObjectComparisonResult.java | 60 +++ .../model/DBStructureComparisonConfig.java | 46 ++ .../test/database/TestDBConfiguration.java | 4 +- .../api/SchemaBrowserExtensionPoint.java | 34 ++ .../schema/mysql/MySQLDatabaseExtension.java | 4 +- .../schema/mysql/MySQLFunctionExtension.java | 4 +- .../schema/mysql/MySQLProcedureExtension.java | 4 +- .../mysql/MySQLSchemaBrowserExtension.java | 51 +++ .../schema/mysql/MySQLTableExtension.java | 12 +- .../schema/mysql/MySQLViewExtension.java | 4 +- .../OBMySQLSchemaBrowserExtension.java | 43 ++ .../schema/obmysql/OBMySQLTableExtension.java | 20 +- .../schema/obmysql/utils/DBAccessorUtil.java | 23 + .../OBOracleSchemaBrowserExtension.java | 43 ++ .../oboracle/OBOracleTableExtension.java | 8 +- .../schema/oboracle/utils/DBAccessorUtil.java | 11 + ...ShardingOBMySQLSchemaBrowserExtension.java | 50 +++ .../ODPShardingOBMySQLTableExtension.java | 11 +- 46 files changed, 2098 insertions(+), 69 deletions(-) create mode 100644 server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparatorTest.java create mode 100644 server/integration-test/src/test/resources/structurecompare/source_drop.sql create mode 100644 server/integration-test/src/test/resources/structurecompare/source_schema_ddl.sql create mode 100644 server/integration-test/src/test/resources/structurecompare/target_drop.sql create mode 100644 server/integration-test/src/test/resources/structurecompare/target_schema_ddl.sql create mode 100644 server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DBStructureComparator.java create mode 100644 server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparator.java create mode 100644 server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBObjectStructureComparator.java create mode 100644 server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableColumnStructureComparator.java create mode 100644 server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableConstraintStructureComparator.java create mode 100644 server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableIndexStructureComparator.java create mode 100644 server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TablePartitionStructureComparator.java create mode 100644 server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java create mode 100644 server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/ComparisonResult.java create mode 100644 server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBObjectComparisonResult.java create mode 100644 server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBStructureComparisonConfig.java create mode 100644 server/plugins/schema-plugin-api/src/main/java/com/oceanbase/odc/plugin/schema/api/SchemaBrowserExtensionPoint.java create mode 100644 server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLSchemaBrowserExtension.java create mode 100644 server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLSchemaBrowserExtension.java create mode 100644 server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleSchemaBrowserExtension.java create mode 100644 server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLSchemaBrowserExtension.java diff --git a/libs/db-browser/pom.xml b/libs/db-browser/pom.xml index 9703a0749e..bef24d5df9 100644 --- a/libs/db-browser/pom.xml +++ b/libs/db-browser/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.oceanbase db-browser - 1.0.4 + 1.0.5 db-browser https://github.com/oceanbase/odc/tree/main/libs/db-browser diff --git a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/DBTableEditor.java b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/DBTableEditor.java index 82ca3c9ac2..ad4e73265c 100644 --- a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/DBTableEditor.java +++ b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/DBTableEditor.java @@ -182,7 +182,7 @@ public String generateUpdateObjectDDLWithoutRenaming(@NotNull DBTable oldTable, return sqlBuilder.toString(); } - protected abstract void generateUpdateTableOptionDDL(DBTable oldTable, DBTable newTable, SqlBuilder sqlBuilder); + public abstract void generateUpdateTableOptionDDL(DBTable oldTable, DBTable newTable, SqlBuilder sqlBuilder); protected abstract SqlBuilder sqlBuilder(); @@ -199,7 +199,7 @@ protected String getFullyQualifiedTableName(@NotNull DBTable table) { * 排除唯一性约束
* 创建一个唯一索引,OB 会自动创建一个同名唯一约束;因此在生成 DDL 时,如果已有唯一索引,则需要忽略掉同名唯一约束,不然生成的 DDL 会无法执行
*/ - protected List excludeUniqueConstraint(List indexes, + public List excludeUniqueConstraint(List indexes, List constraints) { if (CollectionUtils.isEmpty(indexes) || CollectionUtils.isEmpty(constraints)) { return constraints; @@ -219,7 +219,7 @@ protected List excludeUniqueConstraint(List ind * 排除主键约束对应的唯一索引
* 创建主键约束的时候,OB 会自动创建一个同名唯一索引;因此在生成 DDL 时,如果已有主键约束,则需要忽略掉同名唯一索引,不然生成的 DDL 会无法执行
*/ - protected List excludePrimaryKeyIndex(List indexes, + public List excludePrimaryKeyIndex(List indexes, List constraints) { if (CollectionUtils.isEmpty(indexes) || CollectionUtils.isEmpty(constraints)) { return indexes; diff --git a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/DBTablePartitionEditor.java b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/DBTablePartitionEditor.java index e475c965a2..9633727678 100644 --- a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/DBTablePartitionEditor.java +++ b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/DBTablePartitionEditor.java @@ -246,10 +246,10 @@ protected abstract String generateAddPartitionDefinitionDDL(@NotNull DBTablePart protected String getFullyQualifiedTableName(@NotNull DBTablePartition partition) { SqlBuilder sqlBuilder = sqlBuilder(); if (StringUtils.isNotEmpty(partition.getSchemaName())) { - sqlBuilder.identifier(partition.getSchemaName()).append("."); + sqlBuilder.identifier(partition.getSchemaName()); } if (StringUtils.isNotEmpty(partition.getTableName())) { - sqlBuilder.identifier(partition.getTableName()); + sqlBuilder.append(".").identifier(partition.getTableName()); } return sqlBuilder.toString(); } diff --git a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/mysql/MySQLTableEditor.java b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/mysql/MySQLTableEditor.java index 87cc576509..a7a7b2ea2d 100644 --- a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/mysql/MySQLTableEditor.java +++ b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/mysql/MySQLTableEditor.java @@ -85,7 +85,7 @@ protected void appendTableOptions(DBTable table, SqlBuilder sqlBuilder) { protected void appendMoreTableOptions(DBTable table, SqlBuilder sqlBuilder) {} @Override - protected void generateUpdateTableOptionDDL(@NonNull DBTable oldTable, @NonNull DBTable newTable, + public void generateUpdateTableOptionDDL(@NonNull DBTable oldTable, @NonNull DBTable newTable, @NonNull SqlBuilder sqlBuilder) { if (Objects.isNull(oldTable.getTableOptions()) || Objects.isNull(newTable.getTableOptions())) { return; @@ -97,6 +97,22 @@ protected void generateUpdateTableOptionDDL(@NonNull DBTable oldTable, @NonNull .value(newTable.getTableOptions().getComment()) .append(";\n"); } + if (!StringUtils.equals(oldTable.getTableOptions().getCharsetName(), + newTable.getTableOptions().getCharsetName())) { + sqlBuilder.append("ALTER TABLE ") + .append(getFullyQualifiedTableName(newTable)) + .append(" CHARACTER SET = ") + .append(newTable.getTableOptions().getCharsetName()) + .append(";\n"); + } + if (!StringUtils.equals(oldTable.getTableOptions().getCollationName(), + newTable.getTableOptions().getCollationName())) { + sqlBuilder.append("ALTER TABLE ") + .append(getFullyQualifiedTableName(newTable)) + .append(" COLLATE = ") + .append(newTable.getTableOptions().getCollationName()) + .append(";\n"); + } } @Override diff --git a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/oracle/OracleTableEditor.java b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/oracle/OracleTableEditor.java index cd36965a36..e81d5aae16 100644 --- a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/oracle/OracleTableEditor.java +++ b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/editor/oracle/OracleTableEditor.java @@ -73,7 +73,7 @@ protected void appendTableOptions(DBTable table, SqlBuilder sqlBuilder) { } @Override - protected void generateUpdateTableOptionDDL(DBTable oldTable, DBTable newTable, SqlBuilder sqlBuilder) { + public void generateUpdateTableOptionDDL(DBTable oldTable, DBTable newTable, SqlBuilder sqlBuilder) { if (!StringUtils.equals(oldTable.getTableOptions().getComment(), newTable.getTableOptions().getComment())) { appendTableComment(newTable, sqlBuilder); } diff --git a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/model/DBTableColumn.java b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/model/DBTableColumn.java index ad0096e77d..ba0fd057bb 100644 --- a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/model/DBTableColumn.java +++ b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/model/DBTableColumn.java @@ -35,7 +35,7 @@ * columnName. */ @Data -@EqualsAndHashCode(exclude = {"name", "warning", "schemaName", "tableName", "ordinalPosition"}) +@EqualsAndHashCode(exclude = {"name", "warning", "schemaName", "tableName", "ordinalPosition", "keyType"}) public class DBTableColumn implements DBObject, DBObjectWarningDescriptor { /** * 所属 schemaName diff --git a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/model/DBTableConstraint.java b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/model/DBTableConstraint.java index 4cac4a5f0a..6ed0f71c4e 100644 --- a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/model/DBTableConstraint.java +++ b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/model/DBTableConstraint.java @@ -26,7 +26,7 @@ @Data @EqualsAndHashCode( - exclude = {"name", "warning", "schemaName", "tableName", "createTime", "updateTime", "ordinalPosition", + exclude = {"name", "warning", "schemaName", "owner", "tableName", "createTime", "updateTime", "ordinalPosition", "enabled"}) public class DBTableConstraint implements DBObject, DBObjectWarningDescriptor { /** diff --git a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/model/DBTableIndex.java b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/model/DBTableIndex.java index 668959197f..803db47010 100644 --- a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/model/DBTableIndex.java +++ b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/model/DBTableIndex.java @@ -26,7 +26,8 @@ @Data @EqualsAndHashCode( - exclude = {"name", "warning", "schemaName", "tableName", "createTime", "updateTime", "ordinalPosition"}) + exclude = {"name", "warning", "owner", "schemaName", "tableName", "createTime", "updateTime", + "ordinalPosition"}) public class DBTableIndex implements DBObject, DBObjectWarningDescriptor { /** * 所属 schemaName diff --git a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/schema/mysql/MySQLNoGreaterThan5740SchemaAccessor.java b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/schema/mysql/MySQLNoGreaterThan5740SchemaAccessor.java index 77d7c74913..4394b5ac04 100644 --- a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/schema/mysql/MySQLNoGreaterThan5740SchemaAccessor.java +++ b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/schema/mysql/MySQLNoGreaterThan5740SchemaAccessor.java @@ -849,6 +849,9 @@ public DBTablePartition getPartition(String schemaName, String tableName) { DBTablePartition partition = new DBTablePartition(); DBTablePartition subPartition = new DBTablePartition(); partition.setSubpartition(subPartition); + partition.setSchemaName(schemaName); + partition.setTableName(tableName); + subPartition.setSchemaName(schemaName); DBTablePartitionOption partitionOption = new DBTablePartitionOption(); partitionOption.setType(DBTablePartitionType.NOT_PARTITIONED); diff --git a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/schema/mysql/OBMySQLBetween2277And3XSchemaAccessor.java b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/schema/mysql/OBMySQLBetween2277And3XSchemaAccessor.java index 7e8ce67aaf..6c66d79673 100644 --- a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/schema/mysql/OBMySQLBetween2277And3XSchemaAccessor.java +++ b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/schema/mysql/OBMySQLBetween2277And3XSchemaAccessor.java @@ -137,6 +137,9 @@ public DBTablePartition getPartition(String schemaName, String tableName) { DBTablePartitionOption partitionOption = new DBTablePartitionOption(); partitionOption.setType(DBTablePartitionType.NOT_PARTITIONED); partition.setPartitionOption(partitionOption); + partition.setSchemaName(schemaName); + partition.setTableName(tableName); + subPartition.setSchemaName(schemaName); DBTablePartitionOption subPartitionOption = new DBTablePartitionOption(); subPartitionOption.setType(DBTablePartitionType.NOT_PARTITIONED); diff --git a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/schema/mysql/OBMySQLNoGreaterThan1479SchemaAccessor.java b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/schema/mysql/OBMySQLNoGreaterThan1479SchemaAccessor.java index 6408f495f4..45358506ac 100644 --- a/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/schema/mysql/OBMySQLNoGreaterThan1479SchemaAccessor.java +++ b/libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/schema/mysql/OBMySQLNoGreaterThan1479SchemaAccessor.java @@ -97,6 +97,9 @@ public DBTablePartition getPartition(String schemaName, String tableName) { } DBTablePartition subPartition = new DBTablePartition(); partition.setSubpartition(subPartition); + partition.setSchemaName(schemaName); + partition.setTableName(tableName); + subPartition.setSchemaName(schemaName); DBTablePartitionOption partitionOption = new DBTablePartitionOption(); partitionOption.setType(DBTablePartitionType.NOT_PARTITIONED); diff --git a/libs/db-browser/src/test/java/com/oceanbase/tools/dbbrowser/editor/MySQLTableEditorTest.java b/libs/db-browser/src/test/java/com/oceanbase/tools/dbbrowser/editor/MySQLTableEditorTest.java index a946f53b39..54c009ccfc 100644 --- a/libs/db-browser/src/test/java/com/oceanbase/tools/dbbrowser/editor/MySQLTableEditorTest.java +++ b/libs/db-browser/src/test/java/com/oceanbase/tools/dbbrowser/editor/MySQLTableEditorTest.java @@ -63,7 +63,9 @@ public void generateUpdateObjectDDL() { String ddl = tableEditor.generateUpdateObjectDDL(DBObjectUtilsTest.getOldTable(), DBObjectUtilsTest.getNewTable()); Assert.assertEquals( - "ALTER TABLE `old_table` RENAME TO `whatever_table`;\n", + "ALTER TABLE `old_table` RENAME TO `whatever_table`;\n" + + "ALTER TABLE `whatever_schema`.`whatever_table` CHARACTER SET = utf8mb4;\n" + + "ALTER TABLE `whatever_schema`.`whatever_table` COLLATE = utf8mb4_bin;\n", ddl); } diff --git a/pom.xml b/pom.xml index ea3361c1c2..5806fb5ced 100644 --- a/pom.xml +++ b/pom.xml @@ -93,7 +93,7 @@ 4.20.19.ALL 4.10.0 2.10.0 - 1.0.4 + 1.0.5 1.2.0 3.10.0 1.64 diff --git a/server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparatorTest.java b/server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparatorTest.java new file mode 100644 index 0000000000..32870281d8 --- /dev/null +++ b/server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparatorTest.java @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.service.structurecompare; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.springframework.beans.BeanUtils; +import org.springframework.jdbc.core.JdbcTemplate; + +import com.oceanbase.odc.PluginTestEnv; +import com.oceanbase.odc.core.shared.constant.DialectType; +import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; +import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.odc.service.structurecompare.model.DBStructureComparisonConfig; +import com.oceanbase.odc.test.database.TestDBConfiguration; +import com.oceanbase.odc.test.database.TestDBConfigurations; +import com.oceanbase.odc.test.util.FileUtil; +import com.oceanbase.tools.dbbrowser.model.DBObjectType; + +/** + * @author jingtian + * @date 2024/1/8 + * @since ODC_release_4.2.4 + */ +public class OdcDBStructureComparatorTest extends PluginTestEnv { + private static final String BASE_PATH = "src/test/resources/structurecompare/"; + private static String sourceSchemaDdl = FileUtil.loadAsString(BASE_PATH + "source_schema_ddl.sql"); + private static String targetSchemaDdl = FileUtil.loadAsString(BASE_PATH + "target_schema_ddl.sql"); + private static final String sourceDrop = FileUtil.loadAsString(BASE_PATH + "source_drop.sql"); + private static final String targetDrop = FileUtil.loadAsString(BASE_PATH + "target_drop.sql"); + private static TestDBConfiguration configuration = TestDBConfigurations.getInstance().getTestOBMysqlConfiguration(); + private static JdbcTemplate jdbcTemplate = new JdbcTemplate(configuration.getDataSource()); + private final static String sourceSchemaName = generateSchemaName() + "_source"; + private final static String targetSchemaName = generateSchemaName() + "_target"; + private static TestDBConfiguration srcConfiguration = new TestDBConfiguration(); + private static TestDBConfiguration tgtConfiguration = new TestDBConfiguration(); + private static OdcDBStructureComparator comparator = new OdcDBStructureComparator(); + private static List results; + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @BeforeClass + public static void setUp() throws SQLException { + jdbcTemplate.execute("create database `" + sourceSchemaName + "`"); + jdbcTemplate.execute("create database `" + targetSchemaName + "`"); + + BeanUtils.copyProperties(configuration, srcConfiguration); + srcConfiguration.setDefaultDBName(sourceSchemaName); + srcConfiguration.initDataSource(); + + BeanUtils.copyProperties(configuration, tgtConfiguration); + tgtConfiguration.setDefaultDBName(targetSchemaName); + tgtConfiguration.initDataSource(); + + jdbcTemplate.execute("use `" + sourceSchemaName + "`"); + jdbcTemplate.execute(sourceDrop); + jdbcTemplate.execute(sourceSchemaDdl); + jdbcTemplate.execute("use `" + targetSchemaName + "`"); + jdbcTemplate.execute(targetDrop); + jdbcTemplate.execute(targetSchemaDdl); + jdbcTemplate.execute("use `" + configuration.getDefaultDBName() + "`"); + + results = comparator.compare(getSourceConfig(srcConfiguration), + getTargetConfig(tgtConfiguration)); + } + + @AfterClass + public static void clear() { + jdbcTemplate.execute("drop database `" + sourceSchemaName + "`"); + jdbcTemplate.execute("drop database `" + targetSchemaName + "`"); + } + + private static String generateSchemaName() { + return "odc_db_compare_test_" + UUID.randomUUID().toString().replaceAll("-", "").substring(0, 15).toLowerCase(); + } + + private static DBStructureComparisonConfig getSourceConfig(TestDBConfiguration configuration) { + DBStructureComparisonConfig srcConfig = new DBStructureComparisonConfig(); + srcConfig.setSchemaName(sourceSchemaName); + srcConfig.setDialectType(DialectType.OB_MYSQL); + srcConfig.setDataSource(configuration.getDataSource()); + srcConfig.setToComparedObjectTypes(Collections.singleton(DBObjectType.TABLE)); + return srcConfig; + } + + private static DBStructureComparisonConfig getTargetConfig(TestDBConfiguration configuration) { + DBStructureComparisonConfig srcConfig = new DBStructureComparisonConfig(); + srcConfig.setSchemaName(targetSchemaName); + srcConfig.setDialectType(DialectType.OB_MYSQL); + srcConfig.setDataSource(configuration.getDataSource()); + srcConfig.setToComparedObjectTypes(Collections.singleton(DBObjectType.TABLE)); + return srcConfig; + } + + @Test + public void test_srcDialectTypeNotEqualsToTgtDialectType_throwException() throws SQLException { + DBStructureComparisonConfig targetConfig = getTargetConfig(tgtConfiguration); + targetConfig.setDialectType(DialectType.OB_ORACLE); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("The dialect type of source and target schema must be equal"); + comparator.compare(getSourceConfig(srcConfiguration), targetConfig); + } + + @Test + public void test_notSupportedDialect_throwException() throws SQLException { + DBStructureComparisonConfig sourceConfig = getSourceConfig(srcConfiguration); + sourceConfig.setDialectType(DialectType.ORACLE); + DBStructureComparisonConfig targetConfig = getTargetConfig(tgtConfiguration); + targetConfig.setDialectType(DialectType.ORACLE); + thrown.expect(UnsupportedOperationException.class); + thrown.expectMessage("Unsupported dialect type for schema structure comparison: ORACLE"); + comparator.compare(sourceConfig, targetConfig); + } + + @Test + public void test_notSupportedDBObjectType_throwException() throws SQLException { + DBStructureComparisonConfig sourceConfig = getSourceConfig(srcConfiguration); + sourceConfig.setToComparedObjectTypes(Collections.singleton(DBObjectType.VIEW)); + thrown.expectMessage("Unsupported database object type for schema structure comparison: VIEW"); + comparator.compare(sourceConfig, getTargetConfig(tgtConfiguration)); + } + + @Test + public void test_GetCreateTableResultsByDependencyOrder() { + int dependentTableOrder1 = 0; + int dependentTableOrder2 = 0; + int foreignKeyTableOrder = 0; + List toCreate = results.stream().filter( + item -> item.getComparisonResult().equals(ComparisonResult.ONLY_IN_SOURCE)).collect( + Collectors.toList()); + for (int i = 0; i < toCreate.size(); i++) { + if (toCreate.get(i).getDbObjectName().equals("fk_dependency_only_in_source1")) { + dependentTableOrder1 = i; + } else if (toCreate.get(i).getDbObjectName().equals("fk_dependency_only_in_source2")) { + dependentTableOrder2 = i; + } else if (toCreate.get(i).getDbObjectName().equals("fk_only_in_source")) { + foreignKeyTableOrder = i; + } + } + Assert.assertTrue(dependentTableOrder1 < foreignKeyTableOrder && dependentTableOrder2 < foreignKeyTableOrder); + } + + @Test + public void test_GetDroppedTableResultsByDependencyOrder() { + int dependentTableOrder1 = 0; + int dependentTableOrder2 = 0; + int foreignKeyTableOrder = 0; + List toDrop = results.stream().filter( + item -> item.getComparisonResult().equals(ComparisonResult.ONLY_IN_TARGET)).collect( + Collectors.toList()); + for (int i = 0; i < toDrop.size(); i++) { + if (toDrop.get(i).getDbObjectName().equals("fk_dependency_only_in_target1")) { + dependentTableOrder1 = i; + } else if (toDrop.get(i).getDbObjectName().equals("fk_dependency_only_in_target2")) { + dependentTableOrder2 = i; + } else if (toDrop.get(i).getDbObjectName().equals("fk_only_in_target")) { + foreignKeyTableOrder = i; + } + } + Assert.assertTrue(dependentTableOrder1 > foreignKeyTableOrder && dependentTableOrder2 > foreignKeyTableOrder); + } + + @Test + public void test_updatePrimaryKey() { + DBObjectComparisonResult updatePk = results.stream().filter( + result -> result.getDbObjectName().equals("primary_key_test")).collect(Collectors.toList()).get(0); + + DBObjectComparisonResult actual = updatePk.getSubDBObjectComparisonResult().stream().filter( + item -> item.getDbObjectType().equals(DBObjectType.CONSTRAINT)).collect(Collectors.toList()).get(0); + DBObjectComparisonResult expect = + new DBObjectComparisonResult(DBObjectType.CONSTRAINT, "PRIMARY", sourceSchemaName, targetSchemaName); + expect.setChangeScript("ALTER TABLE `" + targetSchemaName + "`.`primary_key_test` DROP PRIMARY KEY;\n" + + "ALTER TABLE `" + targetSchemaName + "`.`primary_key_test` ADD CONSTRAINT `PRIMARY` " + + "PRIMARY KEY (`c1`);\n"); + expect.setComparisonResult(ComparisonResult.INCONSISTENT); + Assert.assertEquals(expect, actual); + } + + @Test + public void test_updateColumns() { + DBObjectComparisonResult result = results.stream().filter( + item -> item.getDbObjectName().equals("update_column")).collect(Collectors.toList()).get(0); + + DBObjectComparisonResult id = + new DBObjectComparisonResult(DBObjectType.COLUMN, "id", sourceSchemaName, targetSchemaName); + id.setComparisonResult(ComparisonResult.CONSISTENT); + + DBObjectComparisonResult c1 = + new DBObjectComparisonResult(DBObjectType.COLUMN, "c1", sourceSchemaName, targetSchemaName); + c1.setComparisonResult(ComparisonResult.INCONSISTENT); + c1.setChangeScript("ALTER TABLE `" + targetSchemaName + + "`.`update_column` MODIFY COLUMN `c1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL;\n"); + + DBObjectComparisonResult c2 = + new DBObjectComparisonResult(DBObjectType.COLUMN, "c2", sourceSchemaName, targetSchemaName); + c2.setComparisonResult(ComparisonResult.INCONSISTENT); + c2.setChangeScript( + "ALTER TABLE `" + targetSchemaName + "`.`update_column` MODIFY COLUMN `c2` date NOT NULL;\n"); + + DBObjectComparisonResult c3 = + new DBObjectComparisonResult(DBObjectType.COLUMN, "c3", sourceSchemaName, targetSchemaName); + c3.setComparisonResult(ComparisonResult.INCONSISTENT); + c3.setChangeScript( + "ALTER TABLE `" + targetSchemaName + "`.`update_column` MODIFY COLUMN `c3` decimal(10, 2) NOT NULL;\n"); + + DBObjectComparisonResult only_in_target_col = new DBObjectComparisonResult(DBObjectType.COLUMN, + "only_in_target_col", sourceSchemaName, targetSchemaName); + only_in_target_col.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); + only_in_target_col.setChangeScript( + "ALTER TABLE `" + targetSchemaName + "`.`update_column` DROP COLUMN `only_in_target_col`;\n"); + + DBObjectComparisonResult only_in_source_col = new DBObjectComparisonResult(DBObjectType.COLUMN, + "only_in_source_col", sourceSchemaName, targetSchemaName); + only_in_source_col.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); + only_in_source_col.setChangeScript("ALTER TABLE `" + targetSchemaName + + "`.`update_column` ADD COLUMN `only_in_source_col` int(11) NULL ;\n"); + + List expected = new ArrayList<>(); + expected.addAll(Arrays.asList(only_in_target_col, id, c1, c2, c3, only_in_source_col)); + + List actual = result.getSubDBObjectComparisonResult().stream().filter( + item -> item.getDbObjectType().equals(DBObjectType.COLUMN)).collect(Collectors.toList()); + + Assert.assertEquals(expected, actual); + } + + @Test + public void test_updateIndex() { + DBObjectComparisonResult result = results.stream().filter( + item -> item.getDbObjectName().equals("update_index")).collect(Collectors.toList()).get(0); + + List actual = result.getSubDBObjectComparisonResult().stream().filter( + item -> item.getDbObjectType().equals(DBObjectType.INDEX)).collect(Collectors.toList()); + + DBObjectComparisonResult idx1 = + new DBObjectComparisonResult(DBObjectType.INDEX, "idx1", sourceSchemaName, targetSchemaName); + idx1.setComparisonResult(ComparisonResult.INCONSISTENT); + idx1.setChangeScript("ALTER TABLE `" + targetSchemaName + "`.`update_index` DROP INDEX " + + "`idx1`;\n" + + "CREATE INDEX `idx1` USING BTREE ON `" + targetSchemaName + "`" + + ".`update_index` (`c1`) LOCAL;\n"); + + DBObjectComparisonResult idx_only_in_source = new DBObjectComparisonResult(DBObjectType.INDEX, + "idx_only_in_source", sourceSchemaName, targetSchemaName); + idx_only_in_source.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); + idx_only_in_source.setChangeScript("CREATE INDEX `idx_only_in_source` USING BTREE ON `" + targetSchemaName + + "`.`update_index` (`c2`) LOCAL;\n"); + + DBObjectComparisonResult idx_only_in_target = new DBObjectComparisonResult(DBObjectType.INDEX, + "idx_only_in_target", sourceSchemaName, targetSchemaName); + idx_only_in_target.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); + idx_only_in_target.setChangeScript( + "ALTER TABLE `" + targetSchemaName + "`.`update_index` DROP INDEX `idx_only_in_target`;\n"); + + List expected = new ArrayList<>(); + expected.addAll(Arrays.asList(idx1, idx_only_in_target, idx_only_in_source)); + Assert.assertEquals(expected, actual); + } + + @Test + public void test_updateConstraint() { + DBObjectComparisonResult actual1 = results.stream().filter( + item -> item.getDbObjectName().equals("add_foreign_key_constraint")).collect(Collectors.toList()).get(0) + .getSubDBObjectComparisonResult().stream().filter( + item -> item.getDbObjectType().equals(DBObjectType.CONSTRAINT) + && !item.getDbObjectName().equals("PRIMARY")) + .collect(Collectors.toList()).get(0); + + DBObjectComparisonResult actual2 = results.stream().filter( + item -> item.getDbObjectName().equals("drop_foreign_key_constraint")).collect(Collectors.toList()) + .get(0).getSubDBObjectComparisonResult().stream().filter( + item -> item.getDbObjectType().equals(DBObjectType.CONSTRAINT) + && !item.getDbObjectName().equals("PRIMARY")) + .collect(Collectors.toList()).get(0); + + DBObjectComparisonResult excepted1 = new DBObjectComparisonResult(DBObjectType.CONSTRAINT, + actual1.getDbObjectName(), sourceSchemaName, targetSchemaName); + excepted1.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); + excepted1.setChangeScript("ALTER TABLE `" + targetSchemaName + "`.`add_foreign_key_constraint` ADD CONSTRAINT `" + + actual1.getDbObjectName() + "` FOREIGN KEY (`product_id`) REFERENCES `" + targetSchemaName + + "`.`fk_dependency` (`product_id`);\n"); + + DBObjectComparisonResult excepted2 = new DBObjectComparisonResult(DBObjectType.CONSTRAINT, + actual2.getDbObjectName(), sourceSchemaName, targetSchemaName); + excepted2.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); + excepted2.setChangeScript("ALTER TABLE `" + targetSchemaName + + "`.`drop_foreign_key_constraint` DROP FOREIGN KEY `" + actual2.getDbObjectName() + "`;\n"); + + Assert.assertEquals(excepted1, actual1); + Assert.assertEquals(excepted2, actual2); + } + + @Test + public void test_updatePartition() { + DBObjectComparisonResult actual = results.stream().filter( + item -> item.getDbObjectName().equals("update_partition")).collect(Collectors.toList()).get(0) + .getSubDBObjectComparisonResult().stream().filter( + item -> item.getDbObjectType().equals(DBObjectType.PARTITION)) + .collect(Collectors.toList()).get(0); + + DBObjectComparisonResult excepted = + new DBObjectComparisonResult(DBObjectType.PARTITION, sourceSchemaName, targetSchemaName); + excepted.setComparisonResult(ComparisonResult.INCONSISTENT); + excepted.setChangeScript("ALTER TABLE `" + targetSchemaName + "`.`update_partition` DROP PARTITION (p4);\n"); + Assert.assertEquals(excepted, actual); + } + + @Test + public void test_converseToPartitionedTable() { + DBObjectComparisonResult actual = results.stream().filter( + item -> item.getDbObjectName().equals("converse_to_partition_table")).collect(Collectors.toList()) + .get(0).getSubDBObjectComparisonResult().stream().filter( + item -> item.getDbObjectType().equals(DBObjectType.PARTITION)) + .collect(Collectors.toList()).get(0); + + DBObjectComparisonResult excepted = + new DBObjectComparisonResult(DBObjectType.PARTITION, sourceSchemaName, targetSchemaName); + excepted.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); + excepted.setChangeScript("ALTER TABLE `" + targetSchemaName + "`.`converse_to_partition_table` PARTITION" + + " BY KEY(`id`) \n" + + "PARTITIONS 4(\n" + + "PARTITION `p0`,\n" + + "PARTITION `p1`,\n" + + "PARTITION `p2`,\n" + + "PARTITION `p3`\n" + + ");\n"); + Assert.assertEquals(excepted, actual); + } + + @Test + public void test_converseToNonPartitionedTable_notSupported() { + DBObjectComparisonResult actual = results.stream().filter( + item -> item.getDbObjectName().equals("converse_to_non_partition_table")).collect(Collectors.toList()) + .get(0).getSubDBObjectComparisonResult().stream().filter( + item -> item.getDbObjectType().equals(DBObjectType.PARTITION)) + .collect(Collectors.toList()).get(0); + + DBObjectComparisonResult excepted = + new DBObjectComparisonResult(DBObjectType.PARTITION, sourceSchemaName, targetSchemaName); + excepted.setComparisonResult(ComparisonResult.UNSUPPORTED); + excepted.setChangeScript("/* Unsupported operation: Convert partitioned table to non-partitioned table */\n"); + Assert.assertEquals(excepted, actual); + } + + @Test + public void test_updateTableOption() { + DBObjectComparisonResult result = results.stream().filter( + item -> item.getDbObjectName().equals("update_options")).collect(Collectors.toList()).get(0); + Assert.assertEquals(result.getComparisonResult(), ComparisonResult.INCONSISTENT); + Assert.assertEquals(result.getChangeScript(), "ALTER TABLE `" + targetSchemaName + "`" + + ".`update_options` COMMENT = 'comment1';\n" + + "ALTER TABLE `" + targetSchemaName + "`" + + ".`update_options` CHARACTER SET = utf8mb4;\n" + + "ALTER TABLE `" + targetSchemaName + "`" + + ".`update_options` COLLATE = utf8mb4_bin;\n"); + } + + @Test + public void test_compareSpecifiedTables() throws SQLException { + DBStructureComparisonConfig sourceConfig = getSourceConfig(srcConfiguration); + Map> blackListMap = new HashMap<>(); + Set set = new HashSet<>(); + set.add("update_column"); + set.add("update_index"); + set.add("fk_dependency_only_in_source1"); + set.add("fk_only_in_source"); + set.add("fk_dependency_only_in_target1"); + blackListMap.put(DBObjectType.TABLE, set); + sourceConfig.setBlackListMap(blackListMap); + + List result = comparator.compare(sourceConfig, getTargetConfig(tgtConfiguration)); + Assert.assertEquals(result.size(), 5); + } +} diff --git a/server/integration-test/src/test/resources/structurecompare/source_drop.sql b/server/integration-test/src/test/resources/structurecompare/source_drop.sql new file mode 100644 index 0000000000..d16bb4bb9b --- /dev/null +++ b/server/integration-test/src/test/resources/structurecompare/source_drop.sql @@ -0,0 +1,15 @@ +drop table if exists `fk_only_in_source`; +drop table if exists `fk_dependency_only_in_source1`; +drop table if exists `fk_dependency_only_in_source2`; +drop table if exists `primary_key_test`; +drop table if exists `update_column`; +drop table if exists `update_index`; +drop table if exists `add_foreign_key_constraint`; +drop table if exists `drop_foreign_key_constraint`; +drop table if exists `fk_dependency`; +drop table if exists `update_partition`; +drop table if exists `converse_to_partition_table`; +drop table if exists `converse_to_non_partition_table`; +drop table if exists `update_options`; + + diff --git a/server/integration-test/src/test/resources/structurecompare/source_schema_ddl.sql b/server/integration-test/src/test/resources/structurecompare/source_schema_ddl.sql new file mode 100644 index 0000000000..ba0cdb86a4 --- /dev/null +++ b/server/integration-test/src/test/resources/structurecompare/source_schema_ddl.sql @@ -0,0 +1,90 @@ +-- 按照外键依赖顺序创建表 case +CREATE TABLE `fk_dependency_only_in_source1` ( + `customer_id` INT AUTO_INCREMENT PRIMARY KEY, + `customer_name` VARCHAR(100) NOT NULL +); + +CREATE TABLE `fk_dependency_only_in_source2` ( + `product_id` INT AUTO_INCREMENT PRIMARY KEY, + `product_name` VARCHAR(100) NOT NULL +); + +CREATE TABLE `fk_only_in_source` ( + `order_id` INT AUTO_INCREMENT, + `customer_id` INT , + `product_id` INT , + `amount` DECIMAL(10, 2) NOT NULL, + PRIMARY KEY (`order_id`), + FOREIGN KEY (`customer_id`) REFERENCES `fk_dependency_only_in_source1` (`customer_id`), + FOREIGN KEY (`product_id`) REFERENCES `fk_dependency_only_in_source2` (`product_id`) +); + +-- 更新主键 case +create table `primary_key_test`(`c1` INT(11) PRIMARY KEY, `c2` int(11) NOT NULL); + +-- 更新表列 case +CREATE TABLE `update_column` ( + `id` INT(11) PRIMARY KEY, + `c1` VARCHAR(100), + `c2` date NOT NULL, + `c3` DECIMAL(10, 2) NOT NULL, + `only_in_source_col` INT(11) +); + +-- 更新索引 case +CREATE TABLE `update_index` ( + `c1` INT(11) NOT NULL, + `c2` INT(11) NOT NULL, + `C3` INT(11) NOT NULL, + INDEX `idx1` (`c1`), + INDEX `idx_only_in_source` (`c2`) +); + +-- 更新约束 case +CREATE TABLE `fk_dependency` ( + `product_id` INT AUTO_INCREMENT PRIMARY KEY, + `product_name` VARCHAR(100) NOT NULL +); + +CREATE TABLE `add_foreign_key_constraint` ( + `order_id` INT AUTO_INCREMENT, + `product_id` INT , + PRIMARY KEY (`order_id`), + FOREIGN KEY (`product_id`) REFERENCES `fk_dependency` (`product_id`) +); + +CREATE TABLE `drop_foreign_key_constraint` ( + `order_id` INT AUTO_INCREMENT, + `product_id` INT , + PRIMARY KEY (`order_id`) +); + +-- 更新分区 case +CREATE TABLE `update_partition` ( + `id` INT NOT NULL, + `created_at` DATETIME NOT NULL, + PRIMARY KEY (`id`, `created_at`) +) +PARTITION BY RANGE (YEAR(`created_at`)) ( + PARTITION p0 VALUES LESS THAN (1995), + PARTITION p1 VALUES LESS THAN (2005), + PARTITION p2 VALUES LESS THAN (2015), + PARTITION p3 VALUES LESS THAN (2025) +); + +CREATE TABLE `converse_to_partition_table` ( + `id` INT(11) AUTO_INCREMENT NOT NULL PRIMARY KEY +) +PARTITION BY KEY(`id`) +PARTITIONS 4; + +CREATE TABLE `converse_to_non_partition_table` ( + `id` INT NOT NULL, + `category` VARCHAR(100) +); + +-- 更新表属性 case +create table `update_options`( + `c1` INT(11) NOT NULL, + `c2` INT(11) NOT NULL +) CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = 'comment1'; \ No newline at end of file diff --git a/server/integration-test/src/test/resources/structurecompare/target_drop.sql b/server/integration-test/src/test/resources/structurecompare/target_drop.sql new file mode 100644 index 0000000000..f6bf56b112 --- /dev/null +++ b/server/integration-test/src/test/resources/structurecompare/target_drop.sql @@ -0,0 +1,13 @@ +drop table if exists `fk_only_in_target`; +drop table if exists `fk_dependency_only_in_target1`; +drop table if exists `fk_dependency_only_in_target2`; +drop table if exists `primary_key_test`; +drop table if exists `update_column`; +drop table if exists `update_index`; +drop table if exists `add_foreign_key_constraint`; +drop table if exists `drop_foreign_key_constraint`; +drop table if exists `fk_dependency`; +drop table if exists `update_partition`; +drop table if exists `converse_to_partition_table`; +drop table if exists `converse_to_non_partition_table`; +drop table if exists `update_options`; \ No newline at end of file diff --git a/server/integration-test/src/test/resources/structurecompare/target_schema_ddl.sql b/server/integration-test/src/test/resources/structurecompare/target_schema_ddl.sql new file mode 100644 index 0000000000..78b19fe68c --- /dev/null +++ b/server/integration-test/src/test/resources/structurecompare/target_schema_ddl.sql @@ -0,0 +1,93 @@ +-- 按照外键依赖顺序删除表 case +CREATE TABLE `fk_dependency_only_in_target1` ( + `customer_id` INT AUTO_INCREMENT PRIMARY KEY, + `customer_name` VARCHAR(100) NOT NULL +); + +CREATE TABLE `fk_dependency_only_in_target2` ( + `product_id` INT AUTO_INCREMENT PRIMARY KEY, + `product_name` VARCHAR(100) NOT NULL +); + +CREATE TABLE `fk_only_in_target` ( + `order_id` INT AUTO_INCREMENT, + `customer_id` INT , + `product_id` INT , + `amount` DECIMAL(10, 2) NOT NULL, + PRIMARY KEY (`order_id`), + FOREIGN KEY (`customer_id`) REFERENCES `fk_dependency_only_in_target1` (`customer_id`), + FOREIGN KEY (`product_id`) REFERENCES `fk_dependency_only_in_target2` (`product_id`) +); + +-- 更新主键 case +create table `primary_key_test`(`c1` INT(11) NOT NULL, `c2` INT(11) PRIMARY KEY); + +-- 更新表列 case +CREATE TABLE `update_column` ( + `id` INT(11) PRIMARY KEY, + `c1` VARCHAR(50), + `c2` INT(11) DEFAULT NULL, + `c3` DECIMAL(9, 5) NOT NULL, + `only_in_target_col` INT(11) +); + +-- 更新索引 case +CREATE TABLE `update_index` ( + `c1` INT(11) NOT NULL, + `c2` INT(11) NOT NULL, + `C3` INT(11) NOT NULL, + INDEX `idx1` (`c1`, `c3`), + INDEX `idx_only_in_target` (`c2`) +); + +-- 更新约束 case +CREATE TABLE `fk_dependency` ( + `product_id` INT AUTO_INCREMENT PRIMARY KEY, + `product_name` VARCHAR(100) NOT NULL +); + +CREATE TABLE `add_foreign_key_constraint` ( + `order_id` INT AUTO_INCREMENT, + `product_id` INT , + PRIMARY KEY (`order_id`) +); + +CREATE TABLE `drop_foreign_key_constraint` ( + `order_id` INT AUTO_INCREMENT, + `product_id` INT , + PRIMARY KEY (`order_id`), + FOREIGN KEY (`product_id`) REFERENCES `fk_dependency` (`product_id`) +); + +-- 更新分区 case +CREATE TABLE `update_partition` ( + `id` INT NOT NULL, + `created_at` DATETIME NOT NULL, + PRIMARY KEY (`id`, `created_at`) +) +PARTITION BY RANGE (YEAR(`created_at`)) ( + PARTITION p0 VALUES LESS THAN (1995), + PARTITION p1 VALUES LESS THAN (2005), + PARTITION p2 VALUES LESS THAN (2015), + PARTITION p3 VALUES LESS THAN (2025), + PARTITION p4 VALUES LESS THAN MAXVALUE +); + +CREATE TABLE `converse_to_partition_table` ( + `id` INT(11) AUTO_INCREMENT NOT NULL PRIMARY KEY +); + +CREATE TABLE `converse_to_non_partition_table` ( + `id` INT NOT NULL, + `category` VARCHAR(100) +) PARTITION BY LIST COLUMNS(`category`) ( + PARTITION p0 VALUES IN ('category1', 'category2'), + PARTITION p1 VALUES IN ('category3', 'category4'), + PARTITION p2 VALUES IN ('category5', 'category6') +); + +-- 更新表属性 case +create table `update_options`( + `c1` INT(11) NOT NULL, + `c2` INT(11) NOT NULL +) CHARACTER SET = gb18030 COLLATE = gb18030_chinese_ci COMMENT = 'comment2'; \ No newline at end of file diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/plugin/SchemaPluginUtil.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/plugin/SchemaPluginUtil.java index e1045cfd65..7381e66731 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/plugin/SchemaPluginUtil.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/plugin/SchemaPluginUtil.java @@ -24,6 +24,7 @@ import com.oceanbase.odc.plugin.schema.api.FunctionExtensionPoint; import com.oceanbase.odc.plugin.schema.api.PackageExtensionPoint; import com.oceanbase.odc.plugin.schema.api.ProcedureExtensionPoint; +import com.oceanbase.odc.plugin.schema.api.SchemaBrowserExtensionPoint; import com.oceanbase.odc.plugin.schema.api.SequenceExtensionPoint; import com.oceanbase.odc.plugin.schema.api.SynonymExtensionPoint; import com.oceanbase.odc.plugin.schema.api.TableExtensionPoint; @@ -82,6 +83,10 @@ public static TypeExtensionPoint getTypeExtension(DialectType dialectType) { return getSingletonExtension(dialectType, TypeExtensionPoint.class); } + public static SchemaBrowserExtensionPoint getSchemaBrowserExtension(DialectType dialectType) { + return getSingletonExtension(dialectType, SchemaBrowserExtensionPoint.class); + } + public static T getSingletonExtension(DialectType dialectType, Class type) { return getOdcPluginManager().getSingletonExtension(dialectType, type); } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DBStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DBStructureComparator.java new file mode 100644 index 0000000000..c2e229b70c --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DBStructureComparator.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.service.structurecompare; + +import java.sql.SQLException; +import java.util.List; + +import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.odc.service.structurecompare.model.DBStructureComparisonConfig; + +/** + * @author jingtian + * @date 2024/1/4 + * @since ODC_release_4.2.4 + */ +public interface DBStructureComparator { + /** + * Compare database objects between two schema. + * + * @param srcConfig {@link DBStructureComparisonConfig} + * @param destConfig {@link DBStructureComparisonConfig} + * @return {@link DBObjectComparisonResult} + */ + List compare(DBStructureComparisonConfig srcConfig, + DBStructureComparisonConfig destConfig) + throws SQLException; +} diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparator.java new file mode 100644 index 0000000000..936e8b980a --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparator.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.service.structurecompare; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.compress.utils.Lists; + +import com.oceanbase.odc.core.shared.constant.DialectType; +import com.oceanbase.odc.service.plugin.SchemaPluginUtil; +import com.oceanbase.odc.service.structurecompare.comparedbobject.TableStructureComparator; +import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; +import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.odc.service.structurecompare.model.DBStructureComparisonConfig; +import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; +import com.oceanbase.tools.dbbrowser.model.DBObjectType; +import com.oceanbase.tools.dbbrowser.model.DBTable; +import com.oceanbase.tools.dbbrowser.model.DBTable.DBTableOptions; +import com.oceanbase.tools.dbbrowser.model.DBTableColumn; +import com.oceanbase.tools.dbbrowser.model.DBTableConstraint; +import com.oceanbase.tools.dbbrowser.model.DBTableIndex; +import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +/** + * @author jingtian + * @date 2024/1/4 + * @since ODC_release_4.2.4 + */ +@Slf4j +public class OdcDBStructureComparator implements DBStructureComparator { + private final List supportedDialectTypes = + Arrays.asList(DialectType.MYSQL, DialectType.OB_MYSQL, DialectType.OB_ORACLE); + private final List supportedDBObjectTypes = Arrays.asList(DBObjectType.TABLE); + + @Override + public List compare(@NonNull DBStructureComparisonConfig srcConfig, + @NonNull DBStructureComparisonConfig tgtConfig) + throws SQLException { + List returnVal = new ArrayList<>(); + checkConfig(srcConfig, tgtConfig); + + DBSchemaAccessor srcAccessor = SchemaPluginUtil.getSchemaBrowserExtension(srcConfig.getDialectType()) + .getDBSchemaAccessor(srcConfig.getDataSource().getConnection()); + DBSchemaAccessor tgtAccessor = SchemaPluginUtil.getSchemaBrowserExtension(tgtConfig.getDialectType()) + .getDBSchemaAccessor(tgtConfig.getDataSource().getConnection()); + DBTableEditor tgtTableEditor = SchemaPluginUtil.getSchemaBrowserExtension(tgtConfig.getDialectType()) + .getDBTableEditor(tgtConfig.getDataSource().getConnection()); + + Map srcTables = buildSchemaTables(srcAccessor, srcConfig.getSchemaName()); + Map tgtTables = buildSchemaTables(tgtAccessor, tgtConfig.getSchemaName()); + TableStructureComparator tableComparator = new TableStructureComparator(tgtTableEditor, + tgtConfig.getDialectType(), + srcConfig.getSchemaName(), tgtConfig.getSchemaName()); + + if (srcConfig.getBlackListMap().get(DBObjectType.TABLE) == null) { + /** + * Compare all the tables between source database and target database. + */ + returnVal = + tableComparator.compare(new ArrayList<>(srcTables.values()), new ArrayList<>(tgtTables.values())); + } else { + /** + * Compare specified tables between source database and target database. + */ + for (String tableName : srcConfig.getBlackListMap().get(DBObjectType.TABLE)) { + if (srcTables.containsKey(tableName)) { + returnVal.add(tableComparator.compare(srcTables.get(tableName), tgtTables.get(tableName))); + } else { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.TABLE, tableName, + srcConfig.getSchemaName(), tgtConfig.getSchemaName()); + result.setComparisonResult(ComparisonResult.MISSING_IN_SOURCE); + returnVal.add(result); + } + } + } + return returnVal; + } + + private void checkConfig(DBStructureComparisonConfig srcConfig, DBStructureComparisonConfig tgtConfig) { + if (!srcConfig.getDialectType().equals(tgtConfig.getDialectType())) { + throw new IllegalArgumentException("The dialect type of source and target schema must be equal"); + } + if (!supportedDialectTypes.contains(srcConfig.getDialectType())) { + throw new UnsupportedOperationException( + "Unsupported dialect type for schema structure comparison: " + srcConfig.getDialectType()); + } + srcConfig.getToComparedObjectTypes().stream().forEach(dbObjectType -> { + if (!supportedDBObjectTypes.contains(dbObjectType)) { + throw new UnsupportedOperationException( + "Unsupported database object type for schema structure comparison: " + dbObjectType); + } + }); + } + + private Map buildSchemaTables(DBSchemaAccessor accessor, String schemaName) { + Map returnVal = new HashMap<>(); + List tableNames = accessor.showTables(schemaName); + if (tableNames.isEmpty()) { + return returnVal; + } + Map> tableName2Columns = accessor.listTableColumns(schemaName); + Map> tableName2Indexes = accessor.listTableIndexes(schemaName); + Map> tableName2Constraints = accessor.listTableConstraints(schemaName); + Map tableName2Options = accessor.listTableOptions(schemaName); + for (String tableName : tableNames) { + if (!tableName2Columns.containsKey(tableName)) { + log.warn("Failed to query table column metadata information, table name: {}, schema name: {}", + tableName, schemaName); + continue; + } + DBTable table = new DBTable(); + table.setSchemaName(schemaName); + table.setOwner(schemaName); + table.setName(tableName); + table.setColumns(tableName2Columns.getOrDefault(tableName, Lists.newArrayList())); + table.setIndexes(tableName2Indexes.getOrDefault(tableName, Lists.newArrayList())); + table.setConstraints(tableName2Constraints.getOrDefault(tableName, Lists.newArrayList())); + table.setTableOptions(tableName2Options.getOrDefault(tableName, new DBTableOptions())); + table.setPartition(accessor.getPartition(schemaName, tableName)); + table.setDDL(accessor.getTableDDL(schemaName, tableName)); + returnVal.put(tableName, table); + } + return returnVal; + } +} diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBObjectStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBObjectStructureComparator.java new file mode 100644 index 0000000000..cd53fef8d4 --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBObjectStructureComparator.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.service.structurecompare.comparedbobject; + +import java.util.List; + +import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.tools.dbbrowser.model.DBObject; + +/** + * @author jingtian + * @date 2024/1/4 + * @since ODC_release_4.2.4 + */ +public interface DBObjectStructureComparator { + String DEFAULT_SQL_DELIMITER = ";"; + + /** + * Compare specified database object types between two schema. + * + * @param sourceObjects source database objects + * @param targetObjects target database objects + * @return {@link DBObjectComparisonResult} + */ + List compare(List sourceObjects, List targetObjects); + + + /** + * Compare single specified database object type between two schema. + * + * @param sourceObject source database object + * @param targetObject target database object + * @return {@link DBObjectComparisonResult} + */ + DBObjectComparisonResult compare(T sourceObject, T targetObject); + + default String appendDelimiterIfNotExist(String sql) { + String returnVal = sql.trim(); + if (!returnVal.endsWith(DEFAULT_SQL_DELIMITER)) { + return returnVal + DEFAULT_SQL_DELIMITER + "\n"; + } + return sql; + } +} diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableColumnStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableColumnStructureComparator.java new file mode 100644 index 0000000000..530f1fc66e --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableColumnStructureComparator.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.service.structurecompare.comparedbobject; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.validation.constraints.NotEmpty; + +import org.springframework.beans.BeanUtils; + +import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; +import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.tools.dbbrowser.editor.DBTableColumnEditor; +import com.oceanbase.tools.dbbrowser.model.DBObjectType; +import com.oceanbase.tools.dbbrowser.model.DBTableColumn; + +import lombok.NonNull; + +/** + * @author jingtian + * @date 2024/1/4 + * @since ODC_release_4.2.4 + */ +public class TableColumnStructureComparator implements DBObjectStructureComparator { + private DBTableColumnEditor tgtColumnEditor; + private String srcSchemaName; + private String tgtSchemaName; + + public TableColumnStructureComparator(DBTableColumnEditor tgtColumnEditor, String srcSchemaName, + String tgtSchemaName) { + this.tgtColumnEditor = tgtColumnEditor; + this.srcSchemaName = srcSchemaName; + this.tgtSchemaName = tgtSchemaName; + } + + @Override + public List compare(@NotEmpty List srcTabCols, + @NotEmpty List tgtTabCols) { + List returnVal = new ArrayList<>(); + + String srcSchemaName = srcTabCols.get(0).getSchemaName(); + String tgtSchemaName = tgtTabCols.get(0).getSchemaName(); + List srcColNames = srcTabCols.stream().map(DBTableColumn::getName).collect(Collectors.toList()); + List tgtColNames = tgtTabCols.stream().map(DBTableColumn::getName).collect(Collectors.toList()); + Map srcColMapping = + srcTabCols.stream().collect(Collectors.toMap(DBTableColumn::getName, col -> col)); + Map tgtColMapping = + tgtTabCols.stream().collect(Collectors.toMap(DBTableColumn::getName, col -> col)); + + tgtColNames.forEach(tarColName -> { + if (!srcColNames.contains(tarColName)) { + // column to be dropped + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.COLUMN, tarColName, + srcSchemaName, tgtSchemaName); + result.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); + result.setChangeScript( + appendDelimiterIfNotExist(this.tgtColumnEditor + .generateDropObjectDDL(tgtColMapping.get(tarColName)))); + returnVal.add(result); + } + }); + + srcColNames.forEach(srcColName -> { + DBTableColumn copiedSrcCol = copySrcColumnWithTgtSchemaName(srcColMapping.get(srcColName), tgtSchemaName); + + if (tgtColNames.contains(srcColName)) { + // column to be compared + returnVal.add(compare(srcColMapping.get(srcColName), tgtColMapping.get(srcColName))); + } else { + // column to be created + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.COLUMN, srcColName, + srcSchemaName, tgtSchemaName); + result.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); + result.setChangeScript(appendDelimiterIfNotExist( + tgtColumnEditor.generateCreateObjectDDL(copiedSrcCol))); + returnVal.add(result); + } + }); + + return returnVal; + } + + @Override + public DBObjectComparisonResult compare(@NonNull DBTableColumn srcTabCol, @NonNull DBTableColumn tgtTabCol) { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.COLUMN, srcTabCol.getName(), + srcTabCol.getSchemaName(), tgtTabCol.getSchemaName()); + + DBTableColumn copiedSrcCol = copySrcColumnWithTgtSchemaName(srcTabCol, tgtTabCol.getSchemaName()); + + String ddl = this.tgtColumnEditor.generateUpdateObjectDDL( + tgtTabCol, copiedSrcCol); + if (!ddl.isEmpty()) { + // column to be updated + result.setComparisonResult(ComparisonResult.INCONSISTENT); + result.setChangeScript(appendDelimiterIfNotExist(ddl)); + } else { + result.setComparisonResult(ComparisonResult.CONSISTENT); + } + return result; + } + + private DBTableColumn copySrcColumnWithTgtSchemaName(DBTableColumn srcCol, String tgtSchemaName) { + DBTableColumn copiedSrcCol = new DBTableColumn(); + BeanUtils.copyProperties(srcCol, copiedSrcCol); + copiedSrcCol.setSchemaName(tgtSchemaName); + return copiedSrcCol; + } +} diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableConstraintStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableConstraintStructureComparator.java new file mode 100644 index 0000000000..451d51b409 --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableConstraintStructureComparator.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.service.structurecompare.comparedbobject; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.beans.BeanUtils; + +import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; +import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.tools.dbbrowser.editor.DBTableConstraintEditor; +import com.oceanbase.tools.dbbrowser.model.DBConstraintType; +import com.oceanbase.tools.dbbrowser.model.DBObjectType; +import com.oceanbase.tools.dbbrowser.model.DBTableConstraint; + +import lombok.NonNull; + +/** + * @author jingtian + * @date 2024/1/4 + * @since ODC_release_4.2.4 + */ +public class TableConstraintStructureComparator implements DBObjectStructureComparator { + private DBTableConstraintEditor tgtConstraintEditor; + private String srcSchemaName; + private String tgtSchemaName; + + public TableConstraintStructureComparator(DBTableConstraintEditor tgtConstraintEditor, String srcSchemaName, + String tgtSchemaName) { + this.tgtConstraintEditor = tgtConstraintEditor; + this.srcSchemaName = srcSchemaName; + this.tgtSchemaName = tgtSchemaName; + } + + @Override + public List compare(List srcTabCons, + List tgtTabCons) { + List returnVal = new ArrayList<>(); + if (srcTabCons.isEmpty() && tgtTabCons.isEmpty()) { + return returnVal; + } else if (srcTabCons.isEmpty()) { + // constraints to be dropped + tgtTabCons.forEach(cons -> { + returnVal.add(buildDropConstraintResult(cons, this.srcSchemaName)); + }); + return returnVal; + } else if (tgtTabCons.isEmpty()) { + // constraints to be created + srcTabCons.forEach(cons -> { + returnVal.add(buildCreateConstraintResult(cons, this.tgtSchemaName)); + }); + return returnVal; + } + + List srcConsNames = srcTabCons.stream().map(DBTableConstraint::getName).collect(Collectors.toList()); + List tgtConsNames = tgtTabCons.stream().map(DBTableConstraint::getName).collect(Collectors.toList()); + Map srcConsMapping = + srcTabCons.stream().collect(Collectors.toMap(DBTableConstraint::getName, col -> col)); + Map tarConsMapping = + tgtTabCons.stream().collect(Collectors.toMap(DBTableConstraint::getName, col -> col)); + + tgtConsNames.forEach(tgtConsName -> { + if (!srcConsNames.contains(tgtConsName)) { + // constraint to be dropped + returnVal.add(buildDropConstraintResult(tarConsMapping.get(tgtConsName), this.srcSchemaName)); + } else { + // constraint to be compared + returnVal.add(compare(srcConsMapping.get(tgtConsName), tarConsMapping.get(tgtConsName))); + } + }); + + srcConsNames.forEach(srcConsName -> { + if (!tgtConsNames.contains(srcConsName)) { + // constraint to be created + returnVal.add(buildCreateConstraintResult(srcConsMapping.get(srcConsName), this.tgtSchemaName)); + } + }); + + return returnVal; + } + + private DBObjectComparisonResult buildDropConstraintResult(DBTableConstraint tgtCons, String srcSchemaName) { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.CONSTRAINT, tgtCons.getName(), + srcSchemaName, tgtCons.getSchemaName()); + result.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); + result.setChangeScript(appendDelimiterIfNotExist( + this.tgtConstraintEditor.generateDropObjectDDL(tgtCons))); + return result; + } + + private DBObjectComparisonResult buildCreateConstraintResult(DBTableConstraint srcConstraint, + String tgtSchemaName) { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.CONSTRAINT, srcConstraint.getName(), + srcConstraint.getSchemaName(), tgtSchemaName); + result.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); + + DBTableConstraint copiedSrcCons = copySrcConstraintWithTgtSchemaName(srcConstraint, tgtSchemaName); + if (copiedSrcCons.getType().equals(DBConstraintType.FOREIGN_KEY)) { + copiedSrcCons.setReferenceSchemaName(tgtSchemaName); + } + result.setChangeScript(appendDelimiterIfNotExist( + this.tgtConstraintEditor + .generateCreateObjectDDL(copiedSrcCons))); + return result; + } + + private DBTableConstraint copySrcConstraintWithTgtSchemaName(DBTableConstraint srcConstraint, + String tgtSchemaName) { + DBTableConstraint copiedSrcConstraint = new DBTableConstraint(); + BeanUtils.copyProperties(srcConstraint, copiedSrcConstraint); + copiedSrcConstraint.setSchemaName(tgtSchemaName); + return copiedSrcConstraint; + } + + @Override + public DBObjectComparisonResult compare(@NonNull DBTableConstraint srcConstraint, + @NonNull DBTableConstraint tgtConstraint) { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.CONSTRAINT, srcConstraint.getName(), + this.srcSchemaName, this.tgtSchemaName); + + DBTableConstraint copiedSrcConstraint = copySrcConstraintWithTgtSchemaName(srcConstraint, this.tgtSchemaName); + String ddl = this.tgtConstraintEditor.generateUpdateObjectDDL( + tgtConstraint, copiedSrcConstraint); + if (!ddl.isEmpty()) { + // constraint to be updated + result.setComparisonResult(ComparisonResult.INCONSISTENT); + result.setChangeScript(appendDelimiterIfNotExist(ddl)); + } else { + result.setComparisonResult(ComparisonResult.CONSISTENT); + } + return result; + } +} diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableIndexStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableIndexStructureComparator.java new file mode 100644 index 0000000000..f696a2f525 --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableIndexStructureComparator.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.service.structurecompare.comparedbobject; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.beans.BeanUtils; + +import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; +import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.tools.dbbrowser.editor.DBTableIndexEditor; +import com.oceanbase.tools.dbbrowser.model.DBObjectType; +import com.oceanbase.tools.dbbrowser.model.DBTableIndex; + +import lombok.NonNull; + +/** + * @author jingtian + * @date 2024/1/4 + * @since ODC_release_4.2.4 + */ +public class TableIndexStructureComparator implements DBObjectStructureComparator { + + private DBTableIndexEditor targetTableIndexEditor; + private String srcSchemaName; + private String tgtSchemaName; + + public TableIndexStructureComparator(DBTableIndexEditor targetTableIndexEditor, String srcSchemaName, + String tgtSchemaName) { + this.targetTableIndexEditor = targetTableIndexEditor; + this.srcSchemaName = srcSchemaName; + this.tgtSchemaName = tgtSchemaName; + } + + @Override + public List compare(List srcIndexes, List tgtIndexes) { + List returnVal = new ArrayList<>(); + if (srcIndexes.isEmpty() && tgtIndexes.isEmpty()) { + return returnVal; + } else if (srcIndexes.isEmpty()) { + // indexes to be dropped + tgtIndexes.forEach(idx -> { + returnVal.add(buildDropIndexResult(idx, this.srcSchemaName)); + }); + return returnVal; + } else if (tgtIndexes.isEmpty()) { + // indexes to be created + srcIndexes.forEach(idx -> { + returnVal.add(buildCreateIndexResult(idx, this.tgtSchemaName)); + }); + return returnVal; + } + + List srcIdxNames = srcIndexes.stream().map(DBTableIndex::getName).collect(Collectors.toList()); + List tgtIdxNames = tgtIndexes.stream().map(DBTableIndex::getName).collect(Collectors.toList()); + Map srcIdxMapping = + srcIndexes.stream().collect(Collectors.toMap(DBTableIndex::getName, col -> col)); + Map tgtIdxMapping = + tgtIndexes.stream().collect(Collectors.toMap(DBTableIndex::getName, col -> col)); + + tgtIdxNames.forEach(tgtIdxName -> { + if (!srcIdxNames.contains(tgtIdxName)) { + // index to be dropped + returnVal.add(buildDropIndexResult(tgtIdxMapping.get(tgtIdxName), this.srcSchemaName)); + } else { + // index to be compared + returnVal.add(compare(srcIdxMapping.get(tgtIdxName), tgtIdxMapping.get(tgtIdxName))); + } + }); + + srcIdxNames.forEach(srcIdxName -> { + if (!tgtIdxNames.contains(srcIdxName)) { + // index to be created + returnVal.add(buildCreateIndexResult(srcIdxMapping.get(srcIdxName), this.tgtSchemaName)); + } + }); + + return returnVal; + } + + @Override + public DBObjectComparisonResult compare(@NonNull DBTableIndex srcIndex, @NonNull DBTableIndex tgtIndex) { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.INDEX, srcIndex.getName(), + srcIndex.getSchemaName(), tgtIndex.getSchemaName()); + + DBTableIndex copiedSrcIdx = copySrcIndexWithTgtSchemaName(srcIndex, tgtIndex.getSchemaName()); + String ddl = this.targetTableIndexEditor.generateUpdateObjectDDL( + tgtIndex, copiedSrcIdx); + if (!ddl.isEmpty()) { + // index to be updated + result.setComparisonResult(ComparisonResult.INCONSISTENT); + result.setChangeScript(appendDelimiterIfNotExist(ddl)); + } else { + result.setComparisonResult(ComparisonResult.CONSISTENT); + } + return result; + } + + private DBObjectComparisonResult buildCreateIndexResult(DBTableIndex srcIndex, String tgtSchemaName) { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.INDEX, srcIndex.getName(), + srcIndex.getSchemaName(), tgtSchemaName); + result.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); + result.setChangeScript(appendDelimiterIfNotExist( + targetTableIndexEditor + .generateCreateObjectDDL(copySrcIndexWithTgtSchemaName(srcIndex, tgtSchemaName)))); + return result; + } + + private DBObjectComparisonResult buildDropIndexResult(DBTableIndex tgtIndex, String srcSchemaName) { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.INDEX, tgtIndex.getName(), + srcSchemaName, tgtIndex.getSchemaName()); + result.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); + result.setChangeScript(appendDelimiterIfNotExist( + targetTableIndexEditor.generateDropObjectDDL(tgtIndex))); + return result; + } + + private DBTableIndex copySrcIndexWithTgtSchemaName(DBTableIndex srcIndex, String tgtSchemaName) { + DBTableIndex copiedSrcIdx = new DBTableIndex(); + BeanUtils.copyProperties(srcIndex, copiedSrcIdx); + copiedSrcIdx.setSchemaName(tgtSchemaName); + return copiedSrcIdx; + } +} diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TablePartitionStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TablePartitionStructureComparator.java new file mode 100644 index 0000000000..5a3cad7b82 --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TablePartitionStructureComparator.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.service.structurecompare.comparedbobject; + +import java.util.List; + +import org.springframework.beans.BeanUtils; + +import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; +import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.tools.dbbrowser.editor.DBTablePartitionEditor; +import com.oceanbase.tools.dbbrowser.model.DBObjectType; +import com.oceanbase.tools.dbbrowser.model.DBTablePartition; +import com.oceanbase.tools.dbbrowser.model.DBTablePartitionType; + +/** + * @author jingtian + * @date 2024/1/4 + * @since ODC_release_4.2.4 + */ +public class TablePartitionStructureComparator implements DBObjectStructureComparator { + private DBTablePartitionEditor tgtPartitionEditor; + private String srcSchemaName; + private String tgtSchemaName; + + public TablePartitionStructureComparator(DBTablePartitionEditor tgtPartitionEditor, String srcSchemaName, + String tgtSchemaName) { + this.tgtPartitionEditor = tgtPartitionEditor; + this.srcSchemaName = srcSchemaName; + this.tgtSchemaName = tgtSchemaName; + } + + @Override + public List compare(List srcPartitions, + List tgtPartitions) { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public DBObjectComparisonResult compare(DBTablePartition srcPartition, DBTablePartition tgtPartition) { + DBTablePartitionType srcPartitionType = srcPartition.getPartitionOption().getType(); + DBTablePartitionType tgtPartitionType = tgtPartition.getPartitionOption().getType(); + DBObjectComparisonResult result = + new DBObjectComparisonResult(DBObjectType.PARTITION, this.srcSchemaName, this.tgtSchemaName); + + if (DBTablePartitionType.NOT_PARTITIONED.equals(srcPartitionType) + && DBTablePartitionType.NOT_PARTITIONED.equals(tgtPartitionType)) { + result.setComparisonResult(ComparisonResult.CONSISTENT); + } else if (DBTablePartitionType.NOT_PARTITIONED.equals(srcPartitionType)) { + // cannot cover partitioned table to non-partitioned table + result.setComparisonResult(ComparisonResult.UNSUPPORTED); + result.setChangeScript("/* Unsupported operation: Convert partitioned table to non-partitioned table */\n"); + } else if (DBTablePartitionType.NOT_PARTITIONED.equals(tgtPartitionType)) { + // partition to be created + result.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); + result.setChangeScript( + appendDelimiterIfNotExist( + this.tgtPartitionEditor.generateCreateObjectDDL( + copySrcPartitionWithTgtSchemaName(srcPartition, this.tgtSchemaName)))); + } else { + String ddl = this.tgtPartitionEditor.generateUpdateObjectDDL(tgtPartition, + copySrcPartitionWithTgtSchemaName(srcPartition, this.tgtSchemaName)); + if (ddl.isEmpty()) { + result.setComparisonResult(ComparisonResult.CONSISTENT); + } else { + // partition to be updated + result.setComparisonResult(ComparisonResult.INCONSISTENT); + result.setChangeScript(appendDelimiterIfNotExist(ddl)); + } + } + return result; + } + + private DBTablePartition copySrcPartitionWithTgtSchemaName(DBTablePartition srcPartition, String tgtSchemaName) { + DBTablePartition copiedSrcPartition = new DBTablePartition(); + BeanUtils.copyProperties(srcPartition, copiedSrcPartition); + copiedSrcPartition.setSchemaName(tgtSchemaName); + return copiedSrcPartition; + } +} diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java new file mode 100644 index 0000000000..c60170f7af --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.service.structurecompare.comparedbobject; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.beans.BeanUtils; + +import com.oceanbase.odc.common.util.ListUtils; +import com.oceanbase.odc.common.util.TopoOrderComparator; +import com.oceanbase.odc.core.shared.constant.DialectType; +import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; +import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.tools.dbbrowser.editor.DBTableColumnEditor; +import com.oceanbase.tools.dbbrowser.editor.DBTableConstraintEditor; +import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; +import com.oceanbase.tools.dbbrowser.editor.DBTableIndexEditor; +import com.oceanbase.tools.dbbrowser.editor.DBTablePartitionEditor; +import com.oceanbase.tools.dbbrowser.editor.GeneralSqlStatementBuilder; +import com.oceanbase.tools.dbbrowser.model.DBConstraintType; +import com.oceanbase.tools.dbbrowser.model.DBObjectType; +import com.oceanbase.tools.dbbrowser.model.DBTable; +import com.oceanbase.tools.dbbrowser.model.DBTableConstraint; +import com.oceanbase.tools.dbbrowser.util.MySQLSqlBuilder; +import com.oceanbase.tools.dbbrowser.util.OracleSqlBuilder; +import com.oceanbase.tools.dbbrowser.util.SqlBuilder; + +/** + * @author jingtian + * @date 2024/1/4 + * @since ODC_release_4.2.4 + */ +public class TableStructureComparator implements DBObjectStructureComparator { + private DBTableEditor tgtTableEditor; + private DialectType tgtDialectType; + private String srcSchemaName; + private String tgtSchemaName; + + public TableStructureComparator(DBTableEditor tgtTableEditor, DialectType tgtDialectType, String srcSchemaName, + String tgtSchemaName) { + this.tgtTableEditor = tgtTableEditor; + this.tgtDialectType = tgtDialectType; + this.srcSchemaName = srcSchemaName; + this.tgtSchemaName = tgtSchemaName; + } + + @Override + public List compare(List srcTables, List tgtTables) { + List returnVal = new LinkedList<>(); + if (srcTables.isEmpty() && tgtTables.isEmpty()) { + return returnVal; + } else if (srcTables.isEmpty()) { + return buildDroppedTableResults(tgtTables.stream().map(DBTable::getName).collect(Collectors.toList()), + new HashMap<>(), srcSchemaName, tgtSchemaName); + } else if (tgtTables.isEmpty()) { + return buildCreatedTableResults(srcTables.stream().map(DBTable::getName).collect(Collectors.toList()), + new HashMap<>(), srcSchemaName, tgtSchemaName); + } + + String srcSchemaName = srcTables.get(0).getSchemaName(); + String tgtSchemaName = tgtTables.get(0).getSchemaName(); + Map srcTableMapping = + srcTables.stream().collect(Collectors.toMap(DBTable::getName, table -> table)); + Map tgtTableMapping = + tgtTables.stream().collect(Collectors.toMap(DBTable::getName, table -> table)); + List toCreatedNames = new ArrayList<>(); + List toComparedNames = new ArrayList<>(); + List toDroppedNames = new ArrayList<>(); + + for (String tableName : srcTableMapping.keySet()) { + if (!tgtTableMapping.containsKey(tableName)) { + toCreatedNames.add(tableName); + } else { + toComparedNames.add(tableName); + } + } + for (String tableName : tgtTableMapping.keySet()) { + if (!srcTableMapping.containsKey(tableName)) { + toDroppedNames.add(tableName); + } + } + + List createdResults = + buildCreatedTableResults(toCreatedNames, srcTableMapping, srcSchemaName, tgtSchemaName); + List dropResults = + buildDroppedTableResults(toDroppedNames, tgtTableMapping, srcSchemaName, tgtSchemaName); + + List comparedResults = new ArrayList<>(); + toComparedNames.forEach(name -> { + comparedResults.add(compare(srcTableMapping.get(name), tgtTableMapping.get(name))); + }); + + returnVal.addAll(createdResults); + returnVal.addAll(comparedResults); + returnVal.addAll(dropResults); + + return returnVal; + } + + private List buildCreatedTableResults(List toCreate, + Map srcTableMapping, String srcSchemaName, String tgtSchemaName) { + List returnVal = new LinkedList<>(); + if (toCreate.isEmpty()) { + return returnVal; + } + toCreate = getTableNamesByDependencyOrder(toCreate, srcTableMapping, srcSchemaName); + + toCreate.forEach(name -> { + DBObjectComparisonResult result = + new DBObjectComparisonResult(DBObjectType.TABLE, name, srcSchemaName, tgtSchemaName); + result.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); + DBTable sourceTable = srcTableMapping.get(name); + result.setSourceDdl(sourceTable.getDDL()); + DBTable targetTable = new DBTable(); + BeanUtils.copyProperties(sourceTable, targetTable); + targetTable.setSchemaName(tgtSchemaName); + result.setChangeScript(this.tgtTableEditor.generateCreateObjectDDL(targetTable)); + returnVal.add(result); + }); + return returnVal; + } + + private List buildDroppedTableResults(List toDrop, + Map tgtTableMapping, + String srcSchemaName, String tgtSchemaName) { + List returnVal = new LinkedList<>(); + if (toDrop.isEmpty()) { + return returnVal; + } + toDrop = getTableNamesByDependencyOrder(toDrop, tgtTableMapping, tgtSchemaName); + Collections.reverse(toDrop); + + toDrop.forEach(name -> { + DBObjectComparisonResult result = + new DBObjectComparisonResult(DBObjectType.TABLE, name, srcSchemaName, tgtSchemaName); + result.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); + result.setTargetDdl(tgtTableMapping.get(name).getDDL()); + SqlBuilder sqlBuilder = getTargetDBSqlBuilder(); + result.setChangeScript( + GeneralSqlStatementBuilder.drop(sqlBuilder, DBObjectType.TABLE, tgtSchemaName, name)); + returnVal.add(result); + }); + return returnVal; + } + + /** + * Construct a topology graph based on foreign key dependencies and obtain a list of table names + * sorted by the topology graph. + */ + private List getTableNamesByDependencyOrder(List tableNames, Map tableMapping, + String schemaName) { + Map> dependencyGraph = new HashMap<>(); + + // Build dependency graph + tableNames.forEach(tableName -> { + for (DBTableConstraint constraint : tableMapping.get(tableName).getConstraints()) { + if (constraint.getType().equals(DBConstraintType.FOREIGN_KEY)) { + String referenceTableName = constraint.getReferenceTableName(); + if (schemaName.equals(constraint.getReferenceSchemaName()) + && tableNames.contains(referenceTableName)) { + dependencyGraph.computeIfAbsent(referenceTableName, k -> new HashSet<>()).add(tableName); + } + } + } + }); + + if (dependencyGraph.isEmpty()) { + return tableNames; + } + ListUtils.sortByTopoOrder(tableNames, new TopoOrderComparator<>(dependencyGraph)); + return tableNames; + } + + private SqlBuilder getTargetDBSqlBuilder() { + if (this.tgtDialectType.isMysql()) { + return new MySQLSqlBuilder(); + } else { + return new OracleSqlBuilder(); + } + } + + @Override + public DBObjectComparisonResult compare(DBTable sourceTable, DBTable targetTable) { + if (Objects.isNull(sourceTable) && Objects.isNull(targetTable)) { + throw new IllegalStateException("Both source table and target table are null"); + } else if (Objects.isNull(sourceTable)) { + return buildDroppedTableResults(Collections.singletonList(targetTable.getName()), + Collections.singletonMap(targetTable.getName(), targetTable), this.srcSchemaName, + this.tgtSchemaName).get(0); + } else if (Objects.isNull(targetTable)) { + return buildCreatedTableResults(Collections.singletonList(sourceTable.getName()), + Collections.singletonMap(sourceTable.getName(), sourceTable), this.srcSchemaName, + this.tgtSchemaName).get(0); + } + + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.TABLE, sourceTable.getName(), + sourceTable.getSchemaName(), targetTable.getSchemaName()); + + String srcSchemaName = sourceTable.getSchemaName(); + String tgtSchemaName = targetTable.getSchemaName(); + + // compare table options + SqlBuilder tableOptionDdl = getTargetDBSqlBuilder(); + DBTable copiedSrcTable = new DBTable(); + BeanUtils.copyProperties(sourceTable, copiedSrcTable); + copiedSrcTable.setSchemaName(targetTable.getSchemaName()); + this.tgtTableEditor.generateUpdateTableOptionDDL(targetTable, copiedSrcTable, tableOptionDdl); + result.setChangeScript(tableOptionDdl.toString()); + result.setSourceDdl(sourceTable.getDDL()); + result.setTargetDdl(targetTable.getDDL()); + + // compare table columns + List columns = + new TableColumnStructureComparator( + (DBTableColumnEditor) this.tgtTableEditor.getColumnEditor(), srcSchemaName, tgtSchemaName) + .compare(sourceTable.getColumns(), targetTable.getColumns()); + + // compare table index + List indexes = + new TableIndexStructureComparator((DBTableIndexEditor) this.tgtTableEditor.getIndexEditor(), + srcSchemaName, tgtSchemaName) + .compare( + this.tgtTableEditor.excludePrimaryKeyIndex(sourceTable.getIndexes(), + sourceTable.getConstraints()), + this.tgtTableEditor.excludePrimaryKeyIndex(targetTable.getIndexes(), + targetTable.getConstraints())); + + // compare table constraints + List constraints = new TableConstraintStructureComparator( + (DBTableConstraintEditor) this.tgtTableEditor.getConstraintEditor(), srcSchemaName, tgtSchemaName) + .compare( + this.tgtTableEditor.excludeUniqueConstraint(sourceTable.getIndexes(), + sourceTable.getConstraints()), + this.tgtTableEditor.excludeUniqueConstraint(targetTable.getIndexes(), + targetTable.getConstraints())); + + // compare table partition + DBObjectComparisonResult partition = + new TablePartitionStructureComparator((DBTablePartitionEditor) this.tgtTableEditor.getPartitionEditor(), + srcSchemaName, tgtSchemaName) + .compare(sourceTable.getPartition(), targetTable.getPartition()); + + if (columns.stream().allMatch(item -> item.getComparisonResult().equals(ComparisonResult.CONSISTENT)) + && indexes.stream().allMatch(item -> item.getComparisonResult().equals(ComparisonResult.CONSISTENT)) + && constraints.stream().allMatch(item -> item.getComparisonResult().equals(ComparisonResult.CONSISTENT)) + && partition.getComparisonResult().equals(ComparisonResult.CONSISTENT) + && tableOptionDdl.toString().isEmpty()) { + result.setComparisonResult(ComparisonResult.CONSISTENT); + } else { + result.setComparisonResult(ComparisonResult.INCONSISTENT); + } + + result.setSubDBObjectComparisonResult(columns); + result.getSubDBObjectComparisonResult().addAll(indexes); + result.getSubDBObjectComparisonResult().addAll(constraints); + result.getSubDBObjectComparisonResult().add(partition); + + return result; + } +} diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/ComparisonResult.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/ComparisonResult.java new file mode 100644 index 0000000000..a4580755f0 --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/ComparisonResult.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.oceanbase.odc.service.structurecompare.model; + +/** + * @author jingtian + * @date 2023/12/19 + * @since ODC_release_4.2.4 + */ +public enum ComparisonResult { + ONLY_IN_SOURCE, + ONLY_IN_TARGET, + CONSISTENT, + INCONSISTENT, + MISSING_IN_SOURCE, + UNSUPPORTED +} diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBObjectComparisonResult.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBObjectComparisonResult.java new file mode 100644 index 0000000000..b8245e34a6 --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBObjectComparisonResult.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.oceanbase.odc.service.structurecompare.model; + +import java.util.ArrayList; +import java.util.List; + +import com.oceanbase.tools.dbbrowser.model.DBObjectType; + +import lombok.Data; + +/** + * @author jingtian + * @date 2023/12/8 + * @since ODC_release_4.2.4 + */ +@Data +public class DBObjectComparisonResult { + private DBObjectType dbObjectType; + private String dbObjectName; + private String sourceSchemaName; + private String targetSchemaName; + private String sourceDdl; + private String targetDdl; + private ComparisonResult comparisonResult; + /** + * For TABLE object, such as COLUMN, INDEX, CONSTRAINT and PARTITION when comparisonResult is + * UPDATE. + */ + private List subDBObjectComparisonResult = new ArrayList<>(); + private String changeScript; + + public DBObjectComparisonResult(DBObjectType dbObjectType, String dbObjectName, String sourceSchemaName, + String targetSchemaName) { + this.dbObjectType = dbObjectType; + this.dbObjectName = dbObjectName; + this.sourceSchemaName = sourceSchemaName; + this.targetSchemaName = targetSchemaName; + } + + public DBObjectComparisonResult(DBObjectType dbObjectType, String sourceSchemaName, String targetSchemaName) { + this.dbObjectType = dbObjectType; + this.sourceSchemaName = sourceSchemaName; + this.targetSchemaName = targetSchemaName; + } +} diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBStructureComparisonConfig.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBStructureComparisonConfig.java new file mode 100644 index 0000000000..be8fb904dd --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBStructureComparisonConfig.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.service.structurecompare.model; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.sql.DataSource; +import javax.validation.constraints.NotNull; + +import com.oceanbase.odc.core.shared.constant.DialectType; +import com.oceanbase.tools.dbbrowser.model.DBObjectType; + +import lombok.Data; + +/** + * @author jingtian + * @date 2024/1/4 + * @since ODC_release_4.2.4 + */ +@Data +public class DBStructureComparisonConfig { + @NotNull + private String schemaName; + @NotNull + private DialectType dialectType; + @NotNull + private DataSource dataSource; + @NotNull + private Set toComparedObjectTypes; + private Map> blackListMap = new HashMap<>(); +} diff --git a/server/odc-test/src/main/java/com/oceanbase/odc/test/database/TestDBConfiguration.java b/server/odc-test/src/main/java/com/oceanbase/odc/test/database/TestDBConfiguration.java index e81bc99295..2d720fc6d4 100644 --- a/server/odc-test/src/main/java/com/oceanbase/odc/test/database/TestDBConfiguration.java +++ b/server/odc-test/src/main/java/com/oceanbase/odc/test/database/TestDBConfiguration.java @@ -25,12 +25,14 @@ import com.oceanbase.odc.test.util.JdbcUtil; import lombok.Data; +import lombok.NoArgsConstructor; /** * @author gaoda.xy * @date 2023/2/17 10:47 */ @Data +@NoArgsConstructor public class TestDBConfiguration { private DataSource dataSource; private TestDBType type; @@ -65,7 +67,7 @@ public TestDBConfiguration(Properties properties) { initDataSource(); } - private void initDataSource() { + public void initDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(JdbcUtil.buildUrl(host, port, defaultDBName, type)); dataSource.setUsername(JdbcUtil.buildUser(username, tenant, cluster)); diff --git a/server/plugins/schema-plugin-api/src/main/java/com/oceanbase/odc/plugin/schema/api/SchemaBrowserExtensionPoint.java b/server/plugins/schema-plugin-api/src/main/java/com/oceanbase/odc/plugin/schema/api/SchemaBrowserExtensionPoint.java new file mode 100644 index 0000000000..432f9f8ed5 --- /dev/null +++ b/server/plugins/schema-plugin-api/src/main/java/com/oceanbase/odc/plugin/schema/api/SchemaBrowserExtensionPoint.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.plugin.schema.api; + +import java.sql.Connection; + +import org.pf4j.ExtensionPoint; + +import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; +import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; + +/** + * @author jingtian + * @date 2024/1/5 + * @since ODC_release_4.2.4 + */ +public interface SchemaBrowserExtensionPoint extends ExtensionPoint { + DBSchemaAccessor getDBSchemaAccessor(Connection connection); + + DBTableEditor getDBTableEditor(Connection connection); +} diff --git a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLDatabaseExtension.java b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLDatabaseExtension.java index 882a0adcfe..1ced426a9a 100644 --- a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLDatabaseExtension.java +++ b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLDatabaseExtension.java @@ -19,10 +19,8 @@ import org.pf4j.Extension; -import com.oceanbase.odc.common.util.JdbcOperationsUtil; import com.oceanbase.odc.plugin.schema.obmysql.OBMySQLDatabaseExtension; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; -import com.oceanbase.tools.dbbrowser.schema.mysql.MySQLNoGreaterThan5740SchemaAccessor; /** * @author jingtian @@ -33,6 +31,6 @@ public class MySQLDatabaseExtension extends OBMySQLDatabaseExtension { @Override protected DBSchemaAccessor getSchemaAccessor(Connection connection) { - return new MySQLNoGreaterThan5740SchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); + return new MySQLSchemaBrowserExtension().getDBSchemaAccessor(connection); } } diff --git a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLFunctionExtension.java b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLFunctionExtension.java index 65014cf071..e4ab191090 100644 --- a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLFunctionExtension.java +++ b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLFunctionExtension.java @@ -19,10 +19,8 @@ import org.pf4j.Extension; -import com.oceanbase.odc.common.util.JdbcOperationsUtil; import com.oceanbase.odc.plugin.schema.obmysql.OBMySQLFunctionExtension; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; -import com.oceanbase.tools.dbbrowser.schema.mysql.MySQLNoGreaterThan5740SchemaAccessor; /** * @author jingtian @@ -33,6 +31,6 @@ public class MySQLFunctionExtension extends OBMySQLFunctionExtension { @Override protected DBSchemaAccessor getSchemaAccessor(Connection connection) { - return new MySQLNoGreaterThan5740SchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); + return new MySQLSchemaBrowserExtension().getDBSchemaAccessor(connection); } } diff --git a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLProcedureExtension.java b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLProcedureExtension.java index 2093536c31..8cbf874d60 100644 --- a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLProcedureExtension.java +++ b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLProcedureExtension.java @@ -19,10 +19,8 @@ import org.pf4j.Extension; -import com.oceanbase.odc.common.util.JdbcOperationsUtil; import com.oceanbase.odc.plugin.schema.obmysql.OBMySQLProcedureExtension; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; -import com.oceanbase.tools.dbbrowser.schema.mysql.MySQLNoGreaterThan5740SchemaAccessor; /** * @author jingtian @@ -33,6 +31,6 @@ public class MySQLProcedureExtension extends OBMySQLProcedureExtension { @Override protected DBSchemaAccessor getSchemaAccessor(Connection connection) { - return new MySQLNoGreaterThan5740SchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); + return new MySQLSchemaBrowserExtension().getDBSchemaAccessor(connection); } } diff --git a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLSchemaBrowserExtension.java b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLSchemaBrowserExtension.java new file mode 100644 index 0000000000..44bcc95d86 --- /dev/null +++ b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLSchemaBrowserExtension.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.plugin.schema.mysql; + +import java.sql.Connection; + +import org.pf4j.Extension; + +import com.oceanbase.odc.common.util.JdbcOperationsUtil; +import com.oceanbase.odc.plugin.schema.api.SchemaBrowserExtensionPoint; +import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLColumnEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLConstraintEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLDBTablePartitionEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLNoGreaterThan5740IndexEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLTableEditor; +import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; +import com.oceanbase.tools.dbbrowser.schema.mysql.MySQLNoGreaterThan5740SchemaAccessor; + +/** + * @author jingtian + * @date 2024/1/5 + * @since ODC_release_4.2.4 + */ +@Extension +public class MySQLSchemaBrowserExtension implements SchemaBrowserExtensionPoint { + @Override + public DBSchemaAccessor getDBSchemaAccessor(Connection connection) { + return new MySQLNoGreaterThan5740SchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); + } + + @Override + public DBTableEditor getDBTableEditor(Connection connection) { + return new MySQLTableEditor(new MySQLNoGreaterThan5740IndexEditor(), new MySQLColumnEditor(), + new MySQLConstraintEditor(), + new MySQLDBTablePartitionEditor()); + } +} diff --git a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLTableExtension.java b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLTableExtension.java index 3909eacd3d..686b385e0b 100644 --- a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLTableExtension.java +++ b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLTableExtension.java @@ -22,14 +22,8 @@ import com.oceanbase.odc.common.util.JdbcOperationsUtil; import com.oceanbase.odc.plugin.schema.obmysql.OBMySQLTableExtension; import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLColumnEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLConstraintEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLDBTablePartitionEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLNoGreaterThan5740IndexEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLTableEditor; import com.oceanbase.tools.dbbrowser.model.DBTable; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; -import com.oceanbase.tools.dbbrowser.schema.mysql.MySQLNoGreaterThan5740SchemaAccessor; import com.oceanbase.tools.dbbrowser.stats.DBStatsAccessor; import com.oceanbase.tools.dbbrowser.stats.mysql.MySQLNoGreaterThan5740StatsAccessor; @@ -61,14 +55,12 @@ public DBTable getDetail(@NonNull Connection connection, @NonNull String schemaN @Override protected DBTableEditor getTableEditor(@NonNull Connection connection) { - return new MySQLTableEditor(new MySQLNoGreaterThan5740IndexEditor(), new MySQLColumnEditor(), - new MySQLConstraintEditor(), - new MySQLDBTablePartitionEditor()); + return new MySQLSchemaBrowserExtension().getDBTableEditor(connection); } @Override protected DBSchemaAccessor getSchemaAccessor(Connection connection) { - return new MySQLNoGreaterThan5740SchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); + return new MySQLSchemaBrowserExtension().getDBSchemaAccessor(connection); } @Override diff --git a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLViewExtension.java b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLViewExtension.java index 4a55b74770..665933809a 100644 --- a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLViewExtension.java +++ b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLViewExtension.java @@ -19,10 +19,8 @@ import org.pf4j.Extension; -import com.oceanbase.odc.common.util.JdbcOperationsUtil; import com.oceanbase.odc.plugin.schema.obmysql.OBMySQLViewExtension; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; -import com.oceanbase.tools.dbbrowser.schema.mysql.MySQLNoGreaterThan5740SchemaAccessor; /** * @author jingtian @@ -33,6 +31,6 @@ public class MySQLViewExtension extends OBMySQLViewExtension { @Override protected DBSchemaAccessor getSchemaAccessor(Connection connection) { - return new MySQLNoGreaterThan5740SchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); + return new MySQLSchemaBrowserExtension().getDBSchemaAccessor(connection); } } diff --git a/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLSchemaBrowserExtension.java b/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLSchemaBrowserExtension.java new file mode 100644 index 0000000000..f934c2b70d --- /dev/null +++ b/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLSchemaBrowserExtension.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.plugin.schema.obmysql; + +import java.sql.Connection; + +import org.pf4j.Extension; + +import com.oceanbase.odc.plugin.schema.api.SchemaBrowserExtensionPoint; +import com.oceanbase.odc.plugin.schema.obmysql.utils.DBAccessorUtil; +import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; +import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; + +/** + * @author jingtian + * @date 2024/1/5 + * @since ODC_release_4.2.4 + */ +@Extension +public class OBMySQLSchemaBrowserExtension implements SchemaBrowserExtensionPoint { + @Override + public DBSchemaAccessor getDBSchemaAccessor(Connection connection) { + return DBAccessorUtil.getSchemaAccessor(connection); + } + + @Override + public DBTableEditor getDBTableEditor(Connection connection) { + return DBAccessorUtil.getTableEditor(connection); + } +} diff --git a/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLTableExtension.java b/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLTableExtension.java index e9bdd4b095..f7037d5f9a 100644 --- a/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLTableExtension.java +++ b/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLTableExtension.java @@ -23,20 +23,12 @@ import com.oceanbase.odc.common.unit.BinarySizeUnit; import com.oceanbase.odc.common.util.JdbcOperationsUtil; -import com.oceanbase.odc.common.util.VersionUtils; import com.oceanbase.odc.plugin.schema.api.TableExtensionPoint; import com.oceanbase.odc.plugin.schema.obmysql.parser.OBMySQLGetDBTableByParser; import com.oceanbase.odc.plugin.schema.obmysql.utils.DBAccessorUtil; import com.oceanbase.tools.dbbrowser.editor.DBObjectOperator; import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; -import com.oceanbase.tools.dbbrowser.editor.DBTablePartitionEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLColumnEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLConstraintEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLDBTablePartitionEditor; import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLObjectOperator; -import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLIndexEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLLessThan2277PartitionEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLTableEditor; import com.oceanbase.tools.dbbrowser.model.DBObjectIdentity; import com.oceanbase.tools.dbbrowser.model.DBObjectType; import com.oceanbase.tools.dbbrowser.model.DBTable; @@ -121,8 +113,7 @@ public String generateUpdateDDL(@NonNull Connection connection, @NonNull DBTable } protected DBTableEditor getTableEditor(Connection connection) { - return new OBMySQLTableEditor(new OBMySQLIndexEditor(), new MySQLColumnEditor(), new MySQLConstraintEditor(), - getDBTablePartitionEditor(connection)); + return DBAccessorUtil.getTableEditor(connection); } protected DBSchemaAccessor getSchemaAccessor(Connection connection) { @@ -137,13 +128,4 @@ private DBObjectOperator getTableOperator(Connection connection) { return new MySQLObjectOperator(JdbcOperationsUtil.getJdbcOperations(connection)); } - protected DBTablePartitionEditor getDBTablePartitionEditor(Connection connection) { - String dbVersion = DBAccessorUtil.getDbVersion(connection); - if (VersionUtils.isLessThan(dbVersion, "2.2.77")) { - return new OBMySQLLessThan2277PartitionEditor(); - } else { - return new MySQLDBTablePartitionEditor(); - } - } - } diff --git a/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/utils/DBAccessorUtil.java b/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/utils/DBAccessorUtil.java index a21abdc75d..f30d4ffee5 100644 --- a/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/utils/DBAccessorUtil.java +++ b/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/utils/DBAccessorUtil.java @@ -18,9 +18,18 @@ import java.sql.Connection; import com.oceanbase.odc.common.util.JdbcOperationsUtil; +import com.oceanbase.odc.common.util.VersionUtils; import com.oceanbase.odc.plugin.connect.obmysql.OBMySQLInformationExtension; import com.oceanbase.odc.plugin.schema.obmysql.browser.DBSchemaAccessors; import com.oceanbase.odc.plugin.schema.obmysql.browser.DBStatsAccessors; +import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; +import com.oceanbase.tools.dbbrowser.editor.DBTablePartitionEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLColumnEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLConstraintEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLDBTablePartitionEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLIndexEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLLessThan2277PartitionEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLTableEditor; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; import com.oceanbase.tools.dbbrowser.stats.DBStatsAccessor; @@ -41,4 +50,18 @@ public static DBSchemaAccessor getSchemaAccessor(Connection connection) { public static DBStatsAccessor getStatsAccessor(Connection connection) { return DBStatsAccessors.create(JdbcOperationsUtil.getJdbcOperations(connection), getDbVersion(connection)); } + + public static DBTableEditor getTableEditor(Connection connection) { + return new OBMySQLTableEditor(new OBMySQLIndexEditor(), new MySQLColumnEditor(), new MySQLConstraintEditor(), + getDBTablePartitionEditor(connection)); + } + + private static DBTablePartitionEditor getDBTablePartitionEditor(Connection connection) { + String dbVersion = getDbVersion(connection); + if (VersionUtils.isLessThan(dbVersion, "2.2.77")) { + return new OBMySQLLessThan2277PartitionEditor(); + } else { + return new MySQLDBTablePartitionEditor(); + } + } } diff --git a/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleSchemaBrowserExtension.java b/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleSchemaBrowserExtension.java new file mode 100644 index 0000000000..b7f1ae27d1 --- /dev/null +++ b/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleSchemaBrowserExtension.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.plugin.schema.oboracle; + +import java.sql.Connection; + +import org.pf4j.Extension; + +import com.oceanbase.odc.plugin.schema.api.SchemaBrowserExtensionPoint; +import com.oceanbase.odc.plugin.schema.oboracle.utils.DBAccessorUtil; +import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; +import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; + +/** + * @author jingtian + * @date 2024/1/5 + * @since ODC_release_4.2.4 + */ +@Extension +public class OBOracleSchemaBrowserExtension implements SchemaBrowserExtensionPoint { + @Override + public DBSchemaAccessor getDBSchemaAccessor(Connection connection) { + return DBAccessorUtil.getSchemaAccessor(connection); + } + + @Override + public DBTableEditor getDBTableEditor(Connection connection) { + return DBAccessorUtil.getTableEditor(connection); + } +} diff --git a/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleTableExtension.java b/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleTableExtension.java index 0c2f379aa9..d543ec8342 100644 --- a/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleTableExtension.java +++ b/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleTableExtension.java @@ -28,11 +28,6 @@ import com.oceanbase.odc.plugin.schema.oboracle.parser.OBOracleGetDBTableByParser; import com.oceanbase.odc.plugin.schema.oboracle.utils.DBAccessorUtil; import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; -import com.oceanbase.tools.dbbrowser.editor.oracle.OBOracleIndexEditor; -import com.oceanbase.tools.dbbrowser.editor.oracle.OracleColumnEditor; -import com.oceanbase.tools.dbbrowser.editor.oracle.OracleConstraintEditor; -import com.oceanbase.tools.dbbrowser.editor.oracle.OracleDBTablePartitionEditor; -import com.oceanbase.tools.dbbrowser.editor.oracle.OracleTableEditor; import com.oceanbase.tools.dbbrowser.model.DBIndexType; import com.oceanbase.tools.dbbrowser.model.DBTable; import com.oceanbase.tools.dbbrowser.model.DBTable.DBTableOptions; @@ -144,7 +139,6 @@ protected DBStatsAccessor getStatsAccessor(Connection connection) { @Override protected DBTableEditor getTableEditor(Connection connection) { - return new OracleTableEditor(new OBOracleIndexEditor(), new OracleColumnEditor(), - new OracleConstraintEditor(), new OracleDBTablePartitionEditor()); + return DBAccessorUtil.getTableEditor(connection); } } diff --git a/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/utils/DBAccessorUtil.java b/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/utils/DBAccessorUtil.java index c306310adc..a4ecf840b8 100644 --- a/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/utils/DBAccessorUtil.java +++ b/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/utils/DBAccessorUtil.java @@ -21,6 +21,12 @@ import com.oceanbase.odc.plugin.connect.oboracle.OBOracleInformationExtension; import com.oceanbase.odc.plugin.schema.oboracle.browser.DBSchemaAccessors; import com.oceanbase.odc.plugin.schema.oboracle.browser.DBStatsAccessors; +import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; +import com.oceanbase.tools.dbbrowser.editor.oracle.OBOracleIndexEditor; +import com.oceanbase.tools.dbbrowser.editor.oracle.OracleColumnEditor; +import com.oceanbase.tools.dbbrowser.editor.oracle.OracleConstraintEditor; +import com.oceanbase.tools.dbbrowser.editor.oracle.OracleDBTablePartitionEditor; +import com.oceanbase.tools.dbbrowser.editor.oracle.OracleTableEditor; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; import com.oceanbase.tools.dbbrowser.stats.DBStatsAccessor; @@ -42,4 +48,9 @@ public static DBStatsAccessor getStatsAccessor(Connection connection) { return DBStatsAccessors.create(JdbcOperationsUtil.getJdbcOperations(connection), getDbVersion(connection)); } + public static DBTableEditor getTableEditor(Connection connection) { + return new OracleTableEditor(new OBOracleIndexEditor(), new OracleColumnEditor(), + new OracleConstraintEditor(), new OracleDBTablePartitionEditor()); + } + } diff --git a/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLSchemaBrowserExtension.java b/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLSchemaBrowserExtension.java new file mode 100644 index 0000000000..59e4428684 --- /dev/null +++ b/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLSchemaBrowserExtension.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.plugin.schema.odpsharding.obmysql; + +import java.sql.Connection; + +import org.pf4j.Extension; + +import com.oceanbase.odc.common.util.JdbcOperationsUtil; +import com.oceanbase.odc.plugin.schema.api.SchemaBrowserExtensionPoint; +import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLColumnEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLConstraintEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLDBTablePartitionEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLIndexEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLTableEditor; +import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; +import com.oceanbase.tools.dbbrowser.schema.mysql.ODPOBMySQLSchemaAccessor; + +/** + * @author jingtian + * @date 2024/1/5 + * @since ODC_release_4.2.4 + */ +@Extension +public class ODPShardingOBMySQLSchemaBrowserExtension implements SchemaBrowserExtensionPoint { + @Override + public DBSchemaAccessor getDBSchemaAccessor(Connection connection) { + return new ODPOBMySQLSchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); + } + + @Override + public DBTableEditor getDBTableEditor(Connection connection) { + return new OBMySQLTableEditor(new OBMySQLIndexEditor(), new MySQLColumnEditor(), new MySQLConstraintEditor(), + new MySQLDBTablePartitionEditor()); + } +} diff --git a/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLTableExtension.java b/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLTableExtension.java index 2544583aa8..1131e52a79 100644 --- a/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLTableExtension.java +++ b/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLTableExtension.java @@ -19,13 +19,10 @@ import org.pf4j.Extension; -import com.oceanbase.odc.common.util.JdbcOperationsUtil; import com.oceanbase.odc.plugin.schema.obmysql.OBMySQLTableExtension; -import com.oceanbase.tools.dbbrowser.editor.DBTablePartitionEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLDBTablePartitionEditor; +import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; import com.oceanbase.tools.dbbrowser.model.DBTable; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; -import com.oceanbase.tools.dbbrowser.schema.mysql.ODPOBMySQLSchemaAccessor; import com.oceanbase.tools.dbbrowser.stats.DBStatsAccessor; import com.oceanbase.tools.dbbrowser.stats.mysql.ODPOBMySQLStatsAccessor; @@ -51,7 +48,7 @@ public DBTable getDetail(@NonNull Connection connection, @NonNull String schemaN @Override protected DBSchemaAccessor getSchemaAccessor(Connection connection) { - return new ODPOBMySQLSchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); + return new ODPShardingOBMySQLSchemaBrowserExtension().getDBSchemaAccessor(connection); } @Override @@ -61,7 +58,7 @@ protected DBStatsAccessor getStatsAccessor(Connection consoleConnection) { } @Override - protected DBTablePartitionEditor getDBTablePartitionEditor(Connection connection) { - return new MySQLDBTablePartitionEditor(); + protected DBTableEditor getTableEditor(Connection connection) { + return new ODPShardingOBMySQLSchemaBrowserExtension().getDBTableEditor(connection); } } From 554fd2edfb2c0333516f344e9600de75753f61b0 Mon Sep 17 00:00:00 2001 From: jingtian Date: Tue, 9 Jan 2024 16:06:39 +0800 Subject: [PATCH 2/5] delete SchemaBrowserExtensionPoint --- pom.xml | 5 ++ .../OdcDBStructureComparatorTest.java | 12 +-- server/odc-service/pom.xml | 9 +++ .../service/db/browser/DBSchemaAccessors.java | 31 +++++--- .../odc/service/plugin/SchemaPluginUtil.java | 4 - .../OdcDBStructureComparator.java | 79 +++++++++++++++---- .../model/DBStructureComparisonConfig.java | 4 +- .../api/SchemaBrowserExtensionPoint.java | 34 -------- .../schema/mysql/MySQLDatabaseExtension.java | 4 +- .../schema/mysql/MySQLFunctionExtension.java | 4 +- .../schema/mysql/MySQLProcedureExtension.java | 4 +- .../mysql/MySQLSchemaBrowserExtension.java | 51 ------------ .../schema/mysql/MySQLTableExtension.java | 12 ++- .../schema/mysql/MySQLViewExtension.java | 4 +- .../OBMySQLSchemaBrowserExtension.java | 43 ---------- .../schema/obmysql/OBMySQLTableExtension.java | 20 ++++- .../schema/obmysql/utils/DBAccessorUtil.java | 23 ------ .../OBOracleSchemaBrowserExtension.java | 43 ---------- .../oboracle/OBOracleTableExtension.java | 8 +- .../schema/oboracle/utils/DBAccessorUtil.java | 11 --- ...ShardingOBMySQLSchemaBrowserExtension.java | 50 ------------ .../ODPShardingOBMySQLTableExtension.java | 11 ++- 22 files changed, 162 insertions(+), 304 deletions(-) delete mode 100644 server/plugins/schema-plugin-api/src/main/java/com/oceanbase/odc/plugin/schema/api/SchemaBrowserExtensionPoint.java delete mode 100644 server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLSchemaBrowserExtension.java delete mode 100644 server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLSchemaBrowserExtension.java delete mode 100644 server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleSchemaBrowserExtension.java delete mode 100644 server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLSchemaBrowserExtension.java diff --git a/pom.xml b/pom.xml index 5806fb5ced..a958bc6903 100644 --- a/pom.xml +++ b/pom.xml @@ -273,6 +273,11 @@ schema-plugin-api ${project.version} + + com.oceanbase + schema-plugin-ob-mysql + ${project.version} + com.oceanbase task-plugin-api diff --git a/server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparatorTest.java b/server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparatorTest.java index 32870281d8..221caa5acc 100644 --- a/server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparatorTest.java +++ b/server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparatorTest.java @@ -37,7 +37,7 @@ import org.springframework.jdbc.core.JdbcTemplate; import com.oceanbase.odc.PluginTestEnv; -import com.oceanbase.odc.core.shared.constant.DialectType; +import com.oceanbase.odc.core.shared.constant.ConnectType; import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; import com.oceanbase.odc.service.structurecompare.model.DBStructureComparisonConfig; @@ -106,7 +106,7 @@ private static String generateSchemaName() { private static DBStructureComparisonConfig getSourceConfig(TestDBConfiguration configuration) { DBStructureComparisonConfig srcConfig = new DBStructureComparisonConfig(); srcConfig.setSchemaName(sourceSchemaName); - srcConfig.setDialectType(DialectType.OB_MYSQL); + srcConfig.setConnectType(ConnectType.OB_MYSQL); srcConfig.setDataSource(configuration.getDataSource()); srcConfig.setToComparedObjectTypes(Collections.singleton(DBObjectType.TABLE)); return srcConfig; @@ -115,7 +115,7 @@ private static DBStructureComparisonConfig getSourceConfig(TestDBConfiguration c private static DBStructureComparisonConfig getTargetConfig(TestDBConfiguration configuration) { DBStructureComparisonConfig srcConfig = new DBStructureComparisonConfig(); srcConfig.setSchemaName(targetSchemaName); - srcConfig.setDialectType(DialectType.OB_MYSQL); + srcConfig.setConnectType(ConnectType.OB_MYSQL); srcConfig.setDataSource(configuration.getDataSource()); srcConfig.setToComparedObjectTypes(Collections.singleton(DBObjectType.TABLE)); return srcConfig; @@ -124,7 +124,7 @@ private static DBStructureComparisonConfig getTargetConfig(TestDBConfiguration c @Test public void test_srcDialectTypeNotEqualsToTgtDialectType_throwException() throws SQLException { DBStructureComparisonConfig targetConfig = getTargetConfig(tgtConfiguration); - targetConfig.setDialectType(DialectType.OB_ORACLE); + targetConfig.setConnectType(ConnectType.OB_ORACLE); thrown.expect(IllegalArgumentException.class); thrown.expectMessage("The dialect type of source and target schema must be equal"); comparator.compare(getSourceConfig(srcConfiguration), targetConfig); @@ -133,9 +133,9 @@ public void test_srcDialectTypeNotEqualsToTgtDialectType_throwException() throws @Test public void test_notSupportedDialect_throwException() throws SQLException { DBStructureComparisonConfig sourceConfig = getSourceConfig(srcConfiguration); - sourceConfig.setDialectType(DialectType.ORACLE); + sourceConfig.setConnectType(ConnectType.ORACLE); DBStructureComparisonConfig targetConfig = getTargetConfig(tgtConfiguration); - targetConfig.setDialectType(DialectType.ORACLE); + targetConfig.setConnectType(ConnectType.ORACLE); thrown.expect(UnsupportedOperationException.class); thrown.expectMessage("Unsupported dialect type for schema structure comparison: ORACLE"); comparator.compare(sourceConfig, targetConfig); diff --git a/server/odc-service/pom.xml b/server/odc-service/pom.xml index fc4894a855..00c4169b1b 100644 --- a/server/odc-service/pom.xml +++ b/server/odc-service/pom.xml @@ -46,6 +46,10 @@ 5.6.0 runtime + + com.oceanbase + schema-plugin-ob-mysql + @@ -261,5 +265,10 @@ com.oceanbase task-plugin-api + + com.oceanbase + schema-plugin-ob-mysql + ${project.version} + diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/db/browser/DBSchemaAccessors.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/db/browser/DBSchemaAccessors.java index d09e986456..ce273eab56 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/db/browser/DBSchemaAccessors.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/db/browser/DBSchemaAccessors.java @@ -15,6 +15,8 @@ */ package com.oceanbase.odc.service.db.browser; +import org.springframework.jdbc.core.JdbcOperations; + import com.oceanbase.odc.common.util.VersionUtils; import com.oceanbase.odc.core.session.ConnectionSession; import com.oceanbase.odc.core.session.ConnectionSessionConstants; @@ -37,6 +39,7 @@ import com.oceanbase.tools.dbbrowser.schema.oracle.OracleSchemaAccessor; import com.oceanbase.tools.dbbrowser.util.ALLDataDictTableNames; +import lombok.NonNull; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -57,6 +60,23 @@ public static DBSchemaAccessor create(ConnectionSession connectionSession, Strin String obVersion = ConnectionSessionUtil.getVersion(connectionSession); PreConditions.notNull(obVersion, "obVersion"); + SyncJdbcExecutor sysSyncJdbcExecutor = null; + String tenantName = null; + if (VersionUtils.isGreaterThanOrEqualsTo(obVersion, "1.4.79")) { + try { + sysSyncJdbcExecutor = + connectionSession.getSyncJdbcExecutor(ConnectionSessionConstants.SYS_DS_KEY); + tenantName = ConnectionSessionUtil.getTenantName(connectionSession); + } catch (Exception e) { + log.warn("Get SYS-DATASOURCE failed, may lack of sys tenant permission,message={}", e.getMessage()); + } + } + + return create(syncJdbcExecutor, sysSyncJdbcExecutor, connectType, obVersion, tenantName); + } + + public static DBSchemaAccessor create(@NonNull JdbcOperations syncJdbcExecutor, JdbcOperations sysJdbcExecutor, + @NonNull ConnectType connectType, @NonNull String obVersion, String tenantName) { if (connectType == ConnectType.OB_MYSQL || connectType == ConnectType.CLOUD_OB_MYSQL) { if (VersionUtils.isGreaterThanOrEqualsTo(obVersion, "4.0.0")) { // OB 版本 >= 4.0.0 @@ -72,16 +92,7 @@ public static DBSchemaAccessor create(ConnectionSession connectionSession, Strin return new OBMySQLBetween220And225XSchemaAccessor(syncJdbcExecutor); } else { // OB 版本 <= 1.4.79 - SyncJdbcExecutor sysSyncJdbcExecutor = null; - String tenantName = null; - try { - sysSyncJdbcExecutor = - connectionSession.getSyncJdbcExecutor(ConnectionSessionConstants.SYS_DS_KEY); - tenantName = ConnectionSessionUtil.getTenantName(connectionSession); - } catch (Exception e) { - log.warn("Get SYS-DATASOURCE failed, may lack of sys tenant permission,message={}", e.getMessage()); - } - return new OBMySQLNoGreaterThan1479SchemaAccessor(syncJdbcExecutor, sysSyncJdbcExecutor, tenantName); + return new OBMySQLNoGreaterThan1479SchemaAccessor(syncJdbcExecutor, sysJdbcExecutor, tenantName); } } else if (connectType == ConnectType.OB_ORACLE || connectType == ConnectType.CLOUD_OB_ORACLE) { if (VersionUtils.isGreaterThanOrEqualsTo(obVersion, "4.0.0")) { diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/plugin/SchemaPluginUtil.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/plugin/SchemaPluginUtil.java index 7381e66731..784f436791 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/plugin/SchemaPluginUtil.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/plugin/SchemaPluginUtil.java @@ -24,7 +24,6 @@ import com.oceanbase.odc.plugin.schema.api.FunctionExtensionPoint; import com.oceanbase.odc.plugin.schema.api.PackageExtensionPoint; import com.oceanbase.odc.plugin.schema.api.ProcedureExtensionPoint; -import com.oceanbase.odc.plugin.schema.api.SchemaBrowserExtensionPoint; import com.oceanbase.odc.plugin.schema.api.SequenceExtensionPoint; import com.oceanbase.odc.plugin.schema.api.SynonymExtensionPoint; import com.oceanbase.odc.plugin.schema.api.TableExtensionPoint; @@ -83,9 +82,6 @@ public static TypeExtensionPoint getTypeExtension(DialectType dialectType) { return getSingletonExtension(dialectType, TypeExtensionPoint.class); } - public static SchemaBrowserExtensionPoint getSchemaBrowserExtension(DialectType dialectType) { - return getSingletonExtension(dialectType, SchemaBrowserExtensionPoint.class); - } public static T getSingletonExtension(DialectType dialectType, Class type) { return getOdcPluginManager().getSingletonExtension(dialectType, type); diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparator.java index 936e8b980a..671786e55d 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparator.java @@ -22,10 +22,20 @@ import java.util.List; import java.util.Map; +import javax.sql.DataSource; + import org.apache.commons.compress.utils.Lists; +import com.oceanbase.odc.common.util.JdbcOperationsUtil; +import com.oceanbase.odc.common.util.VersionUtils; +import com.oceanbase.odc.core.shared.constant.ConnectType; import com.oceanbase.odc.core.shared.constant.DialectType; -import com.oceanbase.odc.service.plugin.SchemaPluginUtil; +import com.oceanbase.odc.plugin.connect.api.InformationExtensionPoint; +import com.oceanbase.odc.plugin.schema.obmysql.parser.OBMySQLGetDBTableByParser; +import com.oceanbase.odc.service.db.browser.DBObjectEditorFactory; +import com.oceanbase.odc.service.db.browser.DBSchemaAccessors; +import com.oceanbase.odc.service.db.browser.DBTableEditorFactory; +import com.oceanbase.odc.service.plugin.ConnectionPluginUtil; import com.oceanbase.odc.service.structurecompare.comparedbobject.TableStructureComparator; import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; @@ -60,17 +70,23 @@ public List compare(@NonNull DBStructureComparisonConf List returnVal = new ArrayList<>(); checkConfig(srcConfig, tgtConfig); - DBSchemaAccessor srcAccessor = SchemaPluginUtil.getSchemaBrowserExtension(srcConfig.getDialectType()) - .getDBSchemaAccessor(srcConfig.getDataSource().getConnection()); - DBSchemaAccessor tgtAccessor = SchemaPluginUtil.getSchemaBrowserExtension(tgtConfig.getDialectType()) - .getDBSchemaAccessor(tgtConfig.getDataSource().getConnection()); - DBTableEditor tgtTableEditor = SchemaPluginUtil.getSchemaBrowserExtension(tgtConfig.getDialectType()) - .getDBTableEditor(tgtConfig.getDataSource().getConnection()); + String srcDbVersion = getDBVersion(srcConfig.getConnectType(), srcConfig.getDataSource()); + String tgtDbVersion = getDBVersion(tgtConfig.getConnectType(), tgtConfig.getDataSource()); + + DBSchemaAccessor srcAccessor = + getDBSchemaAccessor(srcConfig.getConnectType(), srcConfig.getDataSource(), srcDbVersion); + DBSchemaAccessor tgtAccessor = + getDBSchemaAccessor(tgtConfig.getConnectType(), tgtConfig.getDataSource(), tgtDbVersion); + + DBTableEditor tgtTableEditor = getDBTableEditor(tgtConfig.getConnectType(), tgtDbVersion); + + Map srcTables = buildSchemaTables(srcAccessor, srcConfig.getSchemaName(), + srcConfig.getConnectType().getDialectType(), srcDbVersion); + Map tgtTables = buildSchemaTables(tgtAccessor, tgtConfig.getSchemaName(), + tgtConfig.getConnectType().getDialectType(), tgtDbVersion); - Map srcTables = buildSchemaTables(srcAccessor, srcConfig.getSchemaName()); - Map tgtTables = buildSchemaTables(tgtAccessor, tgtConfig.getSchemaName()); TableStructureComparator tableComparator = new TableStructureComparator(tgtTableEditor, - tgtConfig.getDialectType(), + tgtConfig.getConnectType().getDialectType(), srcConfig.getSchemaName(), tgtConfig.getSchemaName()); if (srcConfig.getBlackListMap().get(DBObjectType.TABLE) == null) { @@ -97,13 +113,38 @@ public List compare(@NonNull DBStructureComparisonConf return returnVal; } + private DBSchemaAccessor getDBSchemaAccessor(ConnectType connectType, DataSource dataSource, String dbVersion) + throws SQLException { + /** + * sysJdbcOperations and tenantName are required for OBMySQLNoGreaterThan1479SchemaAccessor to get + * table partition, this method will be replaced by OBMySQLGetDBTableByParser, so we just set it + * null here. + */ + return DBSchemaAccessors.create(JdbcOperationsUtil.getJdbcOperations(dataSource.getConnection()), null, + connectType, dbVersion, null); + } + + private DBTableEditor getDBTableEditor(ConnectType connectType, String dbVersion) { + DBObjectEditorFactory tableEditorFactory = + new DBTableEditorFactory(connectType, dbVersion); + return tableEditorFactory.create(); + } + + private String getDBVersion(ConnectType connectType, DataSource dataSource) throws SQLException { + InformationExtensionPoint informationExtension = ConnectionPluginUtil.getInformationExtension( + connectType.getDialectType()); + return informationExtension.getDBVersion(dataSource.getConnection()); + + } + private void checkConfig(DBStructureComparisonConfig srcConfig, DBStructureComparisonConfig tgtConfig) { - if (!srcConfig.getDialectType().equals(tgtConfig.getDialectType())) { + if (!srcConfig.getConnectType().getDialectType().equals(tgtConfig.getConnectType().getDialectType())) { throw new IllegalArgumentException("The dialect type of source and target schema must be equal"); } - if (!supportedDialectTypes.contains(srcConfig.getDialectType())) { + if (!supportedDialectTypes.contains(srcConfig.getConnectType().getDialectType())) { throw new UnsupportedOperationException( - "Unsupported dialect type for schema structure comparison: " + srcConfig.getDialectType()); + "Unsupported dialect type for schema structure comparison: " + + srcConfig.getConnectType().getDialectType()); } srcConfig.getToComparedObjectTypes().stream().forEach(dbObjectType -> { if (!supportedDBObjectTypes.contains(dbObjectType)) { @@ -113,7 +154,8 @@ private void checkConfig(DBStructureComparisonConfig srcConfig, DBStructureCompa }); } - private Map buildSchemaTables(DBSchemaAccessor accessor, String schemaName) { + private Map buildSchemaTables(DBSchemaAccessor accessor, String schemaName, + DialectType dialectType, String dbVersion) { Map returnVal = new HashMap<>(); List tableNames = accessor.showTables(schemaName); if (tableNames.isEmpty()) { @@ -137,7 +179,14 @@ private Map buildSchemaTables(DBSchemaAccessor accessor, String table.setIndexes(tableName2Indexes.getOrDefault(tableName, Lists.newArrayList())); table.setConstraints(tableName2Constraints.getOrDefault(tableName, Lists.newArrayList())); table.setTableOptions(tableName2Options.getOrDefault(tableName, new DBTableOptions())); - table.setPartition(accessor.getPartition(schemaName, tableName)); + if (DialectType.OB_MYSQL.equals(dialectType) && VersionUtils.isLessThanOrEqualsTo(dbVersion, "1.4.79")) { + // Remove dependence on sys account + String ddl = accessor.getTableDDL(schemaName, tableName); + OBMySQLGetDBTableByParser parser = new OBMySQLGetDBTableByParser(ddl); + table.setPartition(parser.getPartition()); + } else { + table.setPartition(accessor.getPartition(schemaName, tableName)); + } table.setDDL(accessor.getTableDDL(schemaName, tableName)); returnVal.put(tableName, table); } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBStructureComparisonConfig.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBStructureComparisonConfig.java index be8fb904dd..acf3791188 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBStructureComparisonConfig.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBStructureComparisonConfig.java @@ -22,7 +22,7 @@ import javax.sql.DataSource; import javax.validation.constraints.NotNull; -import com.oceanbase.odc.core.shared.constant.DialectType; +import com.oceanbase.odc.core.shared.constant.ConnectType; import com.oceanbase.tools.dbbrowser.model.DBObjectType; import lombok.Data; @@ -37,7 +37,7 @@ public class DBStructureComparisonConfig { @NotNull private String schemaName; @NotNull - private DialectType dialectType; + private ConnectType connectType; @NotNull private DataSource dataSource; @NotNull diff --git a/server/plugins/schema-plugin-api/src/main/java/com/oceanbase/odc/plugin/schema/api/SchemaBrowserExtensionPoint.java b/server/plugins/schema-plugin-api/src/main/java/com/oceanbase/odc/plugin/schema/api/SchemaBrowserExtensionPoint.java deleted file mode 100644 index 432f9f8ed5..0000000000 --- a/server/plugins/schema-plugin-api/src/main/java/com/oceanbase/odc/plugin/schema/api/SchemaBrowserExtensionPoint.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2023 OceanBase. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.oceanbase.odc.plugin.schema.api; - -import java.sql.Connection; - -import org.pf4j.ExtensionPoint; - -import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; -import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; - -/** - * @author jingtian - * @date 2024/1/5 - * @since ODC_release_4.2.4 - */ -public interface SchemaBrowserExtensionPoint extends ExtensionPoint { - DBSchemaAccessor getDBSchemaAccessor(Connection connection); - - DBTableEditor getDBTableEditor(Connection connection); -} diff --git a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLDatabaseExtension.java b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLDatabaseExtension.java index 1ced426a9a..882a0adcfe 100644 --- a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLDatabaseExtension.java +++ b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLDatabaseExtension.java @@ -19,8 +19,10 @@ import org.pf4j.Extension; +import com.oceanbase.odc.common.util.JdbcOperationsUtil; import com.oceanbase.odc.plugin.schema.obmysql.OBMySQLDatabaseExtension; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; +import com.oceanbase.tools.dbbrowser.schema.mysql.MySQLNoGreaterThan5740SchemaAccessor; /** * @author jingtian @@ -31,6 +33,6 @@ public class MySQLDatabaseExtension extends OBMySQLDatabaseExtension { @Override protected DBSchemaAccessor getSchemaAccessor(Connection connection) { - return new MySQLSchemaBrowserExtension().getDBSchemaAccessor(connection); + return new MySQLNoGreaterThan5740SchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); } } diff --git a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLFunctionExtension.java b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLFunctionExtension.java index e4ab191090..65014cf071 100644 --- a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLFunctionExtension.java +++ b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLFunctionExtension.java @@ -19,8 +19,10 @@ import org.pf4j.Extension; +import com.oceanbase.odc.common.util.JdbcOperationsUtil; import com.oceanbase.odc.plugin.schema.obmysql.OBMySQLFunctionExtension; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; +import com.oceanbase.tools.dbbrowser.schema.mysql.MySQLNoGreaterThan5740SchemaAccessor; /** * @author jingtian @@ -31,6 +33,6 @@ public class MySQLFunctionExtension extends OBMySQLFunctionExtension { @Override protected DBSchemaAccessor getSchemaAccessor(Connection connection) { - return new MySQLSchemaBrowserExtension().getDBSchemaAccessor(connection); + return new MySQLNoGreaterThan5740SchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); } } diff --git a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLProcedureExtension.java b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLProcedureExtension.java index 8cbf874d60..2093536c31 100644 --- a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLProcedureExtension.java +++ b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLProcedureExtension.java @@ -19,8 +19,10 @@ import org.pf4j.Extension; +import com.oceanbase.odc.common.util.JdbcOperationsUtil; import com.oceanbase.odc.plugin.schema.obmysql.OBMySQLProcedureExtension; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; +import com.oceanbase.tools.dbbrowser.schema.mysql.MySQLNoGreaterThan5740SchemaAccessor; /** * @author jingtian @@ -31,6 +33,6 @@ public class MySQLProcedureExtension extends OBMySQLProcedureExtension { @Override protected DBSchemaAccessor getSchemaAccessor(Connection connection) { - return new MySQLSchemaBrowserExtension().getDBSchemaAccessor(connection); + return new MySQLNoGreaterThan5740SchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); } } diff --git a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLSchemaBrowserExtension.java b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLSchemaBrowserExtension.java deleted file mode 100644 index 44bcc95d86..0000000000 --- a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLSchemaBrowserExtension.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2023 OceanBase. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.oceanbase.odc.plugin.schema.mysql; - -import java.sql.Connection; - -import org.pf4j.Extension; - -import com.oceanbase.odc.common.util.JdbcOperationsUtil; -import com.oceanbase.odc.plugin.schema.api.SchemaBrowserExtensionPoint; -import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLColumnEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLConstraintEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLDBTablePartitionEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLNoGreaterThan5740IndexEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLTableEditor; -import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; -import com.oceanbase.tools.dbbrowser.schema.mysql.MySQLNoGreaterThan5740SchemaAccessor; - -/** - * @author jingtian - * @date 2024/1/5 - * @since ODC_release_4.2.4 - */ -@Extension -public class MySQLSchemaBrowserExtension implements SchemaBrowserExtensionPoint { - @Override - public DBSchemaAccessor getDBSchemaAccessor(Connection connection) { - return new MySQLNoGreaterThan5740SchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); - } - - @Override - public DBTableEditor getDBTableEditor(Connection connection) { - return new MySQLTableEditor(new MySQLNoGreaterThan5740IndexEditor(), new MySQLColumnEditor(), - new MySQLConstraintEditor(), - new MySQLDBTablePartitionEditor()); - } -} diff --git a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLTableExtension.java b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLTableExtension.java index 686b385e0b..3909eacd3d 100644 --- a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLTableExtension.java +++ b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLTableExtension.java @@ -22,8 +22,14 @@ import com.oceanbase.odc.common.util.JdbcOperationsUtil; import com.oceanbase.odc.plugin.schema.obmysql.OBMySQLTableExtension; import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLColumnEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLConstraintEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLDBTablePartitionEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLNoGreaterThan5740IndexEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLTableEditor; import com.oceanbase.tools.dbbrowser.model.DBTable; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; +import com.oceanbase.tools.dbbrowser.schema.mysql.MySQLNoGreaterThan5740SchemaAccessor; import com.oceanbase.tools.dbbrowser.stats.DBStatsAccessor; import com.oceanbase.tools.dbbrowser.stats.mysql.MySQLNoGreaterThan5740StatsAccessor; @@ -55,12 +61,14 @@ public DBTable getDetail(@NonNull Connection connection, @NonNull String schemaN @Override protected DBTableEditor getTableEditor(@NonNull Connection connection) { - return new MySQLSchemaBrowserExtension().getDBTableEditor(connection); + return new MySQLTableEditor(new MySQLNoGreaterThan5740IndexEditor(), new MySQLColumnEditor(), + new MySQLConstraintEditor(), + new MySQLDBTablePartitionEditor()); } @Override protected DBSchemaAccessor getSchemaAccessor(Connection connection) { - return new MySQLSchemaBrowserExtension().getDBSchemaAccessor(connection); + return new MySQLNoGreaterThan5740SchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); } @Override diff --git a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLViewExtension.java b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLViewExtension.java index 665933809a..4a55b74770 100644 --- a/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLViewExtension.java +++ b/server/plugins/schema-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/schema/mysql/MySQLViewExtension.java @@ -19,8 +19,10 @@ import org.pf4j.Extension; +import com.oceanbase.odc.common.util.JdbcOperationsUtil; import com.oceanbase.odc.plugin.schema.obmysql.OBMySQLViewExtension; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; +import com.oceanbase.tools.dbbrowser.schema.mysql.MySQLNoGreaterThan5740SchemaAccessor; /** * @author jingtian @@ -31,6 +33,6 @@ public class MySQLViewExtension extends OBMySQLViewExtension { @Override protected DBSchemaAccessor getSchemaAccessor(Connection connection) { - return new MySQLSchemaBrowserExtension().getDBSchemaAccessor(connection); + return new MySQLNoGreaterThan5740SchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); } } diff --git a/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLSchemaBrowserExtension.java b/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLSchemaBrowserExtension.java deleted file mode 100644 index f934c2b70d..0000000000 --- a/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLSchemaBrowserExtension.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2023 OceanBase. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.oceanbase.odc.plugin.schema.obmysql; - -import java.sql.Connection; - -import org.pf4j.Extension; - -import com.oceanbase.odc.plugin.schema.api.SchemaBrowserExtensionPoint; -import com.oceanbase.odc.plugin.schema.obmysql.utils.DBAccessorUtil; -import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; -import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; - -/** - * @author jingtian - * @date 2024/1/5 - * @since ODC_release_4.2.4 - */ -@Extension -public class OBMySQLSchemaBrowserExtension implements SchemaBrowserExtensionPoint { - @Override - public DBSchemaAccessor getDBSchemaAccessor(Connection connection) { - return DBAccessorUtil.getSchemaAccessor(connection); - } - - @Override - public DBTableEditor getDBTableEditor(Connection connection) { - return DBAccessorUtil.getTableEditor(connection); - } -} diff --git a/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLTableExtension.java b/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLTableExtension.java index f7037d5f9a..e9bdd4b095 100644 --- a/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLTableExtension.java +++ b/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/OBMySQLTableExtension.java @@ -23,12 +23,20 @@ import com.oceanbase.odc.common.unit.BinarySizeUnit; import com.oceanbase.odc.common.util.JdbcOperationsUtil; +import com.oceanbase.odc.common.util.VersionUtils; import com.oceanbase.odc.plugin.schema.api.TableExtensionPoint; import com.oceanbase.odc.plugin.schema.obmysql.parser.OBMySQLGetDBTableByParser; import com.oceanbase.odc.plugin.schema.obmysql.utils.DBAccessorUtil; import com.oceanbase.tools.dbbrowser.editor.DBObjectOperator; import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; +import com.oceanbase.tools.dbbrowser.editor.DBTablePartitionEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLColumnEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLConstraintEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLDBTablePartitionEditor; import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLObjectOperator; +import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLIndexEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLLessThan2277PartitionEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLTableEditor; import com.oceanbase.tools.dbbrowser.model.DBObjectIdentity; import com.oceanbase.tools.dbbrowser.model.DBObjectType; import com.oceanbase.tools.dbbrowser.model.DBTable; @@ -113,7 +121,8 @@ public String generateUpdateDDL(@NonNull Connection connection, @NonNull DBTable } protected DBTableEditor getTableEditor(Connection connection) { - return DBAccessorUtil.getTableEditor(connection); + return new OBMySQLTableEditor(new OBMySQLIndexEditor(), new MySQLColumnEditor(), new MySQLConstraintEditor(), + getDBTablePartitionEditor(connection)); } protected DBSchemaAccessor getSchemaAccessor(Connection connection) { @@ -128,4 +137,13 @@ private DBObjectOperator getTableOperator(Connection connection) { return new MySQLObjectOperator(JdbcOperationsUtil.getJdbcOperations(connection)); } + protected DBTablePartitionEditor getDBTablePartitionEditor(Connection connection) { + String dbVersion = DBAccessorUtil.getDbVersion(connection); + if (VersionUtils.isLessThan(dbVersion, "2.2.77")) { + return new OBMySQLLessThan2277PartitionEditor(); + } else { + return new MySQLDBTablePartitionEditor(); + } + } + } diff --git a/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/utils/DBAccessorUtil.java b/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/utils/DBAccessorUtil.java index f30d4ffee5..a21abdc75d 100644 --- a/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/utils/DBAccessorUtil.java +++ b/server/plugins/schema-plugin-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/obmysql/utils/DBAccessorUtil.java @@ -18,18 +18,9 @@ import java.sql.Connection; import com.oceanbase.odc.common.util.JdbcOperationsUtil; -import com.oceanbase.odc.common.util.VersionUtils; import com.oceanbase.odc.plugin.connect.obmysql.OBMySQLInformationExtension; import com.oceanbase.odc.plugin.schema.obmysql.browser.DBSchemaAccessors; import com.oceanbase.odc.plugin.schema.obmysql.browser.DBStatsAccessors; -import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; -import com.oceanbase.tools.dbbrowser.editor.DBTablePartitionEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLColumnEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLConstraintEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLDBTablePartitionEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLIndexEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLLessThan2277PartitionEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLTableEditor; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; import com.oceanbase.tools.dbbrowser.stats.DBStatsAccessor; @@ -50,18 +41,4 @@ public static DBSchemaAccessor getSchemaAccessor(Connection connection) { public static DBStatsAccessor getStatsAccessor(Connection connection) { return DBStatsAccessors.create(JdbcOperationsUtil.getJdbcOperations(connection), getDbVersion(connection)); } - - public static DBTableEditor getTableEditor(Connection connection) { - return new OBMySQLTableEditor(new OBMySQLIndexEditor(), new MySQLColumnEditor(), new MySQLConstraintEditor(), - getDBTablePartitionEditor(connection)); - } - - private static DBTablePartitionEditor getDBTablePartitionEditor(Connection connection) { - String dbVersion = getDbVersion(connection); - if (VersionUtils.isLessThan(dbVersion, "2.2.77")) { - return new OBMySQLLessThan2277PartitionEditor(); - } else { - return new MySQLDBTablePartitionEditor(); - } - } } diff --git a/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleSchemaBrowserExtension.java b/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleSchemaBrowserExtension.java deleted file mode 100644 index b7f1ae27d1..0000000000 --- a/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleSchemaBrowserExtension.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2023 OceanBase. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.oceanbase.odc.plugin.schema.oboracle; - -import java.sql.Connection; - -import org.pf4j.Extension; - -import com.oceanbase.odc.plugin.schema.api.SchemaBrowserExtensionPoint; -import com.oceanbase.odc.plugin.schema.oboracle.utils.DBAccessorUtil; -import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; -import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; - -/** - * @author jingtian - * @date 2024/1/5 - * @since ODC_release_4.2.4 - */ -@Extension -public class OBOracleSchemaBrowserExtension implements SchemaBrowserExtensionPoint { - @Override - public DBSchemaAccessor getDBSchemaAccessor(Connection connection) { - return DBAccessorUtil.getSchemaAccessor(connection); - } - - @Override - public DBTableEditor getDBTableEditor(Connection connection) { - return DBAccessorUtil.getTableEditor(connection); - } -} diff --git a/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleTableExtension.java b/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleTableExtension.java index d543ec8342..0c2f379aa9 100644 --- a/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleTableExtension.java +++ b/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/OBOracleTableExtension.java @@ -28,6 +28,11 @@ import com.oceanbase.odc.plugin.schema.oboracle.parser.OBOracleGetDBTableByParser; import com.oceanbase.odc.plugin.schema.oboracle.utils.DBAccessorUtil; import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; +import com.oceanbase.tools.dbbrowser.editor.oracle.OBOracleIndexEditor; +import com.oceanbase.tools.dbbrowser.editor.oracle.OracleColumnEditor; +import com.oceanbase.tools.dbbrowser.editor.oracle.OracleConstraintEditor; +import com.oceanbase.tools.dbbrowser.editor.oracle.OracleDBTablePartitionEditor; +import com.oceanbase.tools.dbbrowser.editor.oracle.OracleTableEditor; import com.oceanbase.tools.dbbrowser.model.DBIndexType; import com.oceanbase.tools.dbbrowser.model.DBTable; import com.oceanbase.tools.dbbrowser.model.DBTable.DBTableOptions; @@ -139,6 +144,7 @@ protected DBStatsAccessor getStatsAccessor(Connection connection) { @Override protected DBTableEditor getTableEditor(Connection connection) { - return DBAccessorUtil.getTableEditor(connection); + return new OracleTableEditor(new OBOracleIndexEditor(), new OracleColumnEditor(), + new OracleConstraintEditor(), new OracleDBTablePartitionEditor()); } } diff --git a/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/utils/DBAccessorUtil.java b/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/utils/DBAccessorUtil.java index a4ecf840b8..c306310adc 100644 --- a/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/utils/DBAccessorUtil.java +++ b/server/plugins/schema-plugin-ob-oracle/src/main/java/com/oceanbase/odc/plugin/schema/oboracle/utils/DBAccessorUtil.java @@ -21,12 +21,6 @@ import com.oceanbase.odc.plugin.connect.oboracle.OBOracleInformationExtension; import com.oceanbase.odc.plugin.schema.oboracle.browser.DBSchemaAccessors; import com.oceanbase.odc.plugin.schema.oboracle.browser.DBStatsAccessors; -import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; -import com.oceanbase.tools.dbbrowser.editor.oracle.OBOracleIndexEditor; -import com.oceanbase.tools.dbbrowser.editor.oracle.OracleColumnEditor; -import com.oceanbase.tools.dbbrowser.editor.oracle.OracleConstraintEditor; -import com.oceanbase.tools.dbbrowser.editor.oracle.OracleDBTablePartitionEditor; -import com.oceanbase.tools.dbbrowser.editor.oracle.OracleTableEditor; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; import com.oceanbase.tools.dbbrowser.stats.DBStatsAccessor; @@ -48,9 +42,4 @@ public static DBStatsAccessor getStatsAccessor(Connection connection) { return DBStatsAccessors.create(JdbcOperationsUtil.getJdbcOperations(connection), getDbVersion(connection)); } - public static DBTableEditor getTableEditor(Connection connection) { - return new OracleTableEditor(new OBOracleIndexEditor(), new OracleColumnEditor(), - new OracleConstraintEditor(), new OracleDBTablePartitionEditor()); - } - } diff --git a/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLSchemaBrowserExtension.java b/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLSchemaBrowserExtension.java deleted file mode 100644 index 59e4428684..0000000000 --- a/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLSchemaBrowserExtension.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2023 OceanBase. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.oceanbase.odc.plugin.schema.odpsharding.obmysql; - -import java.sql.Connection; - -import org.pf4j.Extension; - -import com.oceanbase.odc.common.util.JdbcOperationsUtil; -import com.oceanbase.odc.plugin.schema.api.SchemaBrowserExtensionPoint; -import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLColumnEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLConstraintEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLDBTablePartitionEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLIndexEditor; -import com.oceanbase.tools.dbbrowser.editor.mysql.OBMySQLTableEditor; -import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; -import com.oceanbase.tools.dbbrowser.schema.mysql.ODPOBMySQLSchemaAccessor; - -/** - * @author jingtian - * @date 2024/1/5 - * @since ODC_release_4.2.4 - */ -@Extension -public class ODPShardingOBMySQLSchemaBrowserExtension implements SchemaBrowserExtensionPoint { - @Override - public DBSchemaAccessor getDBSchemaAccessor(Connection connection) { - return new ODPOBMySQLSchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); - } - - @Override - public DBTableEditor getDBTableEditor(Connection connection) { - return new OBMySQLTableEditor(new OBMySQLIndexEditor(), new MySQLColumnEditor(), new MySQLConstraintEditor(), - new MySQLDBTablePartitionEditor()); - } -} diff --git a/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLTableExtension.java b/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLTableExtension.java index 1131e52a79..2544583aa8 100644 --- a/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLTableExtension.java +++ b/server/plugins/schema-plugin-odp-sharding-ob-mysql/src/main/java/com/oceanbase/odc/plugin/schema/odpsharding/obmysql/ODPShardingOBMySQLTableExtension.java @@ -19,10 +19,13 @@ import org.pf4j.Extension; +import com.oceanbase.odc.common.util.JdbcOperationsUtil; import com.oceanbase.odc.plugin.schema.obmysql.OBMySQLTableExtension; -import com.oceanbase.tools.dbbrowser.editor.DBTableEditor; +import com.oceanbase.tools.dbbrowser.editor.DBTablePartitionEditor; +import com.oceanbase.tools.dbbrowser.editor.mysql.MySQLDBTablePartitionEditor; import com.oceanbase.tools.dbbrowser.model.DBTable; import com.oceanbase.tools.dbbrowser.schema.DBSchemaAccessor; +import com.oceanbase.tools.dbbrowser.schema.mysql.ODPOBMySQLSchemaAccessor; import com.oceanbase.tools.dbbrowser.stats.DBStatsAccessor; import com.oceanbase.tools.dbbrowser.stats.mysql.ODPOBMySQLStatsAccessor; @@ -48,7 +51,7 @@ public DBTable getDetail(@NonNull Connection connection, @NonNull String schemaN @Override protected DBSchemaAccessor getSchemaAccessor(Connection connection) { - return new ODPShardingOBMySQLSchemaBrowserExtension().getDBSchemaAccessor(connection); + return new ODPOBMySQLSchemaAccessor(JdbcOperationsUtil.getJdbcOperations(connection)); } @Override @@ -58,7 +61,7 @@ protected DBStatsAccessor getStatsAccessor(Connection consoleConnection) { } @Override - protected DBTableEditor getTableEditor(Connection connection) { - return new ODPShardingOBMySQLSchemaBrowserExtension().getDBTableEditor(connection); + protected DBTablePartitionEditor getDBTablePartitionEditor(Connection connection) { + return new MySQLDBTablePartitionEditor(); } } From 3c68c86b1078aec6c9780268c42ed9327db5ef88 Mon Sep 17 00:00:00 2001 From: jingtian Date: Tue, 9 Jan 2024 16:46:26 +0800 Subject: [PATCH 3/5] response to review --- ... => DefaultDBStructureComparatorTest.java} | 4 +-- ...java => DefaultDBStructureComparator.java} | 14 +++++---- .../TableStructureComparator.java | 30 +++++++++---------- .../model/DBStructureComparisonConfig.java | 3 ++ 4 files changed, 28 insertions(+), 23 deletions(-) rename server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/{OdcDBStructureComparatorTest.java => DefaultDBStructureComparatorTest.java} (99%) rename server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/{OdcDBStructureComparator.java => DefaultDBStructureComparator.java} (94%) diff --git a/server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparatorTest.java b/server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/DefaultDBStructureComparatorTest.java similarity index 99% rename from server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparatorTest.java rename to server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/DefaultDBStructureComparatorTest.java index 221caa5acc..46eafbba41 100644 --- a/server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparatorTest.java +++ b/server/integration-test/src/test/java/com/oceanbase/odc/service/structurecompare/DefaultDBStructureComparatorTest.java @@ -51,7 +51,7 @@ * @date 2024/1/8 * @since ODC_release_4.2.4 */ -public class OdcDBStructureComparatorTest extends PluginTestEnv { +public class DefaultDBStructureComparatorTest extends PluginTestEnv { private static final String BASE_PATH = "src/test/resources/structurecompare/"; private static String sourceSchemaDdl = FileUtil.loadAsString(BASE_PATH + "source_schema_ddl.sql"); private static String targetSchemaDdl = FileUtil.loadAsString(BASE_PATH + "target_schema_ddl.sql"); @@ -63,7 +63,7 @@ public class OdcDBStructureComparatorTest extends PluginTestEnv { private final static String targetSchemaName = generateSchemaName() + "_target"; private static TestDBConfiguration srcConfiguration = new TestDBConfiguration(); private static TestDBConfiguration tgtConfiguration = new TestDBConfiguration(); - private static OdcDBStructureComparator comparator = new OdcDBStructureComparator(); + private static DefaultDBStructureComparator comparator = new DefaultDBStructureComparator(); private static List results; @Rule public ExpectedException thrown = ExpectedException.none(); diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DefaultDBStructureComparator.java similarity index 94% rename from server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparator.java rename to server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DefaultDBStructureComparator.java index 671786e55d..b4a7730fca 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/OdcDBStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DefaultDBStructureComparator.java @@ -58,7 +58,7 @@ * @since ODC_release_4.2.4 */ @Slf4j -public class OdcDBStructureComparator implements DBStructureComparator { +public class DefaultDBStructureComparator implements DBStructureComparator { private final List supportedDialectTypes = Arrays.asList(DialectType.MYSQL, DialectType.OB_MYSQL, DialectType.OB_ORACLE); private final List supportedDBObjectTypes = Arrays.asList(DBObjectType.TABLE); @@ -80,9 +80,9 @@ public List compare(@NonNull DBStructureComparisonConf DBTableEditor tgtTableEditor = getDBTableEditor(tgtConfig.getConnectType(), tgtDbVersion); - Map srcTables = buildSchemaTables(srcAccessor, srcConfig.getSchemaName(), + Map srcTableName2Table = buildSchemaTables(srcAccessor, srcConfig.getSchemaName(), srcConfig.getConnectType().getDialectType(), srcDbVersion); - Map tgtTables = buildSchemaTables(tgtAccessor, tgtConfig.getSchemaName(), + Map tgtTableName2Table = buildSchemaTables(tgtAccessor, tgtConfig.getSchemaName(), tgtConfig.getConnectType().getDialectType(), tgtDbVersion); TableStructureComparator tableComparator = new TableStructureComparator(tgtTableEditor, @@ -94,14 +94,16 @@ public List compare(@NonNull DBStructureComparisonConf * Compare all the tables between source database and target database. */ returnVal = - tableComparator.compare(new ArrayList<>(srcTables.values()), new ArrayList<>(tgtTables.values())); + tableComparator.compare(new ArrayList<>(srcTableName2Table.values()), + new ArrayList<>(tgtTableName2Table.values())); } else { /** * Compare specified tables between source database and target database. */ for (String tableName : srcConfig.getBlackListMap().get(DBObjectType.TABLE)) { - if (srcTables.containsKey(tableName)) { - returnVal.add(tableComparator.compare(srcTables.get(tableName), tgtTables.get(tableName))); + if (srcTableName2Table.containsKey(tableName)) { + returnVal.add(tableComparator.compare(srcTableName2Table.get(tableName), + tgtTableName2Table.get(tableName))); } else { DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.TABLE, tableName, srcConfig.getSchemaName(), tgtConfig.getSchemaName()); diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java index c60170f7af..f01aaac52b 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java @@ -81,35 +81,35 @@ public List compare(List srcTables, List srcTableMapping = + Map srcTableName2Table = srcTables.stream().collect(Collectors.toMap(DBTable::getName, table -> table)); - Map tgtTableMapping = + Map tgtTableName2Table = tgtTables.stream().collect(Collectors.toMap(DBTable::getName, table -> table)); List toCreatedNames = new ArrayList<>(); List toComparedNames = new ArrayList<>(); List toDroppedNames = new ArrayList<>(); - for (String tableName : srcTableMapping.keySet()) { - if (!tgtTableMapping.containsKey(tableName)) { + for (String tableName : srcTableName2Table.keySet()) { + if (!tgtTableName2Table.containsKey(tableName)) { toCreatedNames.add(tableName); } else { toComparedNames.add(tableName); } } - for (String tableName : tgtTableMapping.keySet()) { - if (!srcTableMapping.containsKey(tableName)) { + for (String tableName : tgtTableName2Table.keySet()) { + if (!srcTableName2Table.containsKey(tableName)) { toDroppedNames.add(tableName); } } List createdResults = - buildCreatedTableResults(toCreatedNames, srcTableMapping, srcSchemaName, tgtSchemaName); + buildCreatedTableResults(toCreatedNames, srcTableName2Table, srcSchemaName, tgtSchemaName); List dropResults = - buildDroppedTableResults(toDroppedNames, tgtTableMapping, srcSchemaName, tgtSchemaName); + buildDroppedTableResults(toDroppedNames, tgtTableName2Table, srcSchemaName, tgtSchemaName); List comparedResults = new ArrayList<>(); toComparedNames.forEach(name -> { - comparedResults.add(compare(srcTableMapping.get(name), tgtTableMapping.get(name))); + comparedResults.add(compare(srcTableName2Table.get(name), tgtTableName2Table.get(name))); }); returnVal.addAll(createdResults); @@ -120,18 +120,18 @@ public List compare(List srcTables, List buildCreatedTableResults(List toCreate, - Map srcTableMapping, String srcSchemaName, String tgtSchemaName) { + Map srcTableName2Table, String srcSchemaName, String tgtSchemaName) { List returnVal = new LinkedList<>(); if (toCreate.isEmpty()) { return returnVal; } - toCreate = getTableNamesByDependencyOrder(toCreate, srcTableMapping, srcSchemaName); + toCreate = getTableNamesByDependencyOrder(toCreate, srcTableName2Table, srcSchemaName); toCreate.forEach(name -> { DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.TABLE, name, srcSchemaName, tgtSchemaName); result.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); - DBTable sourceTable = srcTableMapping.get(name); + DBTable sourceTable = srcTableName2Table.get(name); result.setSourceDdl(sourceTable.getDDL()); DBTable targetTable = new DBTable(); BeanUtils.copyProperties(sourceTable, targetTable); @@ -143,20 +143,20 @@ private List buildCreatedTableResults(List toC } private List buildDroppedTableResults(List toDrop, - Map tgtTableMapping, + Map tgtTableName2Table, String srcSchemaName, String tgtSchemaName) { List returnVal = new LinkedList<>(); if (toDrop.isEmpty()) { return returnVal; } - toDrop = getTableNamesByDependencyOrder(toDrop, tgtTableMapping, tgtSchemaName); + toDrop = getTableNamesByDependencyOrder(toDrop, tgtTableName2Table, tgtSchemaName); Collections.reverse(toDrop); toDrop.forEach(name -> { DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.TABLE, name, srcSchemaName, tgtSchemaName); result.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); - result.setTargetDdl(tgtTableMapping.get(name).getDDL()); + result.setTargetDdl(tgtTableName2Table.get(name).getDDL()); SqlBuilder sqlBuilder = getTargetDBSqlBuilder(); result.setChangeScript( GeneralSqlStatementBuilder.drop(sqlBuilder, DBObjectType.TABLE, tgtSchemaName, name)); diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBStructureComparisonConfig.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBStructureComparisonConfig.java index acf3791188..8c5a8676c7 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBStructureComparisonConfig.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/model/DBStructureComparisonConfig.java @@ -42,5 +42,8 @@ public class DBStructureComparisonConfig { private DataSource dataSource; @NotNull private Set toComparedObjectTypes; + /** + * Used to compare specified database objects [Optional] If null or empty, ignore + */ private Map> blackListMap = new HashMap<>(); } From 729f0e662708a0ed6f3448d7211a0927f88683d1 Mon Sep 17 00:00:00 2001 From: jingtian Date: Tue, 9 Jan 2024 20:01:32 +0800 Subject: [PATCH 4/5] add AbstractDBObjectStructureComparator --- .../AbstractDBObjectStructureComparator.java | 90 +++++++++++++++++++ .../TableConstraintStructureComparator.java | 76 +++------------- .../TableIndexStructureComparator.java | 90 ++++--------------- .../TableStructureComparator.java | 71 ++++++++------- 4 files changed, 157 insertions(+), 170 deletions(-) create mode 100644 server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/AbstractDBObjectStructureComparator.java diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/AbstractDBObjectStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/AbstractDBObjectStructureComparator.java new file mode 100644 index 0000000000..f1148e2a35 --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/AbstractDBObjectStructureComparator.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.service.structurecompare.comparedbobject; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.tools.dbbrowser.model.DBObject; + +/** + * @author jingtian + * @date 2024/1/9 + * @since ODC_release_4.2.4 + */ +public abstract class AbstractDBObjectStructureComparator + implements DBObjectStructureComparator { + protected final String srcSchemaName; + protected final String tgtSchemaName; + + public AbstractDBObjectStructureComparator(String srcSchemaName, String tgtSchemaName) { + this.srcSchemaName = srcSchemaName; + this.tgtSchemaName = tgtSchemaName; + } + + @Override + public List compare(List sourceObjects, List targetObjects) { + List returnVal = new ArrayList<>(); + if (sourceObjects.isEmpty() && targetObjects.isEmpty()) { + return returnVal; + } else if (sourceObjects.isEmpty()) { + // database objects to be dropped + targetObjects.forEach(object -> { + returnVal.add(buildOnlyInTargetResult(object, this.srcSchemaName)); + }); + return returnVal; + } else if (targetObjects.isEmpty()) { + // database objects to be created + sourceObjects.forEach(object -> { + returnVal.add(buildOnlyInSourceResult(object, this.tgtSchemaName)); + }); + return returnVal; + } + + List srcObjectNames = sourceObjects.stream().map(DBObject::name).collect(Collectors.toList()); + List tgtObjectNames = targetObjects.stream().map(DBObject::name).collect(Collectors.toList()); + Map srcObjectName2Object = + sourceObjects.stream().collect(Collectors.toMap(DBObject::name, object -> object)); + Map tgtObjectName2Object = + targetObjects.stream().collect(Collectors.toMap(DBObject::name, object -> object)); + + tgtObjectNames.forEach(tgtObjectName -> { + if (!srcObjectNames.contains(tgtObjectName)) { + // database object to be dropped + returnVal.add(buildOnlyInTargetResult(tgtObjectName2Object.get(tgtObjectName), this.srcSchemaName)); + } else { + // database object to be compared + returnVal.add(compare(srcObjectName2Object.get(tgtObjectName), tgtObjectName2Object.get(tgtObjectName))); + } + }); + + srcObjectNames.forEach(srcObjectName -> { + if (!tgtObjectNames.contains(srcObjectName)) { + // database object to be created + returnVal.add(buildOnlyInSourceResult(srcObjectName2Object.get(srcObjectName), this.tgtSchemaName)); + } + }); + + return returnVal; + } + + protected abstract DBObjectComparisonResult buildOnlyInTargetResult(T tgtDbObject, String srcSchemaName); + + protected abstract DBObjectComparisonResult buildOnlyInSourceResult(T srcDbObject, String tgtSchemaName); +} diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableConstraintStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableConstraintStructureComparator.java index 451d51b409..a1528406e0 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableConstraintStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableConstraintStructureComparator.java @@ -15,11 +15,6 @@ */ package com.oceanbase.odc.service.structurecompare.comparedbobject; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import org.springframework.beans.BeanUtils; import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; @@ -36,81 +31,32 @@ * @date 2024/1/4 * @since ODC_release_4.2.4 */ -public class TableConstraintStructureComparator implements DBObjectStructureComparator { +public class TableConstraintStructureComparator extends AbstractDBObjectStructureComparator { private DBTableConstraintEditor tgtConstraintEditor; - private String srcSchemaName; - private String tgtSchemaName; public TableConstraintStructureComparator(DBTableConstraintEditor tgtConstraintEditor, String srcSchemaName, String tgtSchemaName) { + super(srcSchemaName, tgtSchemaName); this.tgtConstraintEditor = tgtConstraintEditor; - this.srcSchemaName = srcSchemaName; - this.tgtSchemaName = tgtSchemaName; } @Override - public List compare(List srcTabCons, - List tgtTabCons) { - List returnVal = new ArrayList<>(); - if (srcTabCons.isEmpty() && tgtTabCons.isEmpty()) { - return returnVal; - } else if (srcTabCons.isEmpty()) { - // constraints to be dropped - tgtTabCons.forEach(cons -> { - returnVal.add(buildDropConstraintResult(cons, this.srcSchemaName)); - }); - return returnVal; - } else if (tgtTabCons.isEmpty()) { - // constraints to be created - srcTabCons.forEach(cons -> { - returnVal.add(buildCreateConstraintResult(cons, this.tgtSchemaName)); - }); - return returnVal; - } - - List srcConsNames = srcTabCons.stream().map(DBTableConstraint::getName).collect(Collectors.toList()); - List tgtConsNames = tgtTabCons.stream().map(DBTableConstraint::getName).collect(Collectors.toList()); - Map srcConsMapping = - srcTabCons.stream().collect(Collectors.toMap(DBTableConstraint::getName, col -> col)); - Map tarConsMapping = - tgtTabCons.stream().collect(Collectors.toMap(DBTableConstraint::getName, col -> col)); - - tgtConsNames.forEach(tgtConsName -> { - if (!srcConsNames.contains(tgtConsName)) { - // constraint to be dropped - returnVal.add(buildDropConstraintResult(tarConsMapping.get(tgtConsName), this.srcSchemaName)); - } else { - // constraint to be compared - returnVal.add(compare(srcConsMapping.get(tgtConsName), tarConsMapping.get(tgtConsName))); - } - }); - - srcConsNames.forEach(srcConsName -> { - if (!tgtConsNames.contains(srcConsName)) { - // constraint to be created - returnVal.add(buildCreateConstraintResult(srcConsMapping.get(srcConsName), this.tgtSchemaName)); - } - }); - - return returnVal; - } - - private DBObjectComparisonResult buildDropConstraintResult(DBTableConstraint tgtCons, String srcSchemaName) { - DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.CONSTRAINT, tgtCons.getName(), - srcSchemaName, tgtCons.getSchemaName()); + protected DBObjectComparisonResult buildOnlyInTargetResult(DBTableConstraint tgtDbObject, String srcSchemaName) { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.CONSTRAINT, tgtDbObject.getName(), + srcSchemaName, tgtDbObject.getSchemaName()); result.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); result.setChangeScript(appendDelimiterIfNotExist( - this.tgtConstraintEditor.generateDropObjectDDL(tgtCons))); + this.tgtConstraintEditor.generateDropObjectDDL(tgtDbObject))); return result; } - private DBObjectComparisonResult buildCreateConstraintResult(DBTableConstraint srcConstraint, - String tgtSchemaName) { - DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.CONSTRAINT, srcConstraint.getName(), - srcConstraint.getSchemaName(), tgtSchemaName); + @Override + protected DBObjectComparisonResult buildOnlyInSourceResult(DBTableConstraint srcDbObject, String tgtSchemaName) { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.CONSTRAINT, srcDbObject.getName(), + srcDbObject.getSchemaName(), tgtSchemaName); result.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); - DBTableConstraint copiedSrcCons = copySrcConstraintWithTgtSchemaName(srcConstraint, tgtSchemaName); + DBTableConstraint copiedSrcCons = copySrcConstraintWithTgtSchemaName(srcDbObject, tgtSchemaName); if (copiedSrcCons.getType().equals(DBConstraintType.FOREIGN_KEY)) { copiedSrcCons.setReferenceSchemaName(tgtSchemaName); } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableIndexStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableIndexStructureComparator.java index f696a2f525..176f9e3c81 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableIndexStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableIndexStructureComparator.java @@ -15,11 +15,6 @@ */ package com.oceanbase.odc.service.structurecompare.comparedbobject; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import org.springframework.beans.BeanUtils; import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; @@ -35,63 +30,35 @@ * @date 2024/1/4 * @since ODC_release_4.2.4 */ -public class TableIndexStructureComparator implements DBObjectStructureComparator { +public class TableIndexStructureComparator extends AbstractDBObjectStructureComparator { private DBTableIndexEditor targetTableIndexEditor; - private String srcSchemaName; - private String tgtSchemaName; public TableIndexStructureComparator(DBTableIndexEditor targetTableIndexEditor, String srcSchemaName, String tgtSchemaName) { + super(srcSchemaName, tgtSchemaName); this.targetTableIndexEditor = targetTableIndexEditor; - this.srcSchemaName = srcSchemaName; - this.tgtSchemaName = tgtSchemaName; } @Override - public List compare(List srcIndexes, List tgtIndexes) { - List returnVal = new ArrayList<>(); - if (srcIndexes.isEmpty() && tgtIndexes.isEmpty()) { - return returnVal; - } else if (srcIndexes.isEmpty()) { - // indexes to be dropped - tgtIndexes.forEach(idx -> { - returnVal.add(buildDropIndexResult(idx, this.srcSchemaName)); - }); - return returnVal; - } else if (tgtIndexes.isEmpty()) { - // indexes to be created - srcIndexes.forEach(idx -> { - returnVal.add(buildCreateIndexResult(idx, this.tgtSchemaName)); - }); - return returnVal; - } - - List srcIdxNames = srcIndexes.stream().map(DBTableIndex::getName).collect(Collectors.toList()); - List tgtIdxNames = tgtIndexes.stream().map(DBTableIndex::getName).collect(Collectors.toList()); - Map srcIdxMapping = - srcIndexes.stream().collect(Collectors.toMap(DBTableIndex::getName, col -> col)); - Map tgtIdxMapping = - tgtIndexes.stream().collect(Collectors.toMap(DBTableIndex::getName, col -> col)); - - tgtIdxNames.forEach(tgtIdxName -> { - if (!srcIdxNames.contains(tgtIdxName)) { - // index to be dropped - returnVal.add(buildDropIndexResult(tgtIdxMapping.get(tgtIdxName), this.srcSchemaName)); - } else { - // index to be compared - returnVal.add(compare(srcIdxMapping.get(tgtIdxName), tgtIdxMapping.get(tgtIdxName))); - } - }); - - srcIdxNames.forEach(srcIdxName -> { - if (!tgtIdxNames.contains(srcIdxName)) { - // index to be created - returnVal.add(buildCreateIndexResult(srcIdxMapping.get(srcIdxName), this.tgtSchemaName)); - } - }); + protected DBObjectComparisonResult buildOnlyInTargetResult(DBTableIndex tgtDbObject, String srcSchemaName) { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.INDEX, tgtDbObject.getName(), + srcSchemaName, tgtDbObject.getSchemaName()); + result.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); + result.setChangeScript(appendDelimiterIfNotExist( + targetTableIndexEditor.generateDropObjectDDL(tgtDbObject))); + return result; + } - return returnVal; + @Override + protected DBObjectComparisonResult buildOnlyInSourceResult(DBTableIndex srcDbObject, String tgtSchemaName) { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.INDEX, srcDbObject.getName(), + srcDbObject.getSchemaName(), tgtSchemaName); + result.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); + result.setChangeScript(appendDelimiterIfNotExist( + targetTableIndexEditor + .generateCreateObjectDDL(copySrcIndexWithTgtSchemaName(srcDbObject, tgtSchemaName)))); + return result; } @Override @@ -112,25 +79,6 @@ public DBObjectComparisonResult compare(@NonNull DBTableIndex srcIndex, @NonNull return result; } - private DBObjectComparisonResult buildCreateIndexResult(DBTableIndex srcIndex, String tgtSchemaName) { - DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.INDEX, srcIndex.getName(), - srcIndex.getSchemaName(), tgtSchemaName); - result.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); - result.setChangeScript(appendDelimiterIfNotExist( - targetTableIndexEditor - .generateCreateObjectDDL(copySrcIndexWithTgtSchemaName(srcIndex, tgtSchemaName)))); - return result; - } - - private DBObjectComparisonResult buildDropIndexResult(DBTableIndex tgtIndex, String srcSchemaName) { - DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.INDEX, tgtIndex.getName(), - srcSchemaName, tgtIndex.getSchemaName()); - result.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); - result.setChangeScript(appendDelimiterIfNotExist( - targetTableIndexEditor.generateDropObjectDDL(tgtIndex))); - return result; - } - private DBTableIndex copySrcIndexWithTgtSchemaName(DBTableIndex srcIndex, String tgtSchemaName) { DBTableIndex copiedSrcIdx = new DBTableIndex(); BeanUtils.copyProperties(srcIndex, copiedSrcIdx); diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java index f01aaac52b..e2f88b4dcf 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java @@ -216,10 +216,7 @@ public DBObjectComparisonResult compare(DBTable sourceTable, DBTable targetTable } DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.TABLE, sourceTable.getName(), - sourceTable.getSchemaName(), targetTable.getSchemaName()); - - String srcSchemaName = sourceTable.getSchemaName(); - String tgtSchemaName = targetTable.getSchemaName(); + this.srcSchemaName, this.tgtSchemaName); // compare table options SqlBuilder tableOptionDdl = getTargetDBSqlBuilder(); @@ -231,36 +228,10 @@ public DBObjectComparisonResult compare(DBTable sourceTable, DBTable targetTable result.setSourceDdl(sourceTable.getDDL()); result.setTargetDdl(targetTable.getDDL()); - // compare table columns - List columns = - new TableColumnStructureComparator( - (DBTableColumnEditor) this.tgtTableEditor.getColumnEditor(), srcSchemaName, tgtSchemaName) - .compare(sourceTable.getColumns(), targetTable.getColumns()); - - // compare table index - List indexes = - new TableIndexStructureComparator((DBTableIndexEditor) this.tgtTableEditor.getIndexEditor(), - srcSchemaName, tgtSchemaName) - .compare( - this.tgtTableEditor.excludePrimaryKeyIndex(sourceTable.getIndexes(), - sourceTable.getConstraints()), - this.tgtTableEditor.excludePrimaryKeyIndex(targetTable.getIndexes(), - targetTable.getConstraints())); - - // compare table constraints - List constraints = new TableConstraintStructureComparator( - (DBTableConstraintEditor) this.tgtTableEditor.getConstraintEditor(), srcSchemaName, tgtSchemaName) - .compare( - this.tgtTableEditor.excludeUniqueConstraint(sourceTable.getIndexes(), - sourceTable.getConstraints()), - this.tgtTableEditor.excludeUniqueConstraint(targetTable.getIndexes(), - targetTable.getConstraints())); - - // compare table partition - DBObjectComparisonResult partition = - new TablePartitionStructureComparator((DBTablePartitionEditor) this.tgtTableEditor.getPartitionEditor(), - srcSchemaName, tgtSchemaName) - .compare(sourceTable.getPartition(), targetTable.getPartition()); + List columns = compareTableColumns(sourceTable, targetTable); + List indexes = compareTableIndexes(sourceTable, targetTable); + List constraints = compareTableConstraints(sourceTable, targetTable); + DBObjectComparisonResult partition = compareTablePartition(sourceTable, targetTable); if (columns.stream().allMatch(item -> item.getComparisonResult().equals(ComparisonResult.CONSISTENT)) && indexes.stream().allMatch(item -> item.getComparisonResult().equals(ComparisonResult.CONSISTENT)) @@ -279,4 +250,36 @@ public DBObjectComparisonResult compare(DBTable sourceTable, DBTable targetTable return result; } + + private List compareTableColumns(DBTable srcTable, DBTable tgtTable) { + return new TableColumnStructureComparator( + (DBTableColumnEditor) this.tgtTableEditor.getColumnEditor(), srcSchemaName, tgtSchemaName) + .compare(srcTable.getColumns(), tgtTable.getColumns()); + } + + private List compareTableIndexes(DBTable srcTable, DBTable tgtTable) { + return new TableIndexStructureComparator((DBTableIndexEditor) this.tgtTableEditor.getIndexEditor(), + srcSchemaName, tgtSchemaName) + .compare( + this.tgtTableEditor.excludePrimaryKeyIndex(srcTable.getIndexes(), + srcTable.getConstraints()), + this.tgtTableEditor.excludePrimaryKeyIndex(tgtTable.getIndexes(), + tgtTable.getConstraints())); + } + + private List compareTableConstraints(DBTable srcTable, DBTable tgtTable) { + return new TableConstraintStructureComparator( + (DBTableConstraintEditor) this.tgtTableEditor.getConstraintEditor(), srcSchemaName, tgtSchemaName) + .compare( + this.tgtTableEditor.excludeUniqueConstraint(srcTable.getIndexes(), + srcTable.getConstraints()), + this.tgtTableEditor.excludeUniqueConstraint(tgtTable.getIndexes(), + tgtTable.getConstraints())); + } + + private DBObjectComparisonResult compareTablePartition(DBTable srcTable, DBTable tgtTable) { + return new TablePartitionStructureComparator((DBTablePartitionEditor) this.tgtTableEditor.getPartitionEditor(), + srcSchemaName, tgtSchemaName) + .compare(srcTable.getPartition(), tgtTable.getPartition()); + } } From 25122c305c29766b6251cb72e3ff12216847923a Mon Sep 17 00:00:00 2001 From: jingtian Date: Tue, 9 Jan 2024 21:10:39 +0800 Subject: [PATCH 5/5] response to review --- server/odc-service/pom.xml | 5 -- .../odc/service/plugin/SchemaPluginUtil.java | 1 - .../DBStructureComparator.java | 3 +- .../DefaultDBStructureComparator.java | 24 +++----- .../AbstractDBObjectStructureComparator.java | 3 +- .../DBObjectStructureComparator.java | 10 ---- ... => DBTableColumnStructureComparator.java} | 57 +++++++++++-------- ...DBTableConstraintStructureComparator.java} | 16 +++--- ...a => DBTableIndexStructureComparator.java} | 16 +++--- ... DBTablePartitionStructureComparator.java} | 12 ++-- ...r.java => DBTableStructureComparator.java} | 29 +++++----- .../util/StructureCompareUtil.java | 33 +++++++++++ 12 files changed, 114 insertions(+), 95 deletions(-) rename server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/{TableColumnStructureComparator.java => DBTableColumnStructureComparator.java} (64%) rename server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/{TableConstraintStructureComparator.java => DBTableConstraintStructureComparator.java} (83%) rename server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/{TableIndexStructureComparator.java => DBTableIndexStructureComparator.java} (81%) rename server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/{TablePartitionStructureComparator.java => DBTablePartitionStructureComparator.java} (86%) rename server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/{TableStructureComparator.java => DBTableStructureComparator.java} (90%) create mode 100644 server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/util/StructureCompareUtil.java diff --git a/server/odc-service/pom.xml b/server/odc-service/pom.xml index 00c4169b1b..6b3af705d9 100644 --- a/server/odc-service/pom.xml +++ b/server/odc-service/pom.xml @@ -46,10 +46,6 @@ 5.6.0 runtime - - com.oceanbase - schema-plugin-ob-mysql - @@ -268,7 +264,6 @@ com.oceanbase schema-plugin-ob-mysql - ${project.version} diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/plugin/SchemaPluginUtil.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/plugin/SchemaPluginUtil.java index 784f436791..e1045cfd65 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/plugin/SchemaPluginUtil.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/plugin/SchemaPluginUtil.java @@ -82,7 +82,6 @@ public static TypeExtensionPoint getTypeExtension(DialectType dialectType) { return getSingletonExtension(dialectType, TypeExtensionPoint.class); } - public static T getSingletonExtension(DialectType dialectType, Class type) { return getOdcPluginManager().getSingletonExtension(dialectType, type); } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DBStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DBStructureComparator.java index c2e229b70c..dd1d7e32bf 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DBStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DBStructureComparator.java @@ -35,6 +35,5 @@ public interface DBStructureComparator { * @return {@link DBObjectComparisonResult} */ List compare(DBStructureComparisonConfig srcConfig, - DBStructureComparisonConfig destConfig) - throws SQLException; + DBStructureComparisonConfig destConfig) throws SQLException; } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DefaultDBStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DefaultDBStructureComparator.java index b4a7730fca..ed4d4c6e27 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DefaultDBStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/DefaultDBStructureComparator.java @@ -30,13 +30,11 @@ import com.oceanbase.odc.common.util.VersionUtils; import com.oceanbase.odc.core.shared.constant.ConnectType; import com.oceanbase.odc.core.shared.constant.DialectType; -import com.oceanbase.odc.plugin.connect.api.InformationExtensionPoint; import com.oceanbase.odc.plugin.schema.obmysql.parser.OBMySQLGetDBTableByParser; -import com.oceanbase.odc.service.db.browser.DBObjectEditorFactory; import com.oceanbase.odc.service.db.browser.DBSchemaAccessors; import com.oceanbase.odc.service.db.browser.DBTableEditorFactory; import com.oceanbase.odc.service.plugin.ConnectionPluginUtil; -import com.oceanbase.odc.service.structurecompare.comparedbobject.TableStructureComparator; +import com.oceanbase.odc.service.structurecompare.comparedbobject.DBTableStructureComparator; import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; import com.oceanbase.odc.service.structurecompare.model.DBStructureComparisonConfig; @@ -65,10 +63,9 @@ public class DefaultDBStructureComparator implements DBStructureComparator { @Override public List compare(@NonNull DBStructureComparisonConfig srcConfig, - @NonNull DBStructureComparisonConfig tgtConfig) - throws SQLException { + @NonNull DBStructureComparisonConfig tgtConfig) throws SQLException { List returnVal = new ArrayList<>(); - checkConfig(srcConfig, tgtConfig); + checkUnsupportedConfiguration(srcConfig, tgtConfig); String srcDbVersion = getDBVersion(srcConfig.getConnectType(), srcConfig.getDataSource()); String tgtDbVersion = getDBVersion(tgtConfig.getConnectType(), tgtConfig.getDataSource()); @@ -85,7 +82,7 @@ public List compare(@NonNull DBStructureComparisonConf Map tgtTableName2Table = buildSchemaTables(tgtAccessor, tgtConfig.getSchemaName(), tgtConfig.getConnectType().getDialectType(), tgtDbVersion); - TableStructureComparator tableComparator = new TableStructureComparator(tgtTableEditor, + DBTableStructureComparator tableComparator = new DBTableStructureComparator(tgtTableEditor, tgtConfig.getConnectType().getDialectType(), srcConfig.getSchemaName(), tgtConfig.getSchemaName()); @@ -127,19 +124,16 @@ private DBSchemaAccessor getDBSchemaAccessor(ConnectType connectType, DataSource } private DBTableEditor getDBTableEditor(ConnectType connectType, String dbVersion) { - DBObjectEditorFactory tableEditorFactory = - new DBTableEditorFactory(connectType, dbVersion); - return tableEditorFactory.create(); + return new DBTableEditorFactory(connectType, dbVersion).create(); } private String getDBVersion(ConnectType connectType, DataSource dataSource) throws SQLException { - InformationExtensionPoint informationExtension = ConnectionPluginUtil.getInformationExtension( - connectType.getDialectType()); - return informationExtension.getDBVersion(dataSource.getConnection()); - + return ConnectionPluginUtil.getInformationExtension(connectType.getDialectType()) + .getDBVersion(dataSource.getConnection()); } - private void checkConfig(DBStructureComparisonConfig srcConfig, DBStructureComparisonConfig tgtConfig) { + private void checkUnsupportedConfiguration(DBStructureComparisonConfig srcConfig, + DBStructureComparisonConfig tgtConfig) { if (!srcConfig.getConnectType().getDialectType().equals(tgtConfig.getConnectType().getDialectType())) { throw new IllegalArgumentException("The dialect type of source and target schema must be equal"); } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/AbstractDBObjectStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/AbstractDBObjectStructureComparator.java index f1148e2a35..78ec8b4b57 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/AbstractDBObjectStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/AbstractDBObjectStructureComparator.java @@ -70,7 +70,8 @@ public List compare(List sourceObjects, List tar returnVal.add(buildOnlyInTargetResult(tgtObjectName2Object.get(tgtObjectName), this.srcSchemaName)); } else { // database object to be compared - returnVal.add(compare(srcObjectName2Object.get(tgtObjectName), tgtObjectName2Object.get(tgtObjectName))); + returnVal + .add(compare(srcObjectName2Object.get(tgtObjectName), tgtObjectName2Object.get(tgtObjectName))); } }); diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBObjectStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBObjectStructureComparator.java index cd53fef8d4..22a1552f17 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBObjectStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBObjectStructureComparator.java @@ -26,8 +26,6 @@ * @since ODC_release_4.2.4 */ public interface DBObjectStructureComparator { - String DEFAULT_SQL_DELIMITER = ";"; - /** * Compare specified database object types between two schema. * @@ -46,12 +44,4 @@ public interface DBObjectStructureComparator { * @return {@link DBObjectComparisonResult} */ DBObjectComparisonResult compare(T sourceObject, T targetObject); - - default String appendDelimiterIfNotExist(String sql) { - String returnVal = sql.trim(); - if (!returnVal.endsWith(DEFAULT_SQL_DELIMITER)) { - return returnVal + DEFAULT_SQL_DELIMITER + "\n"; - } - return sql; - } } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableColumnStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTableColumnStructureComparator.java similarity index 64% rename from server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableColumnStructureComparator.java rename to server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTableColumnStructureComparator.java index 530f1fc66e..6c2235cb95 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableColumnStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTableColumnStructureComparator.java @@ -26,6 +26,7 @@ import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.odc.service.structurecompare.util.StructureCompareUtil; import com.oceanbase.tools.dbbrowser.editor.DBTableColumnEditor; import com.oceanbase.tools.dbbrowser.model.DBObjectType; import com.oceanbase.tools.dbbrowser.model.DBTableColumn; @@ -37,16 +38,13 @@ * @date 2024/1/4 * @since ODC_release_4.2.4 */ -public class TableColumnStructureComparator implements DBObjectStructureComparator { +public class DBTableColumnStructureComparator extends AbstractDBObjectStructureComparator { private DBTableColumnEditor tgtColumnEditor; - private String srcSchemaName; - private String tgtSchemaName; - public TableColumnStructureComparator(DBTableColumnEditor tgtColumnEditor, String srcSchemaName, + public DBTableColumnStructureComparator(DBTableColumnEditor tgtColumnEditor, String srcSchemaName, String tgtSchemaName) { + super(srcSchemaName, tgtSchemaName); this.tgtColumnEditor = tgtColumnEditor; - this.srcSchemaName = srcSchemaName; - this.tgtSchemaName = tgtSchemaName; } @Override @@ -58,44 +56,53 @@ public List compare(@NotEmpty List srcT String tgtSchemaName = tgtTabCols.get(0).getSchemaName(); List srcColNames = srcTabCols.stream().map(DBTableColumn::getName).collect(Collectors.toList()); List tgtColNames = tgtTabCols.stream().map(DBTableColumn::getName).collect(Collectors.toList()); - Map srcColMapping = + Map srcColumnName2Column = srcTabCols.stream().collect(Collectors.toMap(DBTableColumn::getName, col -> col)); - Map tgtColMapping = + Map tgtColumnName2Column = tgtTabCols.stream().collect(Collectors.toMap(DBTableColumn::getName, col -> col)); tgtColNames.forEach(tarColName -> { if (!srcColNames.contains(tarColName)) { // column to be dropped - DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.COLUMN, tarColName, - srcSchemaName, tgtSchemaName); - result.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); - result.setChangeScript( - appendDelimiterIfNotExist(this.tgtColumnEditor - .generateDropObjectDDL(tgtColMapping.get(tarColName)))); - returnVal.add(result); + returnVal.add(buildOnlyInTargetResult(tgtColumnName2Column.get(tarColName), srcSchemaName)); } }); srcColNames.forEach(srcColName -> { - DBTableColumn copiedSrcCol = copySrcColumnWithTgtSchemaName(srcColMapping.get(srcColName), tgtSchemaName); - if (tgtColNames.contains(srcColName)) { // column to be compared - returnVal.add(compare(srcColMapping.get(srcColName), tgtColMapping.get(srcColName))); + returnVal.add(compare(srcColumnName2Column.get(srcColName), tgtColumnName2Column.get(srcColName))); } else { // column to be created - DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.COLUMN, srcColName, - srcSchemaName, tgtSchemaName); - result.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); - result.setChangeScript(appendDelimiterIfNotExist( - tgtColumnEditor.generateCreateObjectDDL(copiedSrcCol))); - returnVal.add(result); + returnVal.add(buildOnlyInSourceResult(srcColumnName2Column.get(srcColName), tgtSchemaName)); } }); return returnVal; } + @Override + protected DBObjectComparisonResult buildOnlyInTargetResult(DBTableColumn tgtDbObject, String srcSchemaName) { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.COLUMN, tgtDbObject.getName(), + srcSchemaName, tgtSchemaName); + result.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); + result.setChangeScript( + StructureCompareUtil.appendDelimiterIfNotExist( + this.tgtColumnEditor.generateDropObjectDDL(tgtDbObject))); + return result; + } + + @Override + protected DBObjectComparisonResult buildOnlyInSourceResult(DBTableColumn srcDbObject, String tgtSchemaName) { + DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.COLUMN, srcDbObject.getName(), + srcSchemaName, tgtSchemaName); + result.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); + result.setChangeScript(StructureCompareUtil + .appendDelimiterIfNotExist(tgtColumnEditor + .generateCreateObjectDDL(copySrcColumnWithTgtSchemaName(srcDbObject, tgtSchemaName)))); + return result; + } + @Override public DBObjectComparisonResult compare(@NonNull DBTableColumn srcTabCol, @NonNull DBTableColumn tgtTabCol) { DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.COLUMN, srcTabCol.getName(), @@ -108,7 +115,7 @@ public DBObjectComparisonResult compare(@NonNull DBTableColumn srcTabCol, @NonNu if (!ddl.isEmpty()) { // column to be updated result.setComparisonResult(ComparisonResult.INCONSISTENT); - result.setChangeScript(appendDelimiterIfNotExist(ddl)); + result.setChangeScript(StructureCompareUtil.appendDelimiterIfNotExist(ddl)); } else { result.setComparisonResult(ComparisonResult.CONSISTENT); } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableConstraintStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTableConstraintStructureComparator.java similarity index 83% rename from server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableConstraintStructureComparator.java rename to server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTableConstraintStructureComparator.java index a1528406e0..a6af7a1bae 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableConstraintStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTableConstraintStructureComparator.java @@ -19,6 +19,7 @@ import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.odc.service.structurecompare.util.StructureCompareUtil; import com.oceanbase.tools.dbbrowser.editor.DBTableConstraintEditor; import com.oceanbase.tools.dbbrowser.model.DBConstraintType; import com.oceanbase.tools.dbbrowser.model.DBObjectType; @@ -31,10 +32,10 @@ * @date 2024/1/4 * @since ODC_release_4.2.4 */ -public class TableConstraintStructureComparator extends AbstractDBObjectStructureComparator { +public class DBTableConstraintStructureComparator extends AbstractDBObjectStructureComparator { private DBTableConstraintEditor tgtConstraintEditor; - public TableConstraintStructureComparator(DBTableConstraintEditor tgtConstraintEditor, String srcSchemaName, + public DBTableConstraintStructureComparator(DBTableConstraintEditor tgtConstraintEditor, String srcSchemaName, String tgtSchemaName) { super(srcSchemaName, tgtSchemaName); this.tgtConstraintEditor = tgtConstraintEditor; @@ -45,8 +46,8 @@ protected DBObjectComparisonResult buildOnlyInTargetResult(DBTableConstraint tgt DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.CONSTRAINT, tgtDbObject.getName(), srcSchemaName, tgtDbObject.getSchemaName()); result.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); - result.setChangeScript(appendDelimiterIfNotExist( - this.tgtConstraintEditor.generateDropObjectDDL(tgtDbObject))); + result.setChangeScript(StructureCompareUtil + .appendDelimiterIfNotExist(this.tgtConstraintEditor.generateDropObjectDDL(tgtDbObject))); return result; } @@ -60,9 +61,8 @@ protected DBObjectComparisonResult buildOnlyInSourceResult(DBTableConstraint src if (copiedSrcCons.getType().equals(DBConstraintType.FOREIGN_KEY)) { copiedSrcCons.setReferenceSchemaName(tgtSchemaName); } - result.setChangeScript(appendDelimiterIfNotExist( - this.tgtConstraintEditor - .generateCreateObjectDDL(copiedSrcCons))); + result.setChangeScript(StructureCompareUtil.appendDelimiterIfNotExist( + this.tgtConstraintEditor.generateCreateObjectDDL(copiedSrcCons))); return result; } @@ -86,7 +86,7 @@ public DBObjectComparisonResult compare(@NonNull DBTableConstraint srcConstraint if (!ddl.isEmpty()) { // constraint to be updated result.setComparisonResult(ComparisonResult.INCONSISTENT); - result.setChangeScript(appendDelimiterIfNotExist(ddl)); + result.setChangeScript(StructureCompareUtil.appendDelimiterIfNotExist(ddl)); } else { result.setComparisonResult(ComparisonResult.CONSISTENT); } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableIndexStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTableIndexStructureComparator.java similarity index 81% rename from server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableIndexStructureComparator.java rename to server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTableIndexStructureComparator.java index 176f9e3c81..4c51d326e7 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableIndexStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTableIndexStructureComparator.java @@ -19,6 +19,7 @@ import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.odc.service.structurecompare.util.StructureCompareUtil; import com.oceanbase.tools.dbbrowser.editor.DBTableIndexEditor; import com.oceanbase.tools.dbbrowser.model.DBObjectType; import com.oceanbase.tools.dbbrowser.model.DBTableIndex; @@ -30,11 +31,11 @@ * @date 2024/1/4 * @since ODC_release_4.2.4 */ -public class TableIndexStructureComparator extends AbstractDBObjectStructureComparator { +public class DBTableIndexStructureComparator extends AbstractDBObjectStructureComparator { private DBTableIndexEditor targetTableIndexEditor; - public TableIndexStructureComparator(DBTableIndexEditor targetTableIndexEditor, String srcSchemaName, + public DBTableIndexStructureComparator(DBTableIndexEditor targetTableIndexEditor, String srcSchemaName, String tgtSchemaName) { super(srcSchemaName, tgtSchemaName); this.targetTableIndexEditor = targetTableIndexEditor; @@ -45,8 +46,8 @@ protected DBObjectComparisonResult buildOnlyInTargetResult(DBTableIndex tgtDbObj DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.INDEX, tgtDbObject.getName(), srcSchemaName, tgtDbObject.getSchemaName()); result.setComparisonResult(ComparisonResult.ONLY_IN_TARGET); - result.setChangeScript(appendDelimiterIfNotExist( - targetTableIndexEditor.generateDropObjectDDL(tgtDbObject))); + result.setChangeScript(StructureCompareUtil + .appendDelimiterIfNotExist(targetTableIndexEditor.generateDropObjectDDL(tgtDbObject))); return result; } @@ -55,9 +56,8 @@ protected DBObjectComparisonResult buildOnlyInSourceResult(DBTableIndex srcDbObj DBObjectComparisonResult result = new DBObjectComparisonResult(DBObjectType.INDEX, srcDbObject.getName(), srcDbObject.getSchemaName(), tgtSchemaName); result.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); - result.setChangeScript(appendDelimiterIfNotExist( - targetTableIndexEditor - .generateCreateObjectDDL(copySrcIndexWithTgtSchemaName(srcDbObject, tgtSchemaName)))); + result.setChangeScript(StructureCompareUtil.appendDelimiterIfNotExist(targetTableIndexEditor + .generateCreateObjectDDL(copySrcIndexWithTgtSchemaName(srcDbObject, tgtSchemaName)))); return result; } @@ -72,7 +72,7 @@ public DBObjectComparisonResult compare(@NonNull DBTableIndex srcIndex, @NonNull if (!ddl.isEmpty()) { // index to be updated result.setComparisonResult(ComparisonResult.INCONSISTENT); - result.setChangeScript(appendDelimiterIfNotExist(ddl)); + result.setChangeScript(StructureCompareUtil.appendDelimiterIfNotExist(ddl)); } else { result.setComparisonResult(ComparisonResult.CONSISTENT); } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TablePartitionStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTablePartitionStructureComparator.java similarity index 86% rename from server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TablePartitionStructureComparator.java rename to server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTablePartitionStructureComparator.java index 5a3cad7b82..1ff82a338f 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TablePartitionStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTablePartitionStructureComparator.java @@ -21,6 +21,7 @@ import com.oceanbase.odc.service.structurecompare.model.ComparisonResult; import com.oceanbase.odc.service.structurecompare.model.DBObjectComparisonResult; +import com.oceanbase.odc.service.structurecompare.util.StructureCompareUtil; import com.oceanbase.tools.dbbrowser.editor.DBTablePartitionEditor; import com.oceanbase.tools.dbbrowser.model.DBObjectType; import com.oceanbase.tools.dbbrowser.model.DBTablePartition; @@ -31,12 +32,12 @@ * @date 2024/1/4 * @since ODC_release_4.2.4 */ -public class TablePartitionStructureComparator implements DBObjectStructureComparator { +public class DBTablePartitionStructureComparator implements DBObjectStructureComparator { private DBTablePartitionEditor tgtPartitionEditor; private String srcSchemaName; private String tgtSchemaName; - public TablePartitionStructureComparator(DBTablePartitionEditor tgtPartitionEditor, String srcSchemaName, + public DBTablePartitionStructureComparator(DBTablePartitionEditor tgtPartitionEditor, String srcSchemaName, String tgtSchemaName) { this.tgtPartitionEditor = tgtPartitionEditor; this.srcSchemaName = srcSchemaName; @@ -67,9 +68,8 @@ public DBObjectComparisonResult compare(DBTablePartition srcPartition, DBTablePa // partition to be created result.setComparisonResult(ComparisonResult.ONLY_IN_SOURCE); result.setChangeScript( - appendDelimiterIfNotExist( - this.tgtPartitionEditor.generateCreateObjectDDL( - copySrcPartitionWithTgtSchemaName(srcPartition, this.tgtSchemaName)))); + StructureCompareUtil.appendDelimiterIfNotExist(this.tgtPartitionEditor.generateCreateObjectDDL( + copySrcPartitionWithTgtSchemaName(srcPartition, this.tgtSchemaName)))); } else { String ddl = this.tgtPartitionEditor.generateUpdateObjectDDL(tgtPartition, copySrcPartitionWithTgtSchemaName(srcPartition, this.tgtSchemaName)); @@ -78,7 +78,7 @@ public DBObjectComparisonResult compare(DBTablePartition srcPartition, DBTablePa } else { // partition to be updated result.setComparisonResult(ComparisonResult.INCONSISTENT); - result.setChangeScript(appendDelimiterIfNotExist(ddl)); + result.setChangeScript(StructureCompareUtil.appendDelimiterIfNotExist(ddl)); } } return result; diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTableStructureComparator.java similarity index 90% rename from server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java rename to server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTableStructureComparator.java index e2f88b4dcf..6624f84163 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/TableStructureComparator.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/comparedbobject/DBTableStructureComparator.java @@ -52,13 +52,13 @@ * @date 2024/1/4 * @since ODC_release_4.2.4 */ -public class TableStructureComparator implements DBObjectStructureComparator { +public class DBTableStructureComparator implements DBObjectStructureComparator { private DBTableEditor tgtTableEditor; private DialectType tgtDialectType; private String srcSchemaName; private String tgtSchemaName; - public TableStructureComparator(DBTableEditor tgtTableEditor, DialectType tgtDialectType, String srcSchemaName, + public DBTableStructureComparator(DBTableEditor tgtTableEditor, DialectType tgtDialectType, String srcSchemaName, String tgtSchemaName) { this.tgtTableEditor = tgtTableEditor; this.tgtDialectType = tgtDialectType; @@ -72,10 +72,10 @@ public List compare(List srcTables, List(), srcSchemaName, tgtSchemaName); } else if (tgtTables.isEmpty()) { - return buildCreatedTableResults(srcTables.stream().map(DBTable::getName).collect(Collectors.toList()), + return buildOnlyInSourceResult(srcTables.stream().map(DBTable::getName).collect(Collectors.toList()), new HashMap<>(), srcSchemaName, tgtSchemaName); } @@ -103,9 +103,9 @@ public List compare(List srcTables, List createdResults = - buildCreatedTableResults(toCreatedNames, srcTableName2Table, srcSchemaName, tgtSchemaName); + buildOnlyInSourceResult(toCreatedNames, srcTableName2Table, srcSchemaName, tgtSchemaName); List dropResults = - buildDroppedTableResults(toDroppedNames, tgtTableName2Table, srcSchemaName, tgtSchemaName); + buildOnlyInTargetResult(toDroppedNames, tgtTableName2Table, srcSchemaName, tgtSchemaName); List comparedResults = new ArrayList<>(); toComparedNames.forEach(name -> { @@ -119,7 +119,7 @@ public List compare(List srcTables, List buildCreatedTableResults(List toCreate, + private List buildOnlyInSourceResult(List toCreate, Map srcTableName2Table, String srcSchemaName, String tgtSchemaName) { List returnVal = new LinkedList<>(); if (toCreate.isEmpty()) { @@ -142,7 +142,7 @@ private List buildCreatedTableResults(List toC return returnVal; } - private List buildDroppedTableResults(List toDrop, + private List buildOnlyInTargetResult(List toDrop, Map tgtTableName2Table, String srcSchemaName, String tgtSchemaName) { List returnVal = new LinkedList<>(); @@ -206,11 +206,11 @@ public DBObjectComparisonResult compare(DBTable sourceTable, DBTable targetTable if (Objects.isNull(sourceTable) && Objects.isNull(targetTable)) { throw new IllegalStateException("Both source table and target table are null"); } else if (Objects.isNull(sourceTable)) { - return buildDroppedTableResults(Collections.singletonList(targetTable.getName()), + return buildOnlyInTargetResult(Collections.singletonList(targetTable.getName()), Collections.singletonMap(targetTable.getName(), targetTable), this.srcSchemaName, this.tgtSchemaName).get(0); } else if (Objects.isNull(targetTable)) { - return buildCreatedTableResults(Collections.singletonList(sourceTable.getName()), + return buildOnlyInSourceResult(Collections.singletonList(sourceTable.getName()), Collections.singletonMap(sourceTable.getName(), sourceTable), this.srcSchemaName, this.tgtSchemaName).get(0); } @@ -252,13 +252,13 @@ public DBObjectComparisonResult compare(DBTable sourceTable, DBTable targetTable } private List compareTableColumns(DBTable srcTable, DBTable tgtTable) { - return new TableColumnStructureComparator( + return new DBTableColumnStructureComparator( (DBTableColumnEditor) this.tgtTableEditor.getColumnEditor(), srcSchemaName, tgtSchemaName) .compare(srcTable.getColumns(), tgtTable.getColumns()); } private List compareTableIndexes(DBTable srcTable, DBTable tgtTable) { - return new TableIndexStructureComparator((DBTableIndexEditor) this.tgtTableEditor.getIndexEditor(), + return new DBTableIndexStructureComparator((DBTableIndexEditor) this.tgtTableEditor.getIndexEditor(), srcSchemaName, tgtSchemaName) .compare( this.tgtTableEditor.excludePrimaryKeyIndex(srcTable.getIndexes(), @@ -268,7 +268,7 @@ private List compareTableIndexes(DBTable srcTable, DBT } private List compareTableConstraints(DBTable srcTable, DBTable tgtTable) { - return new TableConstraintStructureComparator( + return new DBTableConstraintStructureComparator( (DBTableConstraintEditor) this.tgtTableEditor.getConstraintEditor(), srcSchemaName, tgtSchemaName) .compare( this.tgtTableEditor.excludeUniqueConstraint(srcTable.getIndexes(), @@ -278,7 +278,8 @@ private List compareTableConstraints(DBTable srcTable, } private DBObjectComparisonResult compareTablePartition(DBTable srcTable, DBTable tgtTable) { - return new TablePartitionStructureComparator((DBTablePartitionEditor) this.tgtTableEditor.getPartitionEditor(), + return new DBTablePartitionStructureComparator( + (DBTablePartitionEditor) this.tgtTableEditor.getPartitionEditor(), srcSchemaName, tgtSchemaName) .compare(srcTable.getPartition(), tgtTable.getPartition()); } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/util/StructureCompareUtil.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/util/StructureCompareUtil.java new file mode 100644 index 0000000000..59bd7ff551 --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/structurecompare/util/StructureCompareUtil.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.service.structurecompare.util; + +/** + * @author jingtian + * @date 2024/1/9 + * @since ODC_release_4.2.4 + */ +public class StructureCompareUtil { + private static final String DEFAULT_SQL_DELIMITER = ";"; + + public static String appendDelimiterIfNotExist(String sql) { + String returnVal = sql.trim(); + if (!returnVal.endsWith(DEFAULT_SQL_DELIMITER)) { + return returnVal + DEFAULT_SQL_DELIMITER + "\n"; + } + return sql; + } +}