CORDA-1471 Database schema setup for internal tables via Liquibase (#3815)

Internal tables (the tables from node and finance modules) are now tracked /created by Liquibase script.
Tables backing MappedSchemma in Cordapps are created by Hibernate (as before). 
The PR scope added Liquibase library, setup code SchemaMigration and XML scripts and from Enterprise.
For existing database installation - the node will auto-upgrade to use Liquibase.
Method migrateOlderDatabaseToUseLiquibase checks for any 3.X existing Corda database to upgrade database to use Liquibase. When the existing database without Liquibase integral tables is detected, the node (at startup) will create Liquibase tracking tables and fill them with all migration scripts (marked as done), this ensure the database will look as it would use Liquibase from the beginning.
The database changes gradually introduced by the subsequent 3.X releases (3.1, 3.2) are conditionally run by Liquibase.
This commit is contained in:
szymonsztuka 2018-08-23 16:30:02 +01:00 committed by GitHub
parent 409b4e2a42
commit 487cad7d06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 1318 additions and 125 deletions

View File

@ -57,6 +57,7 @@ buildscript {
ext.shiro_version = '1.4.0'
ext.shadow_version = '2.0.4'
ext.artifactory_plugin_version = constants.getProperty('artifactoryPluginVersion')
ext.liquibase_version = '3.6.2'
ext.artifactory_contextUrl = 'https://ci-artifactory.corda.r3cev.com/artifactory'
ext.snake_yaml_version = constants.getProperty('snakeYamlVersion')
ext.docker_compose_rule_version = '0.33.0'

View File

@ -18,6 +18,8 @@ object CommonSchema
*/
object CommonSchemaV1 : MappedSchema(schemaFamily = CommonSchema.javaClass, version = 1, mappedTypes = emptyList()) {
override val migrationResource = "common.changelog-master"
@MappedSuperclass
class LinearState(
/** [ContractState] attributes */

View File

@ -45,6 +45,12 @@ open class MappedSchema(schemaFamily: Class<*>,
val version: Int,
val mappedTypes: Iterable<Class<*>>) {
val name: String = schemaFamily.name
/**
* Optional classpath resource containing the database changes for the [mappedTypes]
*/
open val migrationResource: String? = null
override fun toString(): String = "${this.javaClass.simpleName}(name=$name, version=$version)"
override fun equals(other: Any?): Boolean {

View File

@ -20,6 +20,9 @@ object CashSchema
*/
@CordaSerializable
object CashSchemaV1 : MappedSchema(schemaFamily = CashSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCashState::class.java)) {
override val migrationResource = "cash.changelog-master"
@Entity
@Table(name = "contract_cash_states", indexes = [Index(name = "ccy_code_idx", columnList = "ccy_code"), Index(name = "pennies_idx", columnList = "pennies")])
class PersistentCashState(

View File

@ -23,6 +23,9 @@ object CommercialPaperSchema
*/
@CordaSerializable
object CommercialPaperSchemaV1 : MappedSchema(schemaFamily = CommercialPaperSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCommercialPaperState::class.java)) {
override val migrationResource = "commercial-paper.changelog-master"
@Entity
@Table(name = "cp_states", indexes = [Index(name = "ccy_code_index", columnList = "ccy_code"), Index(name = "maturity_index", columnList = "maturity_instant"), Index(name = "face_value_index", columnList = "face_value")])
class PersistentCommercialPaperState(

View File

@ -0,0 +1,37 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd" >
<changeSet author="R3.Corda" id="1511451595465-2">
<createTable tableName="contract_cash_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="ccy_code" type="NVARCHAR(3)"/>
<column name="issuer_key_hash" type="NVARCHAR(130)"/>
<column name="issuer_ref" type="varbinary(512)"/>
<column name="owner_name" type="NVARCHAR(255)"/>
<column name="pennies" type="BIGINT"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-28">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="contract_cash_states_pkey" tableName="contract_cash_states"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-51">
<createIndex indexName="ccy_code_idx" tableName="contract_cash_states">
<column name="ccy_code"/>
</createIndex>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-57">
<createIndex indexName="pennies_idx" tableName="contract_cash_states">
<column name="pennies"/>
</createIndex>
</changeSet>
<changeSet id="non-clustered_pk-cash" author="R3.Corda" onValidationFail="MARK_RAN">
<dropPrimaryKey tableName="contract_cash_states" constraintName="contract_cash_states_pkey"/>
<addPrimaryKey tableName="contract_cash_states" columnNames="output_index, transaction_id"
constraintName="contract_cash_states_pkey" clustered="false"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,7 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd" >
<include file="migration/cash.changelog-init.xml"/>
<include file="migration/cash.changelog-v1.xml"/>
</databaseChangeLog>

View File

@ -0,0 +1,27 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"
logicalFilePath="migration/node-services.changelog-init.xml">
<changeSet id="1525793504" author="R3.Corda">
<!-- drop indexes before adding not null constraints to the underlying table, recreating index immediately after -->
<dropIndex indexName="ccy_code_idx" tableName="contract_cash_states"/>
<addNotNullConstraint tableName="contract_cash_states" columnName="ccy_code" columnDataType="NVARCHAR(3)"/>
<createIndex indexName="ccy_code_idx" tableName="contract_cash_states">
<column name="ccy_code"/>
</createIndex>
<addNotNullConstraint tableName="contract_cash_states" columnName="issuer_key_hash"
columnDataType="NVARCHAR(130)"/>
<addNotNullConstraint tableName="contract_cash_states" columnName="issuer_ref" columnDataType="varbinary(512)"/>
<!-- drop indexes before adding not null constraints to the underlying table, recreating index immediately after -->
<dropIndex indexName="pennies_idx" tableName="contract_cash_states"/>
<addNotNullConstraint tableName="contract_cash_states" columnName="pennies" columnDataType="BIGINT"/>
<createIndex indexName="pennies_idx" tableName="contract_cash_states">
<column name="pennies"/>
</createIndex>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,45 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="1511451595465-3">
<createTable tableName="cp_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="ccy_code" type="NVARCHAR(3)"/>
<column name="face_value" type="BIGINT"/>
<column name="face_value_issuer_key_hash" type="NVARCHAR(130)"/>
<column name="face_value_issuer_ref" type="varbinary(512)"/>
<column name="issuance_key_hash" type="NVARCHAR(130)"/>
<column name="issuance_ref" type="varbinary(255)"/>
<column name="maturity_instant" type="timestamp"/>
<column name="owner_key_hash" type="NVARCHAR(130)"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-29">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="cp_states_pkey" tableName="cp_states"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-52">
<createIndex indexName="ccy_code_index" tableName="cp_states">
<column name="ccy_code"/>
</createIndex>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-54">
<createIndex indexName="face_value_index" tableName="cp_states">
<column name="face_value"/>
</createIndex>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-56">
<createIndex indexName="maturity_index" tableName="cp_states">
<column name="maturity_instant"/>
</createIndex>
</changeSet>
<changeSet id="non-clustered_pk-commercial-paper" author="R3.Corda" onValidationFail="MARK_RAN">
<dropPrimaryKey tableName="cp_states" constraintName="cp_states_pkey"/>
<addPrimaryKey tableName="cp_states" columnNames="output_index, transaction_id" constraintName="cp_states_pkey"
clustered="false"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,7 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<include file="migration/commercial-paper.changelog-init.xml"/>
<include file="migration/commercial-paper.changelog-v1.xml"/>
</databaseChangeLog>

View File

@ -0,0 +1,27 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="1525962920">
<!-- drop indexes before adding not null constraints to the underlying table, recreating index immediately after -->
<dropIndex tableName="cp_states" indexName="ccy_code_index"/>
<addNotNullConstraint tableName="cp_states" columnName="ccy_code" columnDataType="NVARCHAR(3)"/>
<createIndex indexName="ccy_code_index" tableName="cp_states">
<column name="ccy_code"/>
</createIndex>
<dropIndex tableName="cp_states" indexName="face_value_index"/>
<addNotNullConstraint tableName="cp_states" columnName="face_value" columnDataType="BIGINT"/>
<createIndex indexName="face_value_index" tableName="cp_states">
<column name="face_value"/>
</createIndex>
<addNotNullConstraint tableName="cp_states" columnName="face_value_issuer_key_hash" columnDataType="NVARCHAR(130)"/>
<addNotNullConstraint tableName="cp_states" columnName="face_value_issuer_ref" columnDataType="varbinary(512)"/>
<addNotNullConstraint tableName="cp_states" columnName="issuance_key_hash" columnDataType="NVARCHAR(130)"/>
<addNotNullConstraint tableName="cp_states" columnName="issuance_ref" columnDataType="varbinary(255)"/>
<dropIndex tableName="cp_states" indexName="maturity_index"/>
<addNotNullConstraint tableName="cp_states" columnName="maturity_instant" columnDataType="timestamp"/>
<createIndex indexName="maturity_index" tableName="cp_states">
<column name="maturity_instant"/>
</createIndex>
<addNotNullConstraint tableName="cp_states" columnName="owner_key_hash" columnDataType="NVARCHAR(130)"/>
</changeSet>
</databaseChangeLog>

View File

@ -35,6 +35,11 @@ dependencies {
// For caches rather than guava
compile "com.github.ben-manes.caffeine:caffeine:$caffeine_version"
// For db migration
compile "org.liquibase:liquibase-core:$liquibase_version"
compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version"
runtime 'com.mattbertolini:liquibase-slf4j:2.0.0'
// Unit testing helpers.
testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:$assertj_version"

View File

@ -0,0 +1,32 @@
package net.corda.nodeapi.internal
import com.google.common.base.CaseFormat
import net.corda.core.schemas.MappedSchema
object MigrationHelpers {
private const val MIGRATION_PREFIX = "migration"
private const val DEFAULT_MIGRATION_EXTENSION = "xml"
private const val CHANGELOG_NAME = "changelog-master"
private val possibleMigrationExtensions = listOf(".xml", ".sql", ".yml", ".json")
fun getMigrationResource(schema: MappedSchema, classLoader: ClassLoader): String? {
val declaredMigration = schema.migrationResource
if (declaredMigration == null) {
// try to apply the naming convention and find the migration file in the classpath
val resource = migrationResourceNameForSchema(schema)
return possibleMigrationExtensions.map { "$resource$it" }.firstOrNull {
classLoader.getResource(it) != null
}
}
return "$MIGRATION_PREFIX/$declaredMigration.$DEFAULT_MIGRATION_EXTENSION"
}
// SchemaName will be transformed from camel case to lower_hyphen then add ".changelog-master"
private fun migrationResourceNameForSchema(schema: MappedSchema): String {
val name: String = schema::class.simpleName!!
val fileName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name)
return "$MIGRATION_PREFIX/$fileName.$CHANGELOG_NAME"
}
}

View File

@ -83,8 +83,6 @@ class CordaPersistence(
// Check not in read-only mode.
transaction {
check(!connection.metaData.isReadOnly) { "Database should not be readonly." }
checkCorrectAttachmentsContractsTableName(connection)
checkCorrectCheckpointTypeOnPostgres(connection)
}
}
@ -272,33 +270,3 @@ private fun Throwable.hasSQLExceptionCause(): Boolean =
}
class CouldNotCreateDataSourceException(override val message: String?, override val cause: Throwable? = null) : Exception()
class DatabaseIncompatibleException(override val message: String?, override val cause: Throwable? = null) : Exception()
private fun checkCorrectAttachmentsContractsTableName(connection: Connection) {
val correctName = "NODE_ATTACHMENTS_CONTRACTS"
val incorrectV30Name = "NODE_ATTACHMENTS_CONTRACT_CLASS_NAME"
val incorrectV31Name = "NODE_ATTCHMENTS_CONTRACTS"
fun warning(incorrectName: String, version: String) = "The database contains the older table name $incorrectName instead of $correctName, see upgrade notes to migrate from Corda database version $version https://docs.corda.net/head/upgrade-notes.html."
if (!connection.metaData.getTables(null, null, correctName, null).next()) {
if (connection.metaData.getTables(null, null, incorrectV30Name, null).next()) { throw DatabaseIncompatibleException(warning(incorrectV30Name, "3.0")) }
if (connection.metaData.getTables(null, null, incorrectV31Name, null).next()) { throw DatabaseIncompatibleException(warning(incorrectV31Name, "3.1")) }
}
}
private fun checkCorrectCheckpointTypeOnPostgres(connection: Connection) {
val metaData = connection.metaData
if (metaData.getDatabaseProductName() != "PostgreSQL") {
return
}
val result = metaData.getColumns(null, null, "node_checkpoints", "checkpoint_value")
if (result.next()) {
val type = result.getString("TYPE_NAME")
if (type != "bytea") {
throw DatabaseIncompatibleException("The type of the 'checkpoint_value' table must be 'bytea', but 'oid' was found. See upgrade notes to migrate from Corda database version 3.1 https://docs.corda.net/head/upgrade-notes.html.")
}
}
}

View File

@ -0,0 +1,181 @@
package net.corda.nodeapi.internal.persistence
import com.fasterxml.jackson.databind.ObjectMapper
import liquibase.Contexts
import liquibase.LabelExpression
import liquibase.Liquibase
import liquibase.database.Database
import liquibase.database.DatabaseFactory
import liquibase.database.jvm.JdbcConnection
import liquibase.resource.ClassLoaderResourceAccessor
import net.corda.nodeapi.internal.MigrationHelpers.getMigrationResource
import net.corda.core.schemas.MappedSchema
import net.corda.core.utilities.contextLogger
import java.io.ByteArrayInputStream
import java.io.InputStream
import java.io.Writer
import javax.sql.DataSource
class SchemaMigration(
val schemas: Set<MappedSchema>,
val dataSource: DataSource,
private val databaseConfig: DatabaseConfig,
private val classLoader: ClassLoader = Thread.currentThread().contextClassLoader) {
companion object {
private val logger = contextLogger()
}
/**
* Main entry point to the schema migration.
* Called during node startup.
*/
fun nodeStartup(existingCheckpoints: Boolean) {
when {
databaseConfig.initialiseSchema -> {
migrateOlderDatabaseToUseLiquibase(existingCheckpoints)
runMigration(existingCheckpoints)
}
else -> checkState()
}
}
/**
* Will run the Liquibase migration on the actual database.
*/
private fun runMigration(existingCheckpoints: Boolean) = doRunMigration(run = true, check = false, existingCheckpoints = existingCheckpoints)
/**
* Ensures that the database is up to date with the latest migration changes.
*/
private fun checkState() = doRunMigration(run = false, check = true)
/** Create a resourse accessor that aggregates the changelogs included in the schemas into one dynamic stream. */
private class CustomResourceAccessor(val dynamicInclude: String, val changelogList: List<String?>, classLoader: ClassLoader) : ClassLoaderResourceAccessor(classLoader) {
override fun getResourcesAsStream(path: String): Set<InputStream> {
if (path == dynamicInclude) {
// Create a map in Liquibase format including all migration files.
val includeAllFiles = mapOf("databaseChangeLog" to changelogList.filter { it != null }.map { file -> mapOf("include" to mapOf("file" to file)) })
// Transform it to json.
val includeAllFilesJson = ObjectMapper().writeValueAsBytes(includeAllFiles)
// Return the json as a stream.
return setOf(ByteArrayInputStream(includeAllFilesJson))
}
return super.getResourcesAsStream(path)?.take(1)?.toSet() ?: emptySet()
}
}
private fun doRunMigration(run: Boolean, check: Boolean, existingCheckpoints: Boolean? = null) {
// Virtual file name of the changelog that includes all schemas.
val dynamicInclude = "master.changelog.json"
dataSource.connection.use { connection ->
// Collect all changelog file referenced in the included schemas.
// For backward compatibility reasons, when failOnMigrationMissing=false, we don't manage CorDapps via Liquibase but use the hibernate hbm2ddl=update.
val changelogList = schemas.map { mappedSchema ->
val resource = getMigrationResource(mappedSchema, classLoader)
when {
resource != null -> resource
else -> throw MissingMigrationException(mappedSchema)
}
}
val customResourceAccessor = CustomResourceAccessor(dynamicInclude, changelogList, classLoader)
val liquibase = Liquibase(dynamicInclude, customResourceAccessor, getLiquibaseDatabase(JdbcConnection(connection)))
val unRunChanges = liquibase.listUnrunChangeSets(Contexts(), LabelExpression())
when {
(run && !check) && (unRunChanges.isNotEmpty() && existingCheckpoints!!) -> throw CheckpointsException() // Do not allow database migration when there are checkpoints
run && !check -> liquibase.update(Contexts())
check && !run && unRunChanges.isNotEmpty() -> throw OutstandingDatabaseChangesException(unRunChanges.size)
check && !run -> {} // Do nothing will be interpreted as "check succeeded"
else -> throw IllegalStateException("Invalid usage.")
}
}
}
private fun getLiquibaseDatabase(conn: JdbcConnection): Database {
return DatabaseFactory.getInstance().findCorrectDatabaseImplementation(conn)
}
/** For existing database created before verions 4.0 add Liquibase support - creates DATABASECHANGELOG and DATABASECHANGELOGLOCK tables and mark changesets are executed. */
private fun migrateOlderDatabaseToUseLiquibase(existingCheckpoints: Boolean): Boolean {
val isExistingDBWithoutLiquibase = dataSource.connection.use {
it.metaData.getTables(null, null, "NODE%", null).next() &&
!it.metaData.getTables(null, null, "DATABASECHANGELOG", null).next() &&
!it.metaData.getTables(null, null, "DATABASECHANGELOGLOCK", null).next()
}
when {
isExistingDBWithoutLiquibase && existingCheckpoints -> throw CheckpointsException()
isExistingDBWithoutLiquibase -> {
// Virtual file name of the changelog that includes all schemas.
val dynamicInclude = "master.changelog.json"
dataSource.connection.use { connection ->
// Schema migrations pre release 4.0
val preV4Baseline =
listOf("migration/common.changelog-init.xml",
"migration/node-info.changelog-init.xml",
"migration/node-info.changelog-v1.xml",
"migration/node-info.changelog-v2.xml",
"migration/node-core.changelog-init.xml",
"migration/node-core.changelog-v3.xml",
"migration/node-core.changelog-v4.xml",
"migration/node-core.changelog-v5.xml",
"migration/node-core.changelog-pkey.xml",
"migration/vault-schema.changelog-init.xml",
"migration/vault-schema.changelog-v3.xml",
"migration/vault-schema.changelog-v4.xml",
"migration/vault-schema.changelog-pkey.xml",
"migration/cash.changelog-init.xml",
"migration/cash.changelog-v1.xml",
"migration/commercial-paper.changelog-init.xml",
"migration/commercial-paper.changelog-v1.xml") +
if (schemas.any { schema -> schema.migrationResource == "node-notary.changelog-master" })
listOf("migration/node-notary.changelog-init.xml",
"migration/node-notary.changelog-v1.xml",
"migration/vault-schema.changelog-pkey.xml")
else emptyList()
val customResourceAccessor = CustomResourceAccessor(dynamicInclude, preV4Baseline, classLoader)
val liquibase = Liquibase(dynamicInclude, customResourceAccessor, getLiquibaseDatabase(JdbcConnection(connection)))
liquibase.changeLogSync(Contexts(), LabelExpression())
}
}
}
return isExistingDBWithoutLiquibase
}
}
open class DatabaseMigrationException(message: String) : IllegalArgumentException(message) {
override val message: String = super.message!!
}
class MissingMigrationException(@Suppress("MemberVisibilityCanBePrivate") val mappedSchema: MappedSchema) : DatabaseMigrationException(errorMessageFor(mappedSchema)) {
internal companion object {
fun errorMessageFor(mappedSchema: MappedSchema): String = "No migration defined for schema: ${mappedSchema.name} v${mappedSchema.version}"
}
}
class OutstandingDatabaseChangesException(@Suppress("MemberVisibilityCanBePrivate") private val count: Int) : DatabaseMigrationException(errorMessageFor(count)) {
internal companion object {
fun errorMessageFor(count: Int): String = "There are $count outstanding database changes that need to be run."
}
}
class CheckpointsException : DatabaseMigrationException("Attempting to update the database while there are flows in flight. " +
"This is dangerous because the node might not be able to restore the flows correctly and could consequently fail. " +
"Updating the database would make reverting to the previous version more difficult. " +
"Please drain your node first. See: https://docs.corda.net/upgrading-cordapps.html#flow-drains")
class DatabaseIncompatibleException(@Suppress("MemberVisibilityCanBePrivate") private val reason: String) : DatabaseMigrationException(errorMessageFor(reason)) {
internal companion object {
fun errorMessageFor(reason: String): String = "Incompatible database schema version detected, please run the node with configuration option database.initialiseSchema=true. Reason: $reason"
}
}

View File

@ -1,70 +0,0 @@
package net.corda.node.persistence
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.internal.packageName
import net.corda.core.messaging.startFlow
import net.corda.core.utilities.getOrThrow
import net.corda.node.services.Permissions
import net.corda.testMessage.Message
import net.corda.testMessage.MessageState
import net.corda.testing.core.singleIdentity
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.driver
import net.corda.testing.node.User
import org.junit.Test
import java.nio.file.Path
import java.sql.DriverManager
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class FailNodeOnNotMigratedAttachmentContractsTableNameTests {
@Test
fun `node fails when detecting table name not migrated from version 3 dot 0`() {
`node fails when not detecting compatible table name`("NODE_ATTACHMENTS_CONTRACTS", "NODE_ATTACHMENTS_CONTRACT_CLASS_NAME")
}
@Test
fun `node fails when detecting table name not migrated from version 3 dot 1`() {
`node fails when not detecting compatible table name`("NODE_ATTACHMENTS_CONTRACTS", "NODE_ATTCHMENTS_CONTRACTS")
}
private fun `node fails when not detecting compatible table name`(tableNameFromMapping: String, tableNameInDB: String) {
val user = User("mark", "dadada", setOf(Permissions.startFlow<SendMessageFlow>(), Permissions.invokeRpc("vaultQuery")))
val message = Message("Hello world!")
val baseDir: Path = driver(DriverParameters(
inMemoryDB = false,
startNodesInProcess = isQuasarAgentSpecified(),
extraCordappPackagesToScan = listOf(MessageState::class.packageName)
)) {
val (nodeName, baseDir) = {
val nodeHandle = startNode(rpcUsers = listOf(user)).getOrThrow()
val nodeName = nodeHandle.nodeInfo.singleIdentity().name
CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use {
it.proxy.startFlow(::SendMessageFlow, message, defaultNotaryIdentity).returnValue.getOrThrow()
}
nodeHandle.stop()
Pair(nodeName, nodeHandle.baseDirectory)
}()
// replace the correct table name with one from the former release
DriverManager.getConnection("jdbc:h2:file://$baseDir/persistence", "sa", "").use {
it.createStatement().execute("ALTER TABLE $tableNameFromMapping RENAME TO $tableNameInDB")
it.commit()
}
assertFailsWith(net.corda.nodeapi.internal.persistence.DatabaseIncompatibleException::class) {
val nodeHandle = startNode(providedName = nodeName, rpcUsers = listOf(user)).getOrThrow()
nodeHandle.stop()
}
baseDir
}
// check that the node didn't recreated the correct table matching it's entity mapping
val (hasTableFromMapping, hasTableFromDB) = DriverManager.getConnection("jdbc:h2:file://$baseDir/persistence", "sa", "").use {
Pair(it.metaData.getTables(null, null, tableNameFromMapping, null).next(),
it.metaData.getTables(null, null, tableNameInDB, null).next())
}
assertFalse(hasTableFromMapping)
assertTrue(hasTableFromDB)
}
}

View File

@ -25,6 +25,7 @@ import net.corda.core.internal.uncheckedCast
import net.corda.core.messaging.*
import net.corda.core.node.*
import net.corda.core.node.services.*
import net.corda.core.schemas.MappedSchema
import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.serialization.SerializeAsToken
import net.corda.core.serialization.SingletonSerializeAsToken
@ -66,10 +67,7 @@ import net.corda.nodeapi.internal.DevIdentityGenerator
import net.corda.nodeapi.internal.NodeInfoAndSigned
import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.CouldNotCreateDataSourceException
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.nodeapi.internal.persistence.DatabaseIncompatibleException
import net.corda.nodeapi.internal.persistence.*
import net.corda.nodeapi.internal.storeLegalIdentity
import net.corda.tools.shell.InteractiveShell
import org.apache.activemq.artemis.utils.ReusableLatch
@ -732,7 +730,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
protected open fun startDatabase() {
val props = configuration.dataSourceProperties
if (props.isEmpty) throw DatabaseConfigurationException("There must be a database configured.")
database.startHikariPool(props)
database.startHikariPool(props, configuration.database, schemaService.internalSchemas())
// Now log the vendor string as this will also cause a connection to be tested eagerly.
logVendorString(database, log)
}
@ -993,9 +991,10 @@ fun configureDatabase(hikariProperties: Properties,
databaseConfig: DatabaseConfig,
wellKnownPartyFromX500Name: (CordaX500Name) -> Party?,
wellKnownPartyFromAnonymous: (AbstractParty) -> Party?,
schemaService: SchemaService = NodeSchemaService()): CordaPersistence {
schemaService: SchemaService = NodeSchemaService(),
internalSchemas: Set<MappedSchema> = NodeSchemaService().internalSchemas()): CordaPersistence {
val persistence = createCordaPersistence(databaseConfig, wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous, schemaService, hikariProperties)
persistence.startHikariPool(hikariProperties)
persistence.startHikariPool(hikariProperties, databaseConfig, internalSchemas)
return persistence
}
@ -1014,14 +1013,17 @@ fun createCordaPersistence(databaseConfig: DatabaseConfig,
return CordaPersistence(databaseConfig, schemaService.schemaOptions.keys, jdbcUrl, attributeConverters)
}
fun CordaPersistence.startHikariPool(hikariProperties: Properties) {
fun CordaPersistence.startHikariPool(hikariProperties: Properties, databaseConfig: DatabaseConfig, schemas: Set<MappedSchema>) {
try {
start(DataSourceFactory.createDataSource(hikariProperties))
val dataSource = DataSourceFactory.createDataSource(hikariProperties)
val schemaMigration = SchemaMigration(schemas, dataSource, databaseConfig)
schemaMigration.nodeStartup(dataSource.connection.use { DBCheckpointStorage().getCheckpointCount(it) != 0L })
start(dataSource)
} catch (ex: Exception) {
when {
ex is HikariPool.PoolInitializationException -> throw CouldNotCreateDataSourceException("Could not connect to the database. Please check your JDBC connection URL, or the connectivity to the database.", ex)
ex.cause is ClassNotFoundException -> throw CouldNotCreateDataSourceException("Could not find the database driver class. Please add it to the 'drivers' folder. See: https://docs.corda.net/corda-configuration-file.html")
ex is DatabaseIncompatibleException -> throw ex
ex is OutstandingDatabaseChangesException -> throw (DatabaseIncompatibleException(ex.message))
else -> throw CouldNotCreateDataSourceException("Could not create the DataSource: ${ex.message}", ex)
}
}

View File

@ -19,6 +19,8 @@ object NodeInfoSchemaV1 : MappedSchema(
version = 1,
mappedTypes = listOf(PersistentNodeInfo::class.java, DBPartyAndCertificate::class.java, DBHostAndPort::class.java, NodePropertiesPersistentStore.DBNodeProperty::class.java)
) {
override val migrationResource = "node-info.changelog-master"
@Entity
@Table(name = "node_infos")
class PersistentNodeInfo(

View File

@ -1,9 +1,9 @@
package net.corda.node.services.api
import net.corda.core.cordapp.Cordapp
import net.corda.core.flows.StateMachineRunId
import net.corda.core.serialization.SerializedBytes
import net.corda.node.services.statemachine.Checkpoint
import java.sql.Connection
import java.util.stream.Stream
/**
@ -20,7 +20,6 @@ interface CheckpointStorage {
*/
fun updateCheckpoint(id: StateMachineRunId, checkpoint: SerializedBytes<Checkpoint>)
/**
* Remove existing checkpoint from the store.
* @return whether the id matched a checkpoint that was removed.
@ -38,4 +37,12 @@ interface CheckpointStorage {
* underlying database connection is closed, so any processing should happen before it is closed.
*/
fun getAllCheckpoints(): Stream<Pair<StateMachineRunId, SerializedBytes<Checkpoint>>>
/**
* This needs to run before Hibernate is initialised.
*
* @param connection The SQL Connection.
* @return the number of checkpoints stored in the database.
*/
fun getCheckpointCount(connection: Connection): Long
}

View File

@ -16,6 +16,8 @@ import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.Id
import org.hibernate.annotations.Type
import java.sql.Connection
import java.sql.SQLException
/**
* Simple checkpoint key value storage in DB.
@ -75,4 +77,18 @@ class DBCheckpointStorage : CheckpointStorage {
StateMachineRunId(UUID.fromString(it.checkpointId)) to SerializedBytes<Checkpoint>(it.checkpoint)
}
}
override fun getCheckpointCount(connection: Connection): Long =
try {
connection.prepareStatement("select count(*) from node_checkpoints").use { ps ->
ps.executeQuery().use { rs ->
rs.next()
rs.getLong(1)
}
}
} catch (e: SQLException) {
// Happens when the table was not created yet.
0L
}
}

View File

@ -29,7 +29,7 @@ import net.corda.node.services.vault.VaultSchemaV1
* TODO: support plugins for schema version upgrading or custom mapping not supported by original [QueryableState].
* TODO: create whitelisted tables when a CorDapp is first installed
*/
class NodeSchemaService(extraSchemas: Set<MappedSchema> = emptySet(), includeNotarySchemas: Boolean = false) : SchemaService, SingletonSerializeAsToken() {
class NodeSchemaService(private val extraSchemas: Set<MappedSchema> = emptySet(), includeNotarySchemas: Boolean = false) : SchemaService, SingletonSerializeAsToken() {
// Core Entities used by a Node
object NodeCore
@ -43,7 +43,9 @@ class NodeSchemaService(extraSchemas: Set<MappedSchema> = emptySet(), includeNot
PersistentIdentityService.PersistentIdentity::class.java,
PersistentIdentityService.PersistentIdentityNames::class.java,
ContractUpgradeServiceImpl.DBContractUpgrade::class.java
))
)) {
override val migrationResource = "node-core.changelog-master"
}
// Entities used by a Notary
object NodeNotary
@ -54,17 +56,22 @@ class NodeSchemaService(extraSchemas: Set<MappedSchema> = emptySet(), includeNot
PersistentUniquenessProvider.CommittedState::class.java,
RaftUniquenessProvider.CommittedState::class.java,
BFTNonValidatingNotaryService.CommittedState::class.java
))
)) {
override val migrationResource = "node-notary.changelog-master"
}
// Required schemas are those used by internal Corda services
private val requiredSchemas: Map<MappedSchema, SchemaService.SchemaOptions> =
mapOf(Pair(CommonSchemaV1, SchemaOptions()),
Pair(VaultSchemaV1, SchemaOptions()),
Pair(NodeInfoSchemaV1, SchemaOptions()),
Pair(NodeCoreV1, SchemaOptions()))
private val notarySchemas = if (includeNotarySchemas) mapOf(Pair(NodeNotaryV1, SchemaOptions())) else emptyMap<MappedSchema, SchemaService.SchemaOptions>()
Pair(NodeCoreV1, SchemaOptions())) +
if (includeNotarySchemas) mapOf(Pair(NodeNotaryV1, SchemaOptions())) else emptyMap()
override val schemaOptions: Map<MappedSchema, SchemaService.SchemaOptions> = requiredSchemas + notarySchemas + extraSchemas.associateBy({ it }, { SchemaOptions() })
fun internalSchemas() = requiredSchemas.keys + extraSchemas.filter { schema -> // when mapped schemas from the finance module are present, they are considered as internal ones
schema::class.simpleName == "net.corda.finance.schemas.CashSchemaV1" || schema::class.simpleName == "net.corda.finance.schemas.CommercialPaperSchemaV1" }
override val schemaOptions: Map<MappedSchema, SchemaService.SchemaOptions> = requiredSchemas + extraSchemas.associateBy({ it }, { SchemaOptions() })
// Currently returns all schemas supported by the state, with no filtering or enrichment.
override fun selectSchemas(state: ContractState): Iterable<MappedSchema> {

View File

@ -26,6 +26,9 @@ object VaultSchema
@CordaSerializable
object VaultSchemaV1 : MappedSchema(schemaFamily = VaultSchema.javaClass, version = 1,
mappedTypes = listOf(VaultStates::class.java, VaultLinearStates::class.java, VaultFungibleStates::class.java, VaultTxnNote::class.java)) {
override val migrationResource = "vault-schema.changelog-master"
@Entity
@Table(name = "vault_states", indexes = [Index(name = "state_status_idx", columnList = "state_status"), Index(name = "lock_id_idx", columnList = "lock_id, state_status")])
class VaultStates(

View File

@ -0,0 +1,16 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="1511451595465-1.1" dbms="h2">
<createSequence sequenceName="hibernate_sequence"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-1.3" onValidationFail="MARK_RAN">
<preConditions onFail="MARK_RAN" onSqlOutput="TEST"> <not> <dbms type="h2"/> </not> </preConditions>
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,9 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<include file="migration/common.changelog-init.xml"/>
</databaseChangeLog>

View File

@ -0,0 +1,158 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"
logicalFilePath="migration/node-services.changelog-init.xml">
<changeSet author="R3.Corda" id="1511451595465-5">
<createTable tableName="node_attachments">
<column name="att_id" type="NVARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="content" type="blob"/>
<column name="filename" type="NVARCHAR(255)"/>
<column name="insertion_date" type="timestamp">
<constraints nullable="false"/>
</column>
<column name="uploader" type="NVARCHAR(255)"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-7">
<createTable tableName="node_checkpoints">
<column name="checkpoint_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="checkpoint_value" type="blob"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-8">
<createTable tableName="node_contract_upgrades">
<column name="state_ref" type="NVARCHAR(96)">
<constraints nullable="false"/>
</column>
<column name="contract_class_name" type="NVARCHAR(255)"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-9">
<createTable tableName="node_identities">
<column name="pk_hash" type="NVARCHAR(130)">
<constraints nullable="false"/>
</column>
<column name="identity_value" type="blob"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-13">
<createTable tableName="node_message_ids">
<column name="message_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="insertion_time" type="timestamp"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-14">
<createTable tableName="node_message_retry">
<column name="message_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="message" type="blob"/>
<column name="recipients" type="blob"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-15">
<createTable tableName="node_named_identities">
<column name="name" type="NVARCHAR(128)">
<constraints nullable="false"/>
</column>
<column name="pk_hash" type="NVARCHAR(130)"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-17">
<createTable tableName="node_our_key_pairs">
<column name="public_key_hash" type="NVARCHAR(130)">
<constraints nullable="false"/>
</column>
<column name="private_key" type="blob"/>
<column name="public_key" type="blob"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-19">
<createTable tableName="node_scheduled_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="scheduled_at" type="timestamp">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-20">
<createTable tableName="node_transaction_mappings">
<column name="tx_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="state_machine_run_id" type="NVARCHAR(36)"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-21">
<createTable tableName="node_transactions">
<column name="tx_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="transaction_value" type="blob"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-30">
<addPrimaryKey columnNames="att_id" constraintName="node_attachments_pkey" tableName="node_attachments"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-32">
<addPrimaryKey columnNames="checkpoint_id" constraintName="node_checkpoints_pkey" tableName="node_checkpoints"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-33">
<addPrimaryKey columnNames="state_ref" constraintName="node_contract_upgrades_pkey"
tableName="node_contract_upgrades"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-34">
<addPrimaryKey columnNames="pk_hash" constraintName="node_identities_pkey" tableName="node_identities"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-38">
<addPrimaryKey columnNames="message_id" constraintName="node_message_ids_pkey" tableName="node_message_ids"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-39">
<addPrimaryKey columnNames="message_id" constraintName="node_message_retry_pkey"
tableName="node_message_retry"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-40">
<addPrimaryKey columnNames="name" constraintName="node_named_identities_pkey"
tableName="node_named_identities"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-42">
<addPrimaryKey columnNames="public_key_hash" constraintName="node_our_key_pairs_pkey"
tableName="node_our_key_pairs"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-44">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="node_scheduled_states_pkey"
tableName="node_scheduled_states"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-45">
<addPrimaryKey columnNames="tx_id" constraintName="node_transaction_mappings_pkey"
tableName="node_transaction_mappings"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-46">
<addPrimaryKey columnNames="tx_id" constraintName="node_transactions_pkey" tableName="node_transactions"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-61">
<addForeignKeyConstraint baseColumnNames="party_name" baseTableName="node_link_nodeinfo_party"
constraintName="FK__link_ni_p__info_p_cert"
referencedColumnNames="party_name" referencedTableName="node_info_party_cert"/>
</changeSet>
<changeSet author="R3.Corda" id="add index att_id">
<createIndex tableName="node_attachments" indexName="att_id_idx">
<column name="att_id"/>
</createIndex>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,16 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<include file="migration/node-core.changelog-init.xml"/>
<include file="migration/node-core.changelog-v3.xml"/>
<include file="migration/node-core.changelog-v4.xml"/>
<include file="migration/node-core.changelog-v5.xml"/>
<include file="migration/node-core.changelog-pkey.xml"/>
<include file="migration/node-core.changelog-postgres-blob.xml"/>
<include file="migration/node-core.changelog-v8.xml"/>
<include file="migration/node-core.changelog-tx-mapping.xml"/>
</databaseChangeLog>

View File

@ -0,0 +1,41 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet id="non-clustered_pk-1" author="R3.Corda" onValidationFail="MARK_RAN">
<dropPrimaryKey tableName="node_checkpoints" constraintName="node_checkpoints_pkey"/>
<addPrimaryKey tableName="node_checkpoints" columnNames="checkpoint_id" constraintName="node_checkpoints_pkey"
clustered="false"/>
</changeSet>
<changeSet id="non-clustered_pk-2" author="R3.Corda" onValidationFail="MARK_RAN">
<dropPrimaryKey tableName="node_identities" constraintName="node_identities_pkey"/>
<addPrimaryKey tableName="node_identities" columnNames="pk_hash" constraintName="node_identities_pkey"
clustered="false"/>
</changeSet>
<changeSet id="non-clustered_pk-3" author="R3.Corda" onValidationFail="MARK_RAN">
<dropPrimaryKey tableName="node_message_ids" constraintName="node_message_ids_pkey"/>
<addPrimaryKey tableName="node_message_ids" columnNames="message_id" constraintName="node_message_ids_pkey"
clustered="false"/>
</changeSet>
<changeSet id="non-clustered_pk-4" author="R3.Corda" onValidationFail="MARK_RAN">
<dropPrimaryKey tableName="node_named_identities" constraintName="node_named_identities_pkey"/>
<addPrimaryKey tableName="node_named_identities" columnNames="name" constraintName="node_named_identities_pkey"
clustered="false"/>
</changeSet>
<changeSet id="non-clustered_pk-5" author="R3.Corda" onValidationFail="MARK_RAN">
<dropPrimaryKey tableName="node_our_key_pairs" constraintName="node_our_key_pairs_pkey"/>
<addPrimaryKey tableName="node_our_key_pairs" columnNames="public_key_hash"
constraintName="node_our_key_pairs_pkey" clustered="false"/>
</changeSet>
<changeSet id="non-clustered_pk-6" author="R3.Corda" onValidationFail="MARK_RAN">
<dropPrimaryKey tableName="node_transaction_mappings" constraintName="node_transaction_mappings_pkey"/>
<addPrimaryKey tableName="node_transaction_mappings" columnNames="tx_id"
constraintName="node_transaction_mappings_pkey" clustered="false"/>
</changeSet>
<changeSet id="non-clustered_pk-7" author="R3.Corda" onValidationFail="MARK_RAN">
<dropPrimaryKey tableName="node_transactions" constraintName="node_transactions_pkey"/>
<addPrimaryKey tableName="node_transactions" columnNames="tx_id" constraintName="node_transactions_pkey"
clustered="false"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,25 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="modify checkpoint_value column type" dbms="postgresql">
<preConditions onFail="MARK_RAN">
<not>
<sqlCheck expectedResult="bytea">
SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'node_checkpoints' AND COLUMN_NAME = 'checkpoint_value'
</sqlCheck>
</not>
</preConditions>
<dropColumn tableName="node_checkpoints" columnName="checkpoint_value"/>
<addColumn tableName="node_checkpoints">
<column name="checkpoint_value" type="varbinary(33554432)">
<constraints nullable="false"/>
</column>
</addColumn>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,17 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="add_tx_mapping_column">
<addColumn tableName="node_transactions">
<column name="state_machine_run_id" type="NVARCHAR(36)">
<constraints nullable="true"/>
</column>
</addColumn>
<!-- Copy old values from the table to the new column -->
<sql>update node_transactions set state_machine_run_id=(select state_machine_run_id from
node_transaction_mappings where node_transactions.tx_id = node_transaction_mappings.tx_id)
</sql>
<dropTable tableName="node_transaction_mappings"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,30 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"
logicalFilePath="migration/node-services.changelog-init.xml">
<changeSet author="R3.Corda" id="add_contract_attachment">
<createTable tableName="node_attchments_contracts">
<column name="att_id" type="NVARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="contract_class_name" type="NVARCHAR(255)"/>
</createTable>
<addForeignKeyConstraint baseColumnNames="att_id" baseTableName="node_attchments_contracts"
constraintName="FK__ctr_class__attachments"
referencedColumnNames="att_id" referencedTableName="node_attachments"/>
<!--this is needed because pre-v3 attachments can't be used-->
<delete tableName="node_attachments"/>
</changeSet>
<changeSet author="R3.Corda" id="add_dedup_columns">
<addColumn tableName="node_message_ids">
<column name="sender" type="NVARCHAR(64)"/>
<column name="sequence_number" type="BIGINT"/>
</addColumn>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,37 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="attchments_rename">
<renameTable oldTableName="node_attchments_contracts" newTableName="node_attachments_contracts" />
</changeSet>
<changeSet author="R3.Corda" id="nullability">
<addNotNullConstraint tableName="node_identities" columnName="identity_value" columnDataType="blob" />
<addNotNullConstraint tableName="node_attachments" columnName="content" columnDataType="blob"/>
<addNotNullConstraint tableName="node_attachments_contracts" columnName="contract_class_name" columnDataType="NVARCHAR(255)"/>
<addNotNullConstraint tableName="node_checkpoints" columnName="checkpoint_value" columnDataType="blob"/>
<addNotNullConstraint tableName="node_contract_upgrades" columnName="contract_class_name" columnDataType="NVARCHAR(255)"/>
<addNotNullConstraint tableName="node_message_ids" columnName="insertion_time" columnDataType="timestamp"/>
<addNotNullConstraint tableName="node_message_retry" columnName="message" columnDataType="blob"/>
<addNotNullConstraint tableName="node_message_retry" columnName="recipients" columnDataType="blob"/>
<addNotNullConstraint tableName="node_named_identities" columnName="pk_hash" columnDataType="NVARCHAR(130)"/>
<addNotNullConstraint tableName="node_our_key_pairs" columnName="private_key" columnDataType="blob"/>
<addNotNullConstraint tableName="node_our_key_pairs" columnName="public_key" columnDataType="blob"/>
<addNotNullConstraint tableName="node_transaction_mappings" columnName="state_machine_run_id" columnDataType="NVARCHAR(36)"/>
<addNotNullConstraint tableName="node_transactions" columnName="transaction_value" columnDataType="blob"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="remove_unused_node_message_retry">
<dropTable tableName="node_message_retry"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,17 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="conditional_attchments_rename">
<preConditions onFail="MARK_RAN"><tableExists tableName="NODE_ATTCHMENTS_CONTRACTS"/></preConditions>
<renameTable oldTableName="NODE_ATTCHMENTS_CONTRACTS" newTableName="NODE_ATTACHMENTS_CONTRACTS" />
</changeSet>
<changeSet author="R3.Corda" id="conditional_attchments_contracts">
<preConditions onFail="MARK_RAN"><tableExists tableName="NODE_ATTACHMENTS_CONTRACT_CLASS_NAME"/></preConditions>
<renameTable oldTableName="NODE_ATTACHMENTS_CONTRACT_CLASS_NAME" newTableName="NODE_ATTACHMENTS_CONTRACTS" />
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,84 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="1511451595465-4">
<createTable tableName="node_link_nodeinfo_party">
<column name="node_info_id" type="INT">
<constraints nullable="false"/>
</column>
<column name="party_name" type="NVARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-10">
<createTable tableName="node_info_hosts">
<column name="host" type="NVARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="port" type="INT">
<constraints nullable="false"/>
</column>
<column name="node_info_id" type="INT"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-11">
<createTable tableName="node_info_party_cert">
<column name="party_name" type="NVARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="ismain" type="BOOLEAN">
<constraints nullable="false"/>
</column>
<column name="owning_key_hash" type="NVARCHAR(130)"/>
<column name="party_cert_binary" type="blob"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-12">
<createTable tableName="node_infos">
<column name="node_info_id" type="INT">
<constraints nullable="false"/>
</column>
<column name="node_info_hash" type="NVARCHAR(64)"/>
<column name="platform_version" type="INT"/>
<column name="serial" type="BIGINT"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-35">
<addPrimaryKey columnNames="host, port" constraintName="node_info_hosts_pkey" tableName="node_info_hosts"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-36">
<addPrimaryKey columnNames="party_name" constraintName="node_info_party_cert_pkey"
tableName="node_info_party_cert"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-37">
<addPrimaryKey columnNames="node_info_id" constraintName="node_infos_pkey" tableName="node_infos"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-62">
<addForeignKeyConstraint baseColumnNames="node_info_id" baseTableName="node_link_nodeinfo_party"
constraintName="FK__link_nodeinfo_party__infos"
referencedColumnNames="node_info_id" referencedTableName="node_infos"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-63">
<addForeignKeyConstraint baseColumnNames="node_info_id" baseTableName="node_info_hosts"
constraintName="FK__info_hosts__infos"
referencedColumnNames="node_info_id" referencedTableName="node_infos"/>
</changeSet>
<changeSet author="R3.Corda" id="remove_host_port_pk">
<!--Delete, in fact, truncates the table-->
<delete tableName="node_infos"/>
<delete tableName="node_link_nodeinfo_party"/>
<delete tableName="node_info_hosts"/>
<delete tableName="node_info_party_cert"/>
<dropPrimaryKey tableName="node_info_hosts" constraintName="node_info_hosts_pkey"/>
<addColumn tableName="node_info_hosts">
<column name="hosts_id" type="INT">
<constraints nullable="false"/>
</column>
</addColumn>
<addPrimaryKey columnNames="hosts_id" constraintName="node_info_hosts_pkey_id" tableName="node_info_hosts"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,11 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<include file="migration/node-info.changelog-init.xml"/>
<include file="migration/node-info.changelog-v1.xml"/>
<include file="migration/node-info.changelog-v2.xml"/>
</databaseChangeLog>

View File

@ -0,0 +1,14 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="key/value node properties table">
<createTable tableName="node_properties">
<column name="property_key" type="NVARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="property_value" type="NVARCHAR(255)"/>
</createTable>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,17 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="1525962920">
<addNotNullConstraint tableName="node_infos" columnName="node_info_hash" columnDataType="NVARCHAR(64)"/>
<addNotNullConstraint tableName="node_infos" columnName="platform_version" columnDataType="INT"/>
<addNotNullConstraint tableName="node_infos" columnName="serial" columnDataType="BIGINT"/>
<dropNotNullConstraint tableName="node_info_hosts" columnName="host" columnDataType="NVARCHAR(255)" />
<dropNotNullConstraint tableName="node_info_hosts" columnName="port" columnDataType="INT" />
<addNotNullConstraint tableName="node_info_party_cert" columnName="owning_key_hash" columnDataType="NVARCHAR(130)"/>
<addNotNullConstraint tableName="node_info_party_cert" columnName="party_cert_binary" columnDataType="blob"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,77 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"
logicalFilePath="migration/node-services.changelog-init.xml">
<changeSet author="R3.Corda" id="1511451595465-6">
<createTable tableName="node_bft_committed_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="consuming_transaction_id" type="NVARCHAR(64)"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-16">
<createTable tableName="node_notary_committed_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="consuming_transaction_id" type="NVARCHAR(64)"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-18">
<createTable tableName="node_raft_committed_states">
<column name="transaction_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="raft_log_index" type="BIGINT"/>
<column name="consuming_transaction_id" type="NVARCHAR(64)"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1521131680317-17">
<createTable tableName="node_notary_request_log">
<column name="id" type="INT">
<constraints nullable="false"/>
</column>
<column name="consuming_transaction_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="requesting_party_name" type="NVARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="request_timestamp" type="TIMESTAMP">
<constraints nullable="false"/>
</column>
<column name="request_signature" type="BLOB">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-31">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="node_bft_states_pkey"
tableName="node_bft_committed_states"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-41">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="node_notary_states_pkey"
tableName="node_notary_committed_states"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-43">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="node_raft_state_pkey"
tableName="node_raft_committed_states"/>
</changeSet>
<changeSet author="R3.Corda" id="1521131680317-48">
<addPrimaryKey columnNames="id" constraintName="node_notary_request_log_pkey"
tableName="node_notary_request_log"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,12 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<include file="migration/node-notary.changelog-init.xml"/>
<include file="migration/node-notary.changelog-v1.xml"/>
<include file="migration/node-notary.changelog-pkey.xml"/>
</databaseChangeLog>

View File

@ -0,0 +1,21 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet id="non-clustered_pk-notary_state" author="R3.Corda" onValidationFail="MARK_RAN">
<dropPrimaryKey tableName="node_notary_committed_states" constraintName="node_notary_states_pkey"/>
<addPrimaryKey tableName="node_notary_committed_states" columnNames="output_index, transaction_id"
constraintName="node_notary_states_pkey" clustered="false"/>
</changeSet>
<changeSet id="non-clustered_pk-bft_stae" author="R3.Corda" onValidationFail="MARK_RAN">
<dropPrimaryKey tableName="node_bft_committed_states" constraintName="node_bft_states_pkey"/>
<addPrimaryKey tableName="node_bft_committed_states" columnNames="output_index, transaction_id"
constraintName="node_bft_states_pkey" clustered="false"/>
</changeSet>
<changeSet id="non-clustered_pk-raft_state" author="R3.Corda" onValidationFail="MARK_RAN">
<dropPrimaryKey tableName="node_raft_committed_states" constraintName="node_raft_state_pkey"/>
<addPrimaryKey tableName="node_raft_committed_states" columnNames="output_index, transaction_id"
constraintName="node_raft_state_pkey" clustered="false"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,16 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"
logicalFilePath="migration/node-services.changelog-init.xml">
<changeSet author="R3.Corda" id="nullability">
<addNotNullConstraint tableName="node_bft_committed_states" columnName="consuming_transaction_id" columnDataType="NVARCHAR(64)"/>
<addNotNullConstraint tableName="node_notary_committed_states" columnName="consuming_transaction_id" columnDataType="NVARCHAR(64)"/>
<addNotNullConstraint tableName="node_raft_committed_states" columnName="raft_log_index" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="node_raft_committed_states" columnName="consuming_transaction_id" columnDataType="NVARCHAR(64)"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,138 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="1511451595465-22">
<createTable tableName="vault_fungible_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="issuer_name" type="NVARCHAR(255)"/>
<column name="issuer_ref" type="varbinary(512)"/>
<column name="owner_name" type="NVARCHAR(255)"/>
<column name="quantity" type="BIGINT"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-23">
<createTable tableName="vault_fungible_states_parts">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="participants" type="NVARCHAR(255)"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-24">
<createTable tableName="vault_linear_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="external_id" type="NVARCHAR(255)"/>
<column name="uuid" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-25">
<createTable tableName="vault_linear_states_parts">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="participants" type="NVARCHAR(255)"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-26">
<createTable tableName="vault_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="consumed_timestamp" type="timestamp"/>
<column name="contract_state_class_name" type="NVARCHAR(255)"/>
<column name="lock_id" type="NVARCHAR(255)"/>
<column name="lock_timestamp" type="timestamp"/>
<column name="notary_name" type="NVARCHAR(255)"/>
<column name="recorded_timestamp" type="timestamp"/>
<column name="state_status" type="INT"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-27">
<createTable tableName="vault_transaction_notes">
<column name="seq_no" type="INT">
<constraints nullable="false"/>
</column>
<column name="note" type="NVARCHAR(255)"/>
<column name="transaction_id" type="NVARCHAR(64)"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-47">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="vault_fungible_states_pkey"
tableName="vault_fungible_states"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-48">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="vault_linear_states_pkey"
tableName="vault_linear_states"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-49">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="vault_states_pkey"
tableName="vault_states"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-50">
<addPrimaryKey columnNames="seq_no" constraintName="vault_transaction_notes_pkey"
tableName="vault_transaction_notes"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-53">
<createIndex indexName="external_id_index" tableName="vault_linear_states">
<column name="external_id"/>
</createIndex>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-55">
<createIndex indexName="lock_id_idx" tableName="vault_states">
<column name="lock_id"/>
<column name="state_status"/>
</createIndex>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-58">
<createIndex indexName="state_status_idx" tableName="vault_states">
<column name="state_status"/>
</createIndex>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-59">
<createIndex indexName="transaction_id_index" tableName="vault_transaction_notes">
<column name="transaction_id"/>
</createIndex>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-60">
<createIndex indexName="uuid_index" tableName="vault_linear_states">
<column name="uuid"/>
</createIndex>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-64">
<addForeignKeyConstraint baseColumnNames="output_index,transaction_id"
baseTableName="vault_fungible_states_parts"
constraintName="FK__fung_st_parts__fung_st"
referencedColumnNames="output_index,transaction_id"
referencedTableName="vault_fungible_states"/>
</changeSet>
<changeSet author="R3.Corda" id="1511451595465-65">
<addForeignKeyConstraint baseColumnNames="output_index,transaction_id" baseTableName="vault_linear_states_parts"
constraintName="FK__lin_stat_parts__lin_stat"
referencedColumnNames="output_index,transaction_id"
referencedTableName="vault_linear_states"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,12 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<include file="migration/vault-schema.changelog-init.xml"/>
<include file="migration/vault-schema.changelog-v3.xml"/>
<include file="migration/vault-schema.changelog-v4.xml"/>
<include file="migration/vault-schema.changelog-pkey.xml"/>
<include file="migration/vault-schema.changelog-v5.xml"/>
</databaseChangeLog>

View File

@ -0,0 +1,35 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet id="non-clustered_pk-11" author="R3.Corda" onValidationFail="MARK_RAN">
<dropForeignKeyConstraint baseTableName="vault_fungible_states_parts" constraintName="FK__fung_st_parts__fung_st"/>
<dropPrimaryKey tableName="vault_fungible_states" constraintName="vault_fungible_states_pkey"/>
<addPrimaryKey tableName="vault_fungible_states" columnNames="output_index, transaction_id"
constraintName="vault_fungible_states_pkey" clustered="false"/>
<addForeignKeyConstraint baseColumnNames="output_index,transaction_id"
baseTableName="vault_fungible_states_parts"
constraintName="FK__fung_st_parts__fung_st"
referencedColumnNames="output_index,transaction_id"
referencedTableName="vault_fungible_states"/>
</changeSet>
<changeSet id="non-clustered_pk-12" author="R3.Corda" onValidationFail="MARK_RAN">
<dropForeignKeyConstraint baseTableName="vault_linear_states_parts" constraintName="FK__lin_stat_parts__lin_stat"/>
<dropPrimaryKey tableName="vault_linear_states" constraintName="vault_linear_states_pkey"/>
<addPrimaryKey tableName="vault_linear_states" columnNames="output_index, transaction_id"
constraintName="vault_linear_states_pkey" clustered="false"/>
<addForeignKeyConstraint baseColumnNames="output_index,transaction_id" baseTableName="vault_linear_states_parts"
constraintName="FK__lin_stat_parts__lin_stat"
referencedColumnNames="output_index,transaction_id"
referencedTableName="vault_linear_states"/>
</changeSet>
<changeSet id="non-clustered_pk-13" author="R3.Corda" onValidationFail="MARK_RAN">
<dropPrimaryKey tableName="vault_states" constraintName="vault_states_pkey"/>
<addPrimaryKey tableName="vault_states" columnNames="output_index, transaction_id"
constraintName="vault_states_pkey" clustered="false"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,16 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<!--this is needed because pre-v3 states are no longer supported-->
<changeSet author="R3.Corda" id="clean_vault">
<delete tableName="vault_fungible_states_parts"/>
<delete tableName="vault_fungible_states"/>
<delete tableName="vault_linear_states_parts"/>
<delete tableName="vault_linear_states"/>
<delete tableName="vault_states"/>
<delete tableName="vault_transaction_notes"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,33 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<!--this is needed because pre-v3 states are no longer supported-->
<changeSet author="R3.Corda" id="nullability">
<addNotNullConstraint tableName="vault_fungible_states" columnName="quantity" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="vault_states" columnName="contract_state_class_name" columnDataType="NVARCHAR(255)"/>
<addNotNullConstraint tableName="vault_states" columnName="notary_name" columnDataType="NVARCHAR(255)"/>
<addNotNullConstraint tableName="vault_states" columnName="recorded_timestamp" columnDataType="timestamp"/>
<!-- drop indexes before adding not null constraints to the underlying table, recreating index immediately after -->
<dropIndex indexName="state_status_idx" tableName="vault_states"/>
<dropIndex indexName="lock_id_idx" tableName="vault_states"/>
<addNotNullConstraint tableName="vault_states" columnName="state_status" columnDataType="INT"/>
<createIndex indexName="state_status_idx" tableName="vault_states">
<column name="state_status"/>
</createIndex>
<createIndex indexName="lock_id_idx" tableName="vault_states">
<column name="lock_id"/>
<column name="state_status"/>
</createIndex>
<dropIndex indexName="transaction_id_index" tableName="vault_transaction_notes"/>
<addNotNullConstraint tableName="vault_transaction_notes" columnName="note" columnDataType="NVARCHAR(255)"/>
<addNotNullConstraint tableName="vault_transaction_notes" columnName="transaction_id" columnDataType="NVARCHAR(64)"/>
<createIndex indexName="transaction_id_index" tableName="vault_transaction_notes">
<column name="transaction_id"/>
</createIndex>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,15 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="R3.Corda" id="add_is_modifiable_column">
<addColumn tableName="vault_states">
<column name="is_modifiable" type="INT"/>
</addColumn>
<update tableName="vault_states">
<column name="is_modifiable" valueNumeric="0"/>
</update>
<addNotNullConstraint tableName="vault_states" columnName="is_modifiable" columnDataType="INT" />
</changeSet>
</databaseChangeLog>

View File

@ -11,7 +11,6 @@ import net.corda.core.identity.Party;
import net.corda.core.messaging.DataFeed;
import net.corda.core.node.services.IdentityService;
import net.corda.core.node.services.Vault;
import net.corda.core.node.services.VaultQueryException;
import net.corda.core.node.services.VaultService;
import net.corda.core.node.services.vault.*;
import net.corda.core.node.services.vault.QueryCriteria.LinearStateQueryCriteria;
@ -33,7 +32,6 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import rx.Observable;
import java.util.*;
import java.util.stream.Collectors;

View File

@ -6,8 +6,8 @@ import net.corda.core.node.services.vault.*
import net.corda.core.node.services.vault.QueryCriteria.*
import net.corda.finance.*
import net.corda.finance.contracts.asset.Cash
import net.corda.finance.schemas.CashSchemaV1
import net.corda.finance.schemas.SampleCashSchemaV3
import net.corda.finance.schemas.CashSchemaV1
import net.corda.testing.core.*
import net.corda.testing.internal.vault.DummyLinearStateSchemaV1
import org.assertj.core.api.Assertions.assertThatThrownBy
@ -51,4 +51,4 @@ class VaultQueryExceptionsTests : VaultQueryParties by rule {
}.isInstanceOf(VaultQueryException::class.java).hasMessageContaining("Please register the entity")
}
}
}
}

View File

@ -111,7 +111,7 @@ open class MockServices private constructor(
val cordappLoader = cordappLoaderForPackages(cordappPackages)
val dataSourceProps = makeTestDataSourceProperties()
val schemaService = NodeSchemaService(cordappLoader.cordappSchemas)
val database = configureDatabase(dataSourceProps, DatabaseConfig(), identityService::wellKnownPartyFromX500Name, identityService::wellKnownPartyFromAnonymous, schemaService)
val database = configureDatabase(dataSourceProps, DatabaseConfig(), identityService::wellKnownPartyFromX500Name, identityService::wellKnownPartyFromAnonymous, schemaService, schemaService.internalSchemas())
val mockService = database.transaction {
object : MockServices(cordappLoader, identityService, networkParameters, initialIdentity, moreKeys) {
override val vaultService: VaultService = makeVaultService(schemaService, database)