From d9574338bc25ecddbded4ded7032380b4dc12b0a Mon Sep 17 00:00:00 2001 From: szymonsztuka Date: Wed, 20 Dec 2017 17:17:17 +0000 Subject: [PATCH] Liquibase works for a single db user with multi schema setup (par of ENT-1275) (#233) * Override Liquibase default schema by one from the node configuration (database.schema) if they are different. This allows database tables be created within a correct schema when no default schema is set at database level. * Pass in the databaseConfig.schema for network manager (for Liquibase schema migration). --- .../common/persistence/PersistenceUtils.kt | 2 +- .../persistence/HibernateConfiguration.kt | 4 ++ .../internal/persistence/SchemaMigration.kt | 21 +++++++- .../net/corda/node/internal/AbstractNode.kt | 6 +-- .../db-global-cleanup.sql | 46 +++++++++++++++++ .../db-global-setup.sql | 51 +++++++++++++++++++ .../sql-server-no-default-schema/db-setup.sql | 43 ++++++++++++++++ 7 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 testing/test-utils/src/main/resources/database-scripts/sql-server-no-default-schema/db-global-cleanup.sql create mode 100644 testing/test-utils/src/main/resources/database-scripts/sql-server-no-default-schema/db-global-setup.sql create mode 100644 testing/test-utils/src/main/resources/database-scripts/sql-server-no-default-schema/db-setup.sql diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistenceUtils.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistenceUtils.kt index 8387e3cb3e..8a207aef52 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistenceUtils.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistenceUtils.kt @@ -39,7 +39,7 @@ fun configureDatabase(dataSourceProperties: Properties, val schemas = setOf(NetworkManagementSchemaServices.SchemaV1) if (databaseConfig.runMigration) { - SchemaMigration(schemas, dataSource).runMigration() + SchemaMigration(schemas, dataSource, databaseConfig.schema).runMigration() } return CordaPersistence(dataSource, databaseConfig, schemas, emptyList()) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt index 1b83967f43..7dba1c747c 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt @@ -52,6 +52,10 @@ class HibernateConfiguration( .setProperty("hibernate.hbm2ddl.auto", "validate") .setProperty("hibernate.connection.isolation", databaseConfig.transactionIsolationLevel.jdbcValue.toString()) + databaseConfig.schema?.apply { + config.setProperty("hibernate.default_schema", databaseConfig.schema) + } + schemas.forEach { schema -> // TODO: require mechanism to set schemaOptions (databaseSchema, tablePrefix) which are not global to session schema.mappedTypes.forEach { config.addAnnotatedClass(it) } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/SchemaMigration.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/SchemaMigration.kt index 8f62c3317b..9bee1eb403 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/SchemaMigration.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/SchemaMigration.kt @@ -10,12 +10,17 @@ import liquibase.database.jvm.JdbcConnection import liquibase.resource.ClassLoaderResourceAccessor import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.getMigrationResource +import net.corda.core.utilities.contextLogger import java.io.* import javax.sql.DataSource private const val MIGRATION_PREFIX = "migration" -class SchemaMigration(val schemas: Set, val dataSource: DataSource) { +class SchemaMigration(val schemas: Set, val dataSource: DataSource, private val schemaName: String? = null) { + + companion object { + private val logger = contextLogger() + } fun generateMigrationScript(outputFile: File) = doRunMigration(PrintWriter(outputFile)) @@ -55,6 +60,20 @@ class SchemaMigration(val schemas: Set, val dataSource: DataSource val liquibase = Liquibase(dynamicInclude, customResourceAccessor, getLiquibaseDatabase(JdbcConnection(connection))) + if (!schemaName.isNullOrBlank()) { + if (liquibase.database.defaultSchemaName != schemaName) { + logger.debug("defaultSchemaName=${liquibase.database.defaultSchemaName} changed to $schemaName") + liquibase.database.defaultSchemaName = schemaName + } + if (liquibase.database.liquibaseSchemaName != schemaName) { + logger.debug("liquibaseSchemaName=${liquibase.database.liquibaseSchemaName} changed to $schemaName") + liquibase.database.liquibaseSchemaName = schemaName + } + } + logger.info("defaultSchemaName=${liquibase.database.defaultSchemaName}") + logger.info("liquibaseSchemaName=${liquibase.database.liquibaseSchemaName}") + logger.info("outputDefaultSchema=${liquibase.database.outputDefaultSchema}") + if (outputWriter != null) { liquibase.update(Contexts(), outputWriter) } else { diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 2a1b1292f1..ed1d3d6539 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -205,13 +205,13 @@ abstract class AbstractNode(val configuration: NodeConfiguration, fun generateDatabaseSchema(outputFile: String) { HikariDataSource(HikariConfig(configuration.dataSourceProperties)).use { dataSource -> - SchemaMigration(cordappLoader.cordappSchemas, dataSource).generateMigrationScript(File(outputFile)) + SchemaMigration(cordappLoader.cordappSchemas, dataSource, configuration.database.schema).generateMigrationScript(File(outputFile)) } } fun runDbMigration() { HikariDataSource(HikariConfig(configuration.dataSourceProperties)).use { dataSource -> - SchemaMigration(cordappLoader.cordappSchemas, dataSource).runMigration() + SchemaMigration(cordappLoader.cordappSchemas, dataSource, configuration.database.schema).runMigration() } } @@ -876,7 +876,7 @@ fun configureDatabase(dataSourceProperties: Properties, val attributeConverters = listOf(AbstractPartyToX500NameAsStringConverter(identityService)) if(databaseConfig.runMigration){ - SchemaMigration(schemaService.schemaOptions.keys, dataSource).runMigration() + SchemaMigration(schemaService.schemaOptions.keys, dataSource, databaseConfig.schema).runMigration() } return CordaPersistence(dataSource, databaseConfig, schemaService.schemaOptions.keys, attributeConverters) diff --git a/testing/test-utils/src/main/resources/database-scripts/sql-server-no-default-schema/db-global-cleanup.sql b/testing/test-utils/src/main/resources/database-scripts/sql-server-no-default-schema/db-global-cleanup.sql new file mode 100644 index 0000000000..0e733933d7 --- /dev/null +++ b/testing/test-utils/src/main/resources/database-scripts/sql-server-no-default-schema/db-global-cleanup.sql @@ -0,0 +1,46 @@ +DROP TABLE IF EXISTS ${schema}.node_attachments; +DROP TABLE IF EXISTS ${schema}.node_checkpoints; +DROP TABLE IF EXISTS ${schema}.node_transactions; +DROP TABLE IF EXISTS ${schema}.node_message_retry; +DROP TABLE IF EXISTS ${schema}.node_message_ids; +DROP TABLE IF EXISTS ${schema}.vault_states; +DROP TABLE IF EXISTS ${schema}.node_our_key_pairs; +DROP TABLE IF EXISTS ${schema}.node_scheduled_states; +DROP TABLE IF EXISTS ${schema}.node_network_map_nodes; +DROP TABLE IF EXISTS ${schema}.node_network_map_subscribers; +DROP TABLE IF EXISTS ${schema}.node_notary_commit_log; +DROP TABLE IF EXISTS ${schema}.node_transaction_mappings; +DROP TABLE IF EXISTS ${schema}.vault_fungible_states_parts; +DROP TABLE IF EXISTS ${schema}.vault_linear_states_parts; +DROP TABLE IF EXISTS ${schema}.vault_fungible_states; +DROP TABLE IF EXISTS ${schema}.vault_linear_states; +DROP TABLE IF EXISTS ${schema}.node_bft_committed_states; +DROP TABLE IF EXISTS ${schema}.node_raft_committed_states; +DROP TABLE IF EXISTS ${schema}.vault_transaction_notes; +DROP TABLE IF EXISTS ${schema}.link_nodeinfo_party; +DROP TABLE IF EXISTS ${schema}.node_link_nodeinfo_party; +DROP TABLE IF EXISTS ${schema}.node_info_party_cert; +DROP TABLE IF EXISTS ${schema}.node_info_hosts; +DROP TABLE IF EXISTS ${schema}.node_infos; +DROP TABLE IF EXISTS ${schema}.cp_states; +DROP TABLE IF EXISTS ${schema}.node_contract_upgrades; +DROP TABLE IF EXISTS ${schema}.node_identities; +DROP TABLE IF EXISTS ${schema}.node_named_identities; +DROP TABLE IF EXISTS ${schema}.children; +DROP TABLE IF EXISTS ${schema}.parents; +DROP TABLE IF EXISTS ${schema}.contract_cash_states; +DROP TABLE IF EXISTS ${schema}.messages; +DROP TABLE IF EXISTS ${schema}.state_participants; +DROP TABLE IF EXISTS ${schema}.cash_states_v2; +DROP TABLE IF EXISTS ${schema}.cash_states_v3; +DROP TABLE IF EXISTS ${schema}.cp_states_v2; +DROP TABLE IF EXISTS ${schema}.dummy_deal_states; +DROP TABLE IF EXISTS ${schema}.dummy_linear_states; +DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2; +DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion; +DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOG; +DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOGLOCK; +DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence; +DROP LOGIN ${schema}; +DROP USER IF EXISTS ${schema}; +DROP SCHEMA IF EXISTS ${schema}; \ No newline at end of file diff --git a/testing/test-utils/src/main/resources/database-scripts/sql-server-no-default-schema/db-global-setup.sql b/testing/test-utils/src/main/resources/database-scripts/sql-server-no-default-schema/db-global-setup.sql new file mode 100644 index 0000000000..29463d973f --- /dev/null +++ b/testing/test-utils/src/main/resources/database-scripts/sql-server-no-default-schema/db-global-setup.sql @@ -0,0 +1,51 @@ +DROP TABLE IF EXISTS ${schema}.node_attachments; +DROP TABLE IF EXISTS ${schema}.node_checkpoints; +DROP TABLE IF EXISTS ${schema}.node_transactions; +DROP TABLE IF EXISTS ${schema}.node_message_retry; +DROP TABLE IF EXISTS ${schema}.node_message_ids; +DROP TABLE IF EXISTS ${schema}.vault_states; +DROP TABLE IF EXISTS ${schema}.node_our_key_pairs; +DROP TABLE IF EXISTS ${schema}.node_scheduled_states; +DROP TABLE IF EXISTS ${schema}.node_network_map_nodes; +DROP TABLE IF EXISTS ${schema}.node_network_map_subscribers; +DROP TABLE IF EXISTS ${schema}.node_notary_commit_log; +DROP TABLE IF EXISTS ${schema}.node_transaction_mappings; +DROP TABLE IF EXISTS ${schema}.vault_fungible_states_parts; +DROP TABLE IF EXISTS ${schema}.vault_linear_states_parts; +DROP TABLE IF EXISTS ${schema}.vault_fungible_states; +DROP TABLE IF EXISTS ${schema}.vault_linear_states; +DROP TABLE IF EXISTS ${schema}.node_bft_committed_states; +DROP TABLE IF EXISTS ${schema}.node_raft_committed_states; +DROP TABLE IF EXISTS ${schema}.vault_transaction_notes; +DROP TABLE IF EXISTS ${schema}.link_nodeinfo_party; +DROP TABLE IF EXISTS ${schema}.node_link_nodeinfo_party; +DROP TABLE IF EXISTS ${schema}.node_info_party_cert; +DROP TABLE IF EXISTS ${schema}.node_info_hosts; +DROP TABLE IF EXISTS ${schema}.node_infos; +DROP TABLE IF EXISTS ${schema}.cp_states; +DROP TABLE IF EXISTS ${schema}.node_contract_upgrades; +DROP TABLE IF EXISTS ${schema}.node_identities; +DROP TABLE IF EXISTS ${schema}.node_named_identities; +DROP TABLE IF EXISTS ${schema}.children; +DROP TABLE IF EXISTS ${schema}.parents; +DROP TABLE IF EXISTS ${schema}.contract_cash_states; +DROP TABLE IF EXISTS ${schema}.messages; +DROP TABLE IF EXISTS ${schema}.state_participants; +DROP TABLE IF EXISTS ${schema}.cash_states_v2; +DROP TABLE IF EXISTS ${schema}.cash_states_v3; +DROP TABLE IF EXISTS ${schema}.cp_states_v2; +DROP TABLE IF EXISTS ${schema}.dummy_deal_states; +DROP TABLE IF EXISTS ${schema}.dummy_linear_states; +DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2; +DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion; +DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence; +DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOG; +DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOGLOCK; +DROP USER IF EXISTS ${schema}; +DROP LOGIN ${schema}; +DROP SCHEMA IF EXISTS ${schema}; +CREATE LOGIN ${schema} WITH PASSWORD = 'yourStrong(!)Password'; +IF NOT EXISTS (SELECT schema_name FROM information_schema.schemata WHERE schema_name = '${schema}') EXEC('CREATE SCHEMA ${schema}'); +IF NOT EXISTS (SELECT * FROM sys.sysusers WHERE name='${schema}') CREATE USER ${schema} FOR LOGIN ${schema}; +GRANT ALTER, DELETE, EXECUTE, INSERT, REFERENCES, SELECT, UPDATE, VIEW DEFINITION ON SCHEMA::${schema} TO ${schema}; +GRANT CREATE TABLE, CREATE PROCEDURE, CREATE FUNCTION, CREATE VIEW TO ${schema}; \ No newline at end of file diff --git a/testing/test-utils/src/main/resources/database-scripts/sql-server-no-default-schema/db-setup.sql b/testing/test-utils/src/main/resources/database-scripts/sql-server-no-default-schema/db-setup.sql new file mode 100644 index 0000000000..9357df9527 --- /dev/null +++ b/testing/test-utils/src/main/resources/database-scripts/sql-server-no-default-schema/db-setup.sql @@ -0,0 +1,43 @@ +DROP TABLE IF EXISTS ${schema}.node_attachments; +DROP TABLE IF EXISTS ${schema}.node_checkpoints; +DROP TABLE IF EXISTS ${schema}.node_transactions; +DROP TABLE IF EXISTS ${schema}.node_message_retry; +DROP TABLE IF EXISTS ${schema}.node_message_ids; +DROP TABLE IF EXISTS ${schema}.vault_states; +DROP TABLE IF EXISTS ${schema}.node_our_key_pairs; +DROP TABLE IF EXISTS ${schema}.node_scheduled_states; +DROP TABLE IF EXISTS ${schema}.node_network_map_nodes; +DROP TABLE IF EXISTS ${schema}.node_network_map_subscribers; +DROP TABLE IF EXISTS ${schema}.node_notary_commit_log; +DROP TABLE IF EXISTS ${schema}.node_transaction_mappings; +DROP TABLE IF EXISTS ${schema}.vault_fungible_states_parts; +DROP TABLE IF EXISTS ${schema}.vault_linear_states_parts; +DROP TABLE IF EXISTS ${schema}.vault_fungible_states; +DROP TABLE IF EXISTS ${schema}.vault_linear_states; +DROP TABLE IF EXISTS ${schema}.node_bft_committed_states; +DROP TABLE IF EXISTS ${schema}.node_raft_committed_states; +DROP TABLE IF EXISTS ${schema}.vault_transaction_notes; +DROP TABLE IF EXISTS ${schema}.link_nodeinfo_party; +DROP TABLE IF EXISTS ${schema}.node_link_nodeinfo_party; +DROP TABLE IF EXISTS ${schema}.node_info_party_cert; +DROP TABLE IF EXISTS ${schema}.node_info_hosts; +DROP TABLE IF EXISTS ${schema}.node_infos; +DROP TABLE IF EXISTS ${schema}.cp_states; +DROP TABLE IF EXISTS ${schema}.node_contract_upgrades; +DROP TABLE IF EXISTS ${schema}.node_identities; +DROP TABLE IF EXISTS ${schema}.node_named_identities; +DROP TABLE IF EXISTS ${schema}.children; +DROP TABLE IF EXISTS ${schema}.parents; +DROP TABLE IF EXISTS ${schema}.contract_cash_states; +DROP TABLE IF EXISTS ${schema}.messages; +DROP TABLE IF EXISTS ${schema}.state_participants; +DROP TABLE IF EXISTS ${schema}.cash_states_v2; +DROP TABLE IF EXISTS ${schema}.cash_states_v3; +DROP TABLE IF EXISTS ${schema}.cp_states_v2; +DROP TABLE IF EXISTS ${schema}.dummy_deal_states; +DROP TABLE IF EXISTS ${schema}.dummy_linear_states; +DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2; +DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion; +DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOG; +DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOGLOCK; +DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence; \ No newline at end of file