├── .idea ├── .gitignore ├── compiler.xml ├── encodings.xml ├── jarRepositories.xml ├── misc.xml └── vcs.xml ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── pw │ │ └── dcp │ │ ├── DatabaseChangePlatformApplication.java │ │ ├── DatabaseType │ │ └── Enum.java │ │ ├── service │ │ └── SchemaCompareService.java │ │ └── utils │ │ └── DatabaseSchemaComparator.java └── resources │ └── application.properties └── test └── java └── com └── pw └── dcp └── DatabaseChangePlatformApplicationTests.java /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SchemaDiff 2 | 3 | **SchemaDiff** is a powerful tool designed to compare and analyze the differences between database schemas, making it easier to manage and migrate databases in various environments. It supports different types of databases including Oracle, MySQL, PostgreSQL, and more. 4 | 5 | ## Features 6 | 7 | - **Cross-Platform Comparison**: Compare database schemas across different database types (e.g., Oracle to MySQL, PostgreSQL to MySQL, etc.). 8 | - **Comprehensive Diffing**: Supports table structures, indexes, stored procedures, sequences, triggers, and more. 9 | - **User-Friendly Interface**: Easy to use and integrates well with existing workflows. 10 | - **Efficient Reports**: Generate detailed reports on schema differences to simplify migration or database synchronization. 11 | - **Customizable**: Highly configurable to suit various project needs and database configurations. 12 | 13 | ## Supported Databases 14 | 15 | - Oracle 16 | - MySQL 17 | - PostgreSQL 18 | - SQL Server 19 | - DB2 20 | - Sybase 21 | 22 | ## Installation 23 | 24 | ### Requirements 25 | 26 | - Java 8 or later 27 | - Maven 28 | 29 | ### Steps to Install 30 | 31 | 1. Clone the repository: 32 | ```bash 33 | git clone https://github.com/your-username/SchemaDiff.git 34 | 35 | 2. Navigate to the project directory: 36 | ```bash 37 | cd SchemaDiff 38 | 39 | 3. Build the project using Maven: 40 | ```bash 41 | mvn clean install 42 | 43 | ### Usage 44 | 45 | To compare two database schemas, run the following command: 46 | ```bash 47 | java -jar SchemaDiff.jar 48 | 49 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.2 9 | 10 | 11 | com.pw 12 | dcp 13 | 0.0.1-SNAPSHOT 14 | Database-Change-Platform 15 | Demo project for Spring Boot 16 | 17 | 17 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-devtools 28 | runtime 29 | true 30 | 31 | 32 | org.projectlombok 33 | lombok 34 | true 35 | 36 | 37 | 38 | 39 | com.github.jsqlparser 40 | jsqlparser 41 | 3.1 42 | 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-test 48 | test 49 | 50 | 51 | 52 | 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-maven-plugin 57 | 58 | 59 | 60 | org.projectlombok 61 | lombok 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/main/java/com/pw/dcp/DatabaseChangePlatformApplication.java: -------------------------------------------------------------------------------- 1 | package com.pw.dcp; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DatabaseChangePlatformApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(DatabaseChangePlatformApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/pw/dcp/DatabaseType/Enum.java: -------------------------------------------------------------------------------- 1 | package com.pw.dcp.DatabaseType; 2 | 3 | public class Enum { 4 | String Oracle = "Oracle"; 5 | String MySQL = "MySQL"; 6 | String SQLServer = "SQLServer"; 7 | String PostgreSQL = "PostgreSQL"; 8 | String DB2 = "DB2"; 9 | String SQLite = "SQLite"; 10 | String H2 = "H2"; 11 | String Sybase = "Sybase"; 12 | String MariaDB = "MariaDB"; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/pw/dcp/service/SchemaCompareService.java: -------------------------------------------------------------------------------- 1 | package com.pw.dcp.service; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | @Service 6 | public class SchemaCompareService { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/pw/dcp/utils/DatabaseSchemaComparator.java: -------------------------------------------------------------------------------- 1 | package com.pw.dcp.utils; 2 | 3 | import java.sql.*; 4 | 5 | public class DatabaseSchemaComparator { 6 | 7 | 8 | public static void compareSchemas(String usernameDB1, String usernameDB2) { 9 | try (Connection connectionDB1 = DriverManager.getConnection(JDBC_URL_DB1, USER_DB1, PASSWORD_DB1); 10 | Connection connectionDB2 = DriverManager.getConnection(JDBC_URL_DB2, USER_DB2, PASSWORD_DB2)) { 11 | 12 | compareTables(connectionDB1, usernameDB1, connectionDB2, usernameDB2); 13 | compareTriggers(connectionDB1, usernameDB1, connectionDB2, usernameDB2); 14 | compareSequences(connectionDB1, usernameDB1, connectionDB2, usernameDB2); 15 | compareProcedures(connectionDB1, usernameDB1, connectionDB2, usernameDB2); 16 | compareIndexes(connectionDB1, usernameDB1, connectionDB2, usernameDB2); 17 | compareForeignKeys(connectionDB1, usernameDB1, connectionDB2, usernameDB2); 18 | compareViews(connectionDB1, usernameDB1, connectionDB2, usernameDB2); 19 | compareConstraints(connectionDB1, usernameDB1, connectionDB2, usernameDB2); 20 | 21 | } catch (SQLException e) { 22 | e.printStackTrace(); 23 | } 24 | } 25 | 26 | 27 | private static void compareTables(Connection connectionDB1, String usernameDB1, Connection connectionDB2, String usernameDB2) throws SQLException { 28 | compareResults( 29 | executeQuery(connectionDB1, "SELECT table_name, column_name, data_type, data_length, nullable FROM all_tab_columns WHERE owner = '" + usernameDB1 + "' ORDER BY table_name, column_id"), 30 | executeQuery(connectionDB2, "SELECT table_name, column_name, data_type, data_length, nullable FROM all_tab_columns WHERE owner = '" + usernameDB2 + "' ORDER BY table_name, column_id") 31 | ); 32 | } 33 | 34 | 35 | private static void compareTriggers(Connection connectionDB1, String usernameDB1, Connection connectionDB2, String usernameDB2) throws SQLException { 36 | compareResults( 37 | executeQuery(connectionDB1, "SELECT trigger_name, table_name, trigger_type, triggering_event FROM all_triggers WHERE table_owner = '" + usernameDB1 + "' ORDER BY trigger_name"), 38 | executeQuery(connectionDB2, "SELECT trigger_name, table_name, trigger_type, triggering_event FROM all_triggers WHERE table_owner = '" + usernameDB2 + "' ORDER BY trigger_name") 39 | ); 40 | } 41 | 42 | private static void compareSequences(Connection connectionDB1, String usernameDB1, Connection connectionDB2, String usernameDB2) throws SQLException { 43 | compareResults( 44 | executeQuery(connectionDB1, "SELECT sequence_name, min_value, max_value, increment_by, last_number FROM all_sequences WHERE sequence_owner = '" + usernameDB1 + "' ORDER BY sequence_name"), 45 | executeQuery(connectionDB2, "SELECT sequence_name, min_value, max_value, increment_by, last_number FROM all_sequences WHERE sequence_owner = '" + usernameDB2 + "' ORDER BY sequence_name") 46 | ); 47 | } 48 | 49 | private static void compareProcedures(Connection connectionDB1, String usernameDB1, Connection connectionDB2, String usernameDB2) throws SQLException { 50 | compareResults( 51 | executeQuery(connectionDB1, "SELECT object_name, procedure_name, object_type, arguments FROM all_procedures WHERE owner = '" + usernameDB1 + "' ORDER BY object_name, procedure_name"), 52 | executeQuery(connectionDB2, "SELECT object_name, procedure_name, object_type, arguments FROM all_procedures WHERE owner = '" + usernameDB2 + "' ORDER BY object_name, procedure_name") 53 | ); 54 | } 55 | 56 | private static void compareIndexes(Connection connectionDB1, String usernameDB1, Connection connectionDB2, String usernameDB2) throws SQLException { 57 | compareResults( 58 | executeQuery(connectionDB1, "SELECT index_name, table_name, uniqueness, column_name FROM all_ind_columns WHERE table_owner = '" + usernameDB1 + "' ORDER BY index_name"), 59 | executeQuery(connectionDB2, "SELECT index_name, table_name, uniqueness, column_name FROM all_ind_columns WHERE table_owner = '" + usernameDB2 + "' ORDER BY index_name") 60 | ); 61 | } 62 | 63 | private static void compareForeignKeys(Connection connectionDB1, String usernameDB1, Connection connectionDB2, String usernameDB2) throws SQLException { 64 | compareResults( 65 | executeQuery(connectionDB1, "SELECT constraint_name, table_name, r_constraint_name, delete_rule FROM all_constraints WHERE constraint_type = 'R' AND owner = '" + usernameDB1 + "' ORDER BY table_name, constraint_name"), 66 | executeQuery(connectionDB2, "SELECT constraint_name, table_name, r_constraint_name, delete_rule FROM all_constraints WHERE constraint_type = 'R' AND owner = '" + usernameDB2 + "' ORDER BY table_name, constraint_name") 67 | ); 68 | } 69 | 70 | private static void compareViews(Connection connectionDB1, String usernameDB1, Connection connectionDB2, String usernameDB2) throws SQLException { 71 | compareResults( 72 | executeQuery(connectionDB1, "SELECT view_name, text FROM all_views WHERE owner = '" + usernameDB1 + "' ORDER BY view_name"), 73 | executeQuery(connectionDB2, "SELECT view_name, text FROM all_views WHERE owner = '" + usernameDB2 + "' ORDER BY view_name") 74 | ); 75 | } 76 | 77 | private static void compareConstraints(Connection connectionDB1, String usernameDB1, Connection connectionDB2, String usernameDB2) throws SQLException { 78 | compareResults( 79 | executeQuery(connectionDB1, "SELECT constraint_name, table_name, constraint_type FROM all_constraints WHERE owner = '" + usernameDB1 + "' ORDER BY table_name, constraint_name"), 80 | executeQuery(connectionDB2, "SELECT constraint_name, table_name, constraint_type FROM all_constraints WHERE owner = '" + usernameDB2 + "' ORDER BY table_name, constraint_name") 81 | ); 82 | } 83 | 84 | 85 | private static void compareResults(ResultSet resultSet1, ResultSet resultSet2) throws SQLException { 86 | ResultSetMetaData metaData1 = resultSet1.getMetaData(); 87 | ResultSetMetaData metaData2 = resultSet2.getMetaData(); 88 | 89 | int columnCount1 = metaData1.getColumnCount(); 90 | int columnCount2 = metaData2.getColumnCount(); 91 | 92 | // Check if the number of columns is the same in both result sets 93 | if (columnCount1 != columnCount2) { 94 | System.out.println("Number of columns in the result sets is not the same."); 95 | return; 96 | } 97 | 98 | // Compare column names 99 | for (int i = 1; i <= columnCount1; i++) { 100 | String columnName1 = metaData1.getColumnName(i); 101 | String columnName2 = metaData2.getColumnName(i); 102 | 103 | if (!columnName1.equals(columnName2)) { 104 | System.out.println("Column names do not match: " + columnName1 + " and " + columnName2); 105 | return; 106 | } 107 | } 108 | 109 | // Compare data in the result sets 110 | while (resultSet1.next() && resultSet2.next()) { 111 | for (int i = 1; i <= columnCount1; i++) { 112 | Object value1 = resultSet1.getObject(i); 113 | Object value2 = resultSet2.getObject(i); 114 | 115 | // Add your comparison logic here 116 | // For simplicity, I'm using toString() for comparison 117 | if (!value1.toString().equals(value2.toString())) { 118 | System.out.println("Data mismatch in column " + metaData1.getColumnName(i) + 119 | ": " + value1 + " (DB1) and " + value2 + " (DB2)"); 120 | return; 121 | } 122 | } 123 | } 124 | 125 | // Check if one result set has more rows than the other 126 | if (resultSet1.next()) { 127 | System.out.println("More rows in the first result set."); 128 | } else if (resultSet2.next()) { 129 | System.out.println("More rows in the second result set."); 130 | } else { 131 | System.out.println("Result sets match."); 132 | } 133 | } 134 | 135 | 136 | private static ResultSet executeQuery(Connection connection, String sql) throws SQLException { 137 | try (Statement statement = connection.createStatement()) { 138 | return statement.executeQuery(sql); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/test/java/com/pw/dcp/DatabaseChangePlatformApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.pw.dcp; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DatabaseChangePlatformApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------