fix conflicts from pulling 7.2
This commit is contained in:
commit
22b4669e5c
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: perf
|
||||||
|
issue: 6099
|
||||||
|
title: "Database migrations that add or drop an index no longer lock tables when running on Azure Sql Server."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 6083
|
||||||
|
backport: 7.2.2
|
||||||
|
title: "A bug with $everything operation was discovered when trying to search using hibernate search, this change makes
|
||||||
|
all $everything operation rely on database search until hibernate search fully supports the operation."
|
|
@ -30,6 +30,12 @@ Note that the Oracle JDBC drivers are not distributed in the Maven Central repos
|
||||||
java -cp hapi-fhir-cli.jar ca.uhn.fhir.cli.App migrate-database -d ORACLE_12C -u "[url]" -n "[username]" -p "[password]"
|
java -cp hapi-fhir-cli.jar ca.uhn.fhir.cli.App migrate-database -d ORACLE_12C -u "[url]" -n "[username]" -p "[password]"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Oracle and Sql Server Locking Note
|
||||||
|
|
||||||
|
Some versions of Oracle and Sql Server (e.g. Oracle Standard or Sql Server Standard) do NOT support adding or removing an index without locking the underlying table.
|
||||||
|
If you run migrations while these systems are running,
|
||||||
|
they will have unavoidable long pauses in activity during these changes.
|
||||||
|
|
||||||
## Migrating 3.4.0 to 3.5.0+
|
## Migrating 3.4.0 to 3.5.0+
|
||||||
|
|
||||||
As of HAPI FHIR 3.5.0 a new mechanism for creating the JPA index tables (HFJ_SPIDX_xxx) has been implemented. This new mechanism uses hashes in place of large multi-column indexes. This improves both lookup times as well as required storage space. This change also paves the way for future ability to provide efficient multi-tenant searches (which is not yet implemented but is planned as an incremental improvement).
|
As of HAPI FHIR 3.5.0 a new mechanism for creating the JPA index tables (HFJ_SPIDX_xxx) has been implemented. This new mechanism uses hashes in place of large multi-column indexes. This improves both lookup times as well as required storage space. This change also paves the way for future ability to provide efficient multi-tenant searches (which is not yet implemented but is planned as an incremental improvement).
|
||||||
|
|
|
@ -493,7 +493,8 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
||||||
&& myParams != null
|
&& myParams != null
|
||||||
&& myParams.getSearchContainedMode() == SearchContainedModeEnum.FALSE
|
&& myParams.getSearchContainedMode() == SearchContainedModeEnum.FALSE
|
||||||
&& myFulltextSearchSvc.canUseHibernateSearch(myResourceName, myParams)
|
&& myFulltextSearchSvc.canUseHibernateSearch(myResourceName, myParams)
|
||||||
&& myFulltextSearchSvc.supportsAllSortTerms(myResourceName, myParams);
|
&& myFulltextSearchSvc.supportsAllSortTerms(myResourceName, myParams)
|
||||||
|
&& myParams.getEverythingMode() == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void failIfUsed(String theParamName) {
|
private void failIfUsed(String theParamName) {
|
||||||
|
|
|
@ -68,12 +68,50 @@
|
||||||
<groupId>com.oracle.database.jdbc</groupId>
|
<groupId>com.oracle.database.jdbc</groupId>
|
||||||
<artifactId>ojdbc11</artifactId>
|
<artifactId>ojdbc11</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microsoft.sqlserver</groupId>
|
||||||
|
<artifactId>mssql-jdbc</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.qos.logback</groupId>
|
<groupId>ch.qos.logback</groupId>
|
||||||
<artifactId>logback-classic</artifactId>
|
<artifactId>logback-classic</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-test-utilities</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testcontainers</groupId>
|
||||||
|
<artifactId>junit-jupiter</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testcontainers</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testcontainers</groupId>
|
||||||
|
<artifactId>mssqlserver</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testcontainers</groupId>
|
||||||
|
<artifactId>oracle-xe</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Stupid testcontainers has a runtime dep on junit4 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains</groupId>
|
<groupId>org.jetbrains</groupId>
|
||||||
<artifactId>annotations</artifactId>
|
<artifactId>annotations</artifactId>
|
||||||
|
|
|
@ -33,6 +33,7 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class AddIndexTask extends BaseTableTask {
|
public class AddIndexTask extends BaseTableTask {
|
||||||
|
@ -69,7 +70,7 @@ public class AddIndexTask extends BaseTableTask {
|
||||||
super.validate();
|
super.validate();
|
||||||
Validate.notBlank(myIndexName, "Index name not specified");
|
Validate.notBlank(myIndexName, "Index name not specified");
|
||||||
Validate.isTrue(
|
Validate.isTrue(
|
||||||
myColumns.size() > 0,
|
!myColumns.isEmpty(),
|
||||||
"Columns not specified for AddIndexTask " + myIndexName + " on table " + getTableName());
|
"Columns not specified for AddIndexTask " + myIndexName + " on table " + getTableName());
|
||||||
Validate.notNull(myUnique, "Uniqueness not specified");
|
Validate.notNull(myUnique, "Uniqueness not specified");
|
||||||
setDescription("Add " + myIndexName + " index to table " + getTableName());
|
setDescription("Add " + myIndexName + " index to table " + getTableName());
|
||||||
|
@ -141,7 +142,7 @@ public class AddIndexTask extends BaseTableTask {
|
||||||
}
|
}
|
||||||
// Should we do this non-transactionally? Avoids a write-lock, but introduces weird failure modes.
|
// Should we do this non-transactionally? Avoids a write-lock, but introduces weird failure modes.
|
||||||
String postgresOnlineClause = "";
|
String postgresOnlineClause = "";
|
||||||
String msSqlOracleOnlineClause = "";
|
String oracleOnlineClause = "";
|
||||||
if (myOnline) {
|
if (myOnline) {
|
||||||
switch (getDriverType()) {
|
switch (getDriverType()) {
|
||||||
case POSTGRES_9_4:
|
case POSTGRES_9_4:
|
||||||
|
@ -150,25 +151,66 @@ public class AddIndexTask extends BaseTableTask {
|
||||||
// This runs without a lock, and can't be done transactionally.
|
// This runs without a lock, and can't be done transactionally.
|
||||||
setTransactional(false);
|
setTransactional(false);
|
||||||
break;
|
break;
|
||||||
case ORACLE_12C:
|
|
||||||
if (myMetadataSource.isOnlineIndexSupported(getConnectionProperties())) {
|
|
||||||
msSqlOracleOnlineClause = " ONLINE DEFERRED INVALIDATION";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MSSQL_2012:
|
case MSSQL_2012:
|
||||||
|
// handled below in buildOnlineCreateWithTryCatchFallback()
|
||||||
|
break;
|
||||||
|
case ORACLE_12C:
|
||||||
|
// todo: delete this once we figure out how run Oracle try-catch to match MSSQL.
|
||||||
if (myMetadataSource.isOnlineIndexSupported(getConnectionProperties())) {
|
if (myMetadataSource.isOnlineIndexSupported(getConnectionProperties())) {
|
||||||
msSqlOracleOnlineClause = " WITH (ONLINE = ON)";
|
oracleOnlineClause = " ONLINE DEFERRED INVALIDATION";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String sql = "create " + unique + "index " + postgresOnlineClause + myIndexName + " on " + getTableName() + "("
|
String bareCreateSql = "create " + unique + "index " + postgresOnlineClause + myIndexName + " on "
|
||||||
+ columns + ")" + includeClause + mssqlWhereClause + msSqlOracleOnlineClause;
|
+ getTableName() + "(" + columns + ")" + includeClause + mssqlWhereClause + oracleOnlineClause;
|
||||||
|
|
||||||
|
String sql;
|
||||||
|
if (myOnline && DriverTypeEnum.MSSQL_2012 == getDriverType()) {
|
||||||
|
sql = buildOnlineCreateWithTryCatchFallback(bareCreateSql);
|
||||||
|
} else {
|
||||||
|
sql = bareCreateSql;
|
||||||
|
}
|
||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap a Sql Server create index in a try/catch to try it first ONLINE
|
||||||
|
* (meaning no table locks), and on failure, without ONLINE (locking the table).
|
||||||
|
*
|
||||||
|
* This try-catch syntax was manually tested via sql
|
||||||
|
* {@code
|
||||||
|
* BEGIN TRY
|
||||||
|
* EXEC('create index FOO on TABLE_A (col1) WITH (ONLINE = ON)');
|
||||||
|
* select 'Online-OK';
|
||||||
|
* END TRY
|
||||||
|
* BEGIN CATCH
|
||||||
|
* create index FOO on TABLE_A (col1);
|
||||||
|
* select 'Offline';
|
||||||
|
* END CATCH;
|
||||||
|
* -- Then inspect the result set - Online-OK means it ran the ONLINE version.
|
||||||
|
* -- Note: we use EXEC() in the online path to lower the severity of the error
|
||||||
|
* -- so the CATCH can catch it.
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param bareCreateSql
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static @Nonnull String buildOnlineCreateWithTryCatchFallback(String bareCreateSql) {
|
||||||
|
// Some "Editions" of Sql Server do not support ONLINE.
|
||||||
|
// @format:off
|
||||||
|
return "BEGIN TRY -- try first online, without locking the table \n"
|
||||||
|
+ " EXEC('" + bareCreateSql + " WITH (ONLINE = ON)');\n"
|
||||||
|
+ "END TRY \n"
|
||||||
|
+ "BEGIN CATCH -- for Editions of Sql Server that don't support ONLINE, run with table locks \n"
|
||||||
|
+ bareCreateSql
|
||||||
|
+ "; \n"
|
||||||
|
+ "END CATCH;";
|
||||||
|
// @format:on
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private String buildMSSqlNotNullWhereClause() {
|
private String buildMSSqlNotNullWhereClause() {
|
||||||
String mssqlWhereClause;
|
String mssqlWhereClause;
|
||||||
|
@ -192,7 +234,7 @@ public class AddIndexTask extends BaseTableTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setIncludeColumns(List<String> theIncludeColumns) {
|
private void setIncludeColumns(List<String> theIncludeColumns) {
|
||||||
Validate.notNull(theIncludeColumns);
|
Objects.requireNonNull(theIncludeColumns);
|
||||||
myIncludeColumns = theIncludeColumns;
|
myIncludeColumns = theIncludeColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,12 @@ public class DropIndexTask extends BaseTableTask {
|
||||||
sql.add("drop index " + myIndexName + (myOnline ? " ONLINE" : ""));
|
sql.add("drop index " + myIndexName + (myOnline ? " ONLINE" : ""));
|
||||||
break;
|
break;
|
||||||
case MSSQL_2012:
|
case MSSQL_2012:
|
||||||
sql.add("drop index " + getTableName() + "." + myIndexName);
|
// use a try-catch to try online first, and fail over to lock path.
|
||||||
|
String sqlServerDrop = "drop index " + getTableName() + "." + myIndexName;
|
||||||
|
if (myOnline) {
|
||||||
|
sqlServerDrop = AddIndexTask.buildOnlineCreateWithTryCatchFallback(sqlServerDrop);
|
||||||
|
}
|
||||||
|
sql.add(sqlServerDrop);
|
||||||
break;
|
break;
|
||||||
case COCKROACHDB_21_1:
|
case COCKROACHDB_21_1:
|
||||||
sql.add("drop index " + getTableName() + "@" + myIndexName);
|
sql.add("drop index " + getTableName() + "@" + myIndexName);
|
||||||
|
|
|
@ -32,16 +32,23 @@ public class MetadataSource {
|
||||||
*/
|
*/
|
||||||
public boolean isOnlineIndexSupported(DriverTypeEnum.ConnectionProperties theConnectionProperties) {
|
public boolean isOnlineIndexSupported(DriverTypeEnum.ConnectionProperties theConnectionProperties) {
|
||||||
|
|
||||||
|
// todo: delete this once we figure out how run Oracle try-catch as well.
|
||||||
switch (theConnectionProperties.getDriverType()) {
|
switch (theConnectionProperties.getDriverType()) {
|
||||||
case POSTGRES_9_4:
|
case POSTGRES_9_4:
|
||||||
case COCKROACHDB_21_1:
|
case COCKROACHDB_21_1:
|
||||||
return true;
|
return true;
|
||||||
case MSSQL_2012:
|
case MSSQL_2012:
|
||||||
|
// use a deny-list instead of allow list, so we have a better failure mode for new/unknown versions.
|
||||||
|
// Better to fail in dev than run with a table lock in production.
|
||||||
String mssqlEdition = getEdition(theConnectionProperties);
|
String mssqlEdition = getEdition(theConnectionProperties);
|
||||||
return mssqlEdition.startsWith("Enterprise");
|
return mssqlEdition == null // some weird version without an edition?
|
||||||
|
||
|
||||||
|
// these versions don't support ONLINE index creation
|
||||||
|
!mssqlEdition.startsWith("Standard Edition");
|
||||||
case ORACLE_12C:
|
case ORACLE_12C:
|
||||||
String oracleEdition = getEdition(theConnectionProperties);
|
String oracleEdition = getEdition(theConnectionProperties);
|
||||||
return oracleEdition.contains("Enterprise");
|
return oracleEdition == null // weird unknown version - try, and maybe fail.
|
||||||
|
|| oracleEdition.contains("Enterprise");
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
||||||
|
import ca.uhn.fhir.jpa.migrate.taskdef.containertests.BaseMigrationTaskTestSuite;
|
||||||
|
import ca.uhn.fhir.jpa.migrate.tasks.api.Builder;
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
|
import org.awaitility.Awaitility;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for AddIndexTask.
|
||||||
|
*/
|
||||||
|
public interface AddIndexTaskITTestSuite extends BaseMigrationTaskTestSuite {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
default void testAddIndexOnline_createsIndex() throws SQLException {
|
||||||
|
// given
|
||||||
|
Builder builder = getSupport().getBuilder();
|
||||||
|
String tableName = "TABLE_ADD" + System.currentTimeMillis();
|
||||||
|
Builder.BuilderAddTableByColumns tableBuilder = builder.addTableByColumns("1", tableName, "id");
|
||||||
|
tableBuilder.addColumn("id").nonNullable().type(ColumnTypeEnum.LONG);
|
||||||
|
tableBuilder.addColumn("col1").nullable().type(ColumnTypeEnum.STRING, 100);
|
||||||
|
getSupport().executeAndClearPendingTasks();
|
||||||
|
|
||||||
|
// when
|
||||||
|
builder.onTable(tableName)
|
||||||
|
.addIndex("2", "FOO")
|
||||||
|
.unique(false)
|
||||||
|
.online(true)
|
||||||
|
.withColumns("col1");
|
||||||
|
getSupport().executeAndClearPendingTasks();
|
||||||
|
|
||||||
|
// then
|
||||||
|
|
||||||
|
// we wait since the ONLINE path is async.
|
||||||
|
Awaitility.await("index FOO exists").atMost(10, TimeUnit.SECONDS).untilAsserted(
|
||||||
|
() -> Assertions.assertThat(JdbcUtils.getIndexNames(getSupport().getConnectionProperties(), tableName)).contains("FOO"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.hasItem;
|
import static org.hamcrest.Matchers.hasItem;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
@SuppressWarnings("SqlDialectInspection")
|
||||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||||
public class AddIndexTaskTest extends BaseTest {
|
public class AddIndexTaskTest extends BaseTest {
|
||||||
|
|
||||||
|
@ -180,7 +181,7 @@ public class AddIndexTaskTest extends BaseTest {
|
||||||
public void platformSyntaxWhenOn(DriverTypeEnum theDriver) {
|
public void platformSyntaxWhenOn(DriverTypeEnum theDriver) {
|
||||||
myTask.setDriverType(theDriver);
|
myTask.setDriverType(theDriver);
|
||||||
myTask.setOnline(true);
|
myTask.setOnline(true);
|
||||||
DriverTypeEnum.ConnectionProperties props;
|
|
||||||
Mockito.when(mockMetadataSource.isOnlineIndexSupported(Mockito.any())).thenReturn(true);
|
Mockito.when(mockMetadataSource.isOnlineIndexSupported(Mockito.any())).thenReturn(true);
|
||||||
mySql = myTask.generateSql();
|
mySql = myTask.generateSql();
|
||||||
switch (theDriver) {
|
switch (theDriver) {
|
||||||
|
@ -192,7 +193,12 @@ public class AddIndexTaskTest extends BaseTest {
|
||||||
assertEquals("create index IDX_ANINDEX on SOMETABLE(PID, TEXTCOL) ONLINE DEFERRED INVALIDATION", mySql);
|
assertEquals("create index IDX_ANINDEX on SOMETABLE(PID, TEXTCOL) ONLINE DEFERRED INVALIDATION", mySql);
|
||||||
break;
|
break;
|
||||||
case MSSQL_2012:
|
case MSSQL_2012:
|
||||||
assertEquals("create index IDX_ANINDEX on SOMETABLE(PID, TEXTCOL) WITH (ONLINE = ON)", mySql);
|
assertEquals("BEGIN TRY -- try first online, without locking the table \n" +
|
||||||
|
" EXEC('create index IDX_ANINDEX on SOMETABLE(PID, TEXTCOL) WITH (ONLINE = ON)');\n" +
|
||||||
|
"END TRY \n" +
|
||||||
|
"BEGIN CATCH -- for Editions of Sql Server that don't support ONLINE, run with table locks \n" +
|
||||||
|
"create index IDX_ANINDEX on SOMETABLE(PID, TEXTCOL); \n" +
|
||||||
|
"END CATCH;", mySql);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// unsupported is ok. But it means we lock the table for a bit.
|
// unsupported is ok. But it means we lock the table for a bit.
|
||||||
|
@ -201,32 +207,19 @@ public class AddIndexTaskTest extends BaseTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We sniff the edition of Oracle to detect support for ONLINE migrations.
|
||||||
|
*/
|
||||||
@ParameterizedTest(name = "{index}: {0}")
|
@ParameterizedTest(name = "{index}: {0}")
|
||||||
@ValueSource(booleans = { true, false } )
|
@ValueSource(booleans = { true, false } )
|
||||||
public void offForUnsupportedVersionsOfSqlServer(boolean theSupportedFlag) {
|
public void offForUnsupportedVersionsOfOracleServer(boolean theOnlineIndexingSupportedFlag) {
|
||||||
myTask.setDriverType(DriverTypeEnum.MSSQL_2012);
|
|
||||||
myTask.setOnline(true);
|
|
||||||
myTask.setMetadataSource(mockMetadataSource);
|
|
||||||
Mockito.when(mockMetadataSource.isOnlineIndexSupported(Mockito.any())).thenReturn(theSupportedFlag);
|
|
||||||
|
|
||||||
mySql = myTask.generateSql();
|
|
||||||
if (theSupportedFlag) {
|
|
||||||
assertEquals("create index IDX_ANINDEX on SOMETABLE(PID, TEXTCOL) WITH (ONLINE = ON)", mySql);
|
|
||||||
} else {
|
|
||||||
assertEquals("create index IDX_ANINDEX on SOMETABLE(PID, TEXTCOL)", mySql);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest(name = "{index}: {0}")
|
|
||||||
@ValueSource(booleans = { true, false } )
|
|
||||||
public void offForUnsupportedVersionsOfOracleServer(boolean theSupportedFlag) {
|
|
||||||
myTask.setDriverType(DriverTypeEnum.ORACLE_12C);
|
myTask.setDriverType(DriverTypeEnum.ORACLE_12C);
|
||||||
myTask.setOnline(true);
|
myTask.setOnline(true);
|
||||||
myTask.setMetadataSource(mockMetadataSource);
|
myTask.setMetadataSource(mockMetadataSource);
|
||||||
Mockito.when(mockMetadataSource.isOnlineIndexSupported(Mockito.any())).thenReturn(theSupportedFlag);
|
Mockito.when(mockMetadataSource.isOnlineIndexSupported(Mockito.any())).thenReturn(theOnlineIndexingSupportedFlag);
|
||||||
|
|
||||||
mySql = myTask.generateSql();
|
mySql = myTask.generateSql();
|
||||||
if (theSupportedFlag) {
|
if (theOnlineIndexingSupportedFlag) {
|
||||||
assertEquals("create index IDX_ANINDEX on SOMETABLE(PID, TEXTCOL) ONLINE DEFERRED INVALIDATION", mySql);
|
assertEquals("create index IDX_ANINDEX on SOMETABLE(PID, TEXTCOL) ONLINE DEFERRED INVALIDATION", mySql);
|
||||||
} else {
|
} else {
|
||||||
assertEquals("create index IDX_ANINDEX on SOMETABLE(PID, TEXTCOL)", mySql);
|
assertEquals("create index IDX_ANINDEX on SOMETABLE(PID, TEXTCOL)", mySql);
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
||||||
|
import ca.uhn.fhir.jpa.migrate.taskdef.containertests.BaseMigrationTaskTestSuite;
|
||||||
|
import ca.uhn.fhir.jpa.migrate.tasks.api.Builder;
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
|
import org.awaitility.Awaitility;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for AddIndexTask.
|
||||||
|
*/
|
||||||
|
public interface DropIndexTaskITTestSuite extends BaseMigrationTaskTestSuite {
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
default void testDropIndex_dropsIndex() throws SQLException {
|
||||||
|
// given
|
||||||
|
Builder builder = getSupport().getBuilder();
|
||||||
|
String tableName = "INDEX_DROP" + System.currentTimeMillis();
|
||||||
|
Builder.BuilderAddTableByColumns tableBuilder = builder.addTableByColumns("1", tableName, "id");
|
||||||
|
tableBuilder.addColumn("id").nonNullable().type(ColumnTypeEnum.LONG);
|
||||||
|
tableBuilder.addColumn("col1").nullable().type(ColumnTypeEnum.STRING, 100);
|
||||||
|
builder.onTable(tableName)
|
||||||
|
.addIndex("2", "FOO")
|
||||||
|
.unique(false)
|
||||||
|
.online(false)
|
||||||
|
.withColumns("col1");
|
||||||
|
getSupport().executeAndClearPendingTasks();
|
||||||
|
Assertions.assertThat(JdbcUtils.getIndexNames(getSupport().getConnectionProperties(), tableName)).contains("FOO");
|
||||||
|
|
||||||
|
// when
|
||||||
|
builder.onTable(tableName)
|
||||||
|
.dropIndex("2", "FOO");
|
||||||
|
getSupport().executeAndClearPendingTasks();
|
||||||
|
|
||||||
|
// then
|
||||||
|
Assertions.assertThat(JdbcUtils.getIndexNames(getSupport().getConnectionProperties(), tableName))
|
||||||
|
.as("index FOO does not exist")
|
||||||
|
.doesNotContain("FOO");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
default void testDropIndexOnline_dropsIndex() throws SQLException {
|
||||||
|
// given
|
||||||
|
Builder builder = getSupport().getBuilder();
|
||||||
|
String tableName = "INDEX_DROP" + System.currentTimeMillis();
|
||||||
|
Builder.BuilderAddTableByColumns tableBuilder = builder.addTableByColumns("1", tableName, "id");
|
||||||
|
tableBuilder.addColumn("id").nonNullable().type(ColumnTypeEnum.LONG);
|
||||||
|
tableBuilder.addColumn("col1").nullable().type(ColumnTypeEnum.STRING, 100);
|
||||||
|
builder.onTable(tableName)
|
||||||
|
.addIndex("2", "FOO")
|
||||||
|
.unique(false)
|
||||||
|
.online(false)
|
||||||
|
.withColumns("col1");
|
||||||
|
getSupport().executeAndClearPendingTasks();
|
||||||
|
Assertions.assertThat(JdbcUtils.getIndexNames(getSupport().getConnectionProperties(), tableName)).contains("FOO");
|
||||||
|
|
||||||
|
// when
|
||||||
|
builder.onTable(tableName)
|
||||||
|
.dropIndexOnline("2", "FOO");
|
||||||
|
getSupport().executeAndClearPendingTasks();
|
||||||
|
|
||||||
|
// then
|
||||||
|
|
||||||
|
// we wait since the ONLINE path is async.
|
||||||
|
Awaitility.await("index FOO does not exist").atMost(10, TimeUnit.SECONDS).untilAsserted(
|
||||||
|
() -> Assertions.assertThat(JdbcUtils.getIndexNames(getSupport().getConnectionProperties(), tableName)).doesNotContain("FOO"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
import ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
import ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
@ -19,7 +20,7 @@ import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
|
|
||||||
public class DropIndexTest extends BaseTest {
|
public class DropIndexTaskTest extends BaseTest {
|
||||||
|
|
||||||
|
|
||||||
@ParameterizedTest(name = "{index}: {0}")
|
@ParameterizedTest(name = "{index}: {0}")
|
||||||
|
@ -251,7 +252,12 @@ public class DropIndexTest extends BaseTest {
|
||||||
assertThat(mySql, equalTo(asList("drop index IDX_ANINDEX ONLINE")));
|
assertThat(mySql, equalTo(asList("drop index IDX_ANINDEX ONLINE")));
|
||||||
break;
|
break;
|
||||||
case MSSQL_2012:
|
case MSSQL_2012:
|
||||||
assertThat(mySql, equalTo(asList("drop index SOMETABLE.IDX_ANINDEX")));
|
Assertions.assertEquals(asList("BEGIN TRY -- try first online, without locking the table \n" +
|
||||||
|
" EXEC('drop index SOMETABLE.IDX_ANINDEX WITH (ONLINE = ON)');\n" +
|
||||||
|
"END TRY \n" +
|
||||||
|
"BEGIN CATCH -- for Editions of Sql Server that don't support ONLINE, run with table locks \n" +
|
||||||
|
"drop index SOMETABLE.IDX_ANINDEX; \n" +
|
||||||
|
"END CATCH;"), mySql);
|
||||||
break;
|
break;
|
||||||
case POSTGRES_9_4:
|
case POSTGRES_9_4:
|
||||||
assertThat(mySql, equalTo(asList("drop index CONCURRENTLY IDX_ANINDEX")));
|
assertThat(mySql, equalTo(asList("drop index CONCURRENTLY IDX_ANINDEX")));
|
|
@ -32,12 +32,14 @@ class MetadataSourceTest {
|
||||||
"ORACLE_12C,Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production,true",
|
"ORACLE_12C,Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production,true",
|
||||||
"ORACLE_12C,Oracle Database 19c Express Edition Release 11.2.0.2.0 - 64bit Production,false",
|
"ORACLE_12C,Oracle Database 19c Express Edition Release 11.2.0.2.0 - 64bit Production,false",
|
||||||
"COCKROACHDB_21_1,,true",
|
"COCKROACHDB_21_1,,true",
|
||||||
// sql server only supports it in Enterprise
|
// sql server only supports it in Enterprise and Developer
|
||||||
// https://docs.microsoft.com/en-us/sql/sql-server/editions-and-components-of-sql-server-2019?view=sql-server-ver16#RDBMSHA
|
// https://docs.microsoft.com/en-us/sql/sql-server/editions-and-components-of-sql-server-2019?view=sql-server-ver16#RDBMSHA
|
||||||
"MSSQL_2012,Developer Edition (64-bit),false",
|
"MSSQL_2012,Developer Edition (64-bit),true",
|
||||||
"MSSQL_2012,Developer Edition (64-bit),false",
|
"MSSQL_2012,Developer Edition (64-bit),true",
|
||||||
"MSSQL_2012,Standard Edition (64-bit),false",
|
"MSSQL_2012,Standard Edition (64-bit),false",
|
||||||
"MSSQL_2012,Enterprise Edition (64-bit),true"
|
"MSSQL_2012,Enterprise Edition (64-bit),true",
|
||||||
|
"MSSQL_2012,Azure SQL Edge Developer (64-bit),true",
|
||||||
|
"MSSQL_2012,Azure SQL Edge Premium (64-bit),true"
|
||||||
})
|
})
|
||||||
void isOnlineIndexSupported(DriverTypeEnum theType, String theEdition, boolean theSupportedFlag) {
|
void isOnlineIndexSupported(DriverTypeEnum theType, String theEdition, boolean theSupportedFlag) {
|
||||||
// stub out our Sql Server edition lookup
|
// stub out our Sql Server edition lookup
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
package ca.uhn.fhir.jpa.migrate.taskdef.containertests;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
|
import ca.uhn.fhir.jpa.migrate.taskdef.AddIndexTaskITTestSuite;
|
||||||
|
import ca.uhn.fhir.jpa.migrate.taskdef.DropIndexTaskITTestSuite;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static ca.uhn.fhir.jpa.migrate.taskdef.containertests.BaseMigrationTaskTestSuite.Support;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects all our task suites in a single class so we can run them on each engine.
|
||||||
|
*/
|
||||||
|
public abstract class BaseCollectedMigrationTaskSuite {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Per-test supplier for db-access, migration task list, etc.
|
||||||
|
*/
|
||||||
|
BaseMigrationTaskTestSuite.Support mySupport;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
DriverTypeEnum.ConnectionProperties connectionProperties = getConnectionProperties();
|
||||||
|
mySupport = Support.supportFrom(connectionProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle on concrete class container connection info.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
protected abstract DriverTypeEnum.ConnectionProperties getConnectionProperties();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final public BaseMigrationTaskTestSuite.Support getSupport() {
|
||||||
|
return mySupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class AddIndexTaskTests implements AddIndexTaskITTestSuite {
|
||||||
|
@Override
|
||||||
|
public Support getSupport() {
|
||||||
|
return BaseCollectedMigrationTaskSuite.this.getSupport();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class DropIndexTaskTests implements DropIndexTaskITTestSuite {
|
||||||
|
@Override
|
||||||
|
public Support getSupport() {
|
||||||
|
return BaseCollectedMigrationTaskSuite.this.getSupport();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNothing() {
|
||||||
|
// an empty test to quiet sonar
|
||||||
|
Assertions.assertTrue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package ca.uhn.fhir.jpa.migrate.taskdef.containertests;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
|
import ca.uhn.fhir.jpa.migrate.taskdef.BaseTask;
|
||||||
|
import ca.uhn.fhir.jpa.migrate.tasks.api.BaseMigrationTasks;
|
||||||
|
import ca.uhn.fhir.jpa.migrate.tasks.api.Builder;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mixin for a migration task test suite
|
||||||
|
*/
|
||||||
|
public interface BaseMigrationTaskTestSuite {
|
||||||
|
Support getSupport();
|
||||||
|
|
||||||
|
class Support {
|
||||||
|
final TaskExecutor myTaskExecutor;
|
||||||
|
final Builder myBuilder;
|
||||||
|
final DriverTypeEnum.ConnectionProperties myConnectionProperties;
|
||||||
|
|
||||||
|
public static Support supportFrom(DriverTypeEnum.ConnectionProperties theConnectionProperties) {
|
||||||
|
return new Support(theConnectionProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
Support(DriverTypeEnum.ConnectionProperties theConnectionProperties) {
|
||||||
|
myConnectionProperties = theConnectionProperties;
|
||||||
|
myTaskExecutor = new TaskExecutor(theConnectionProperties);
|
||||||
|
myBuilder = new Builder("1.0", myTaskExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder getBuilder() {
|
||||||
|
return myBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void executeAndClearPendingTasks() throws SQLException {
|
||||||
|
myTaskExecutor.flushPendingTasks();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DriverTypeEnum.ConnectionProperties getConnectionProperties() {
|
||||||
|
return myConnectionProperties;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect and execute the tasks from the Builder
|
||||||
|
*/
|
||||||
|
class TaskExecutor implements BaseMigrationTasks.IAcceptsTasks {
|
||||||
|
final DriverTypeEnum.ConnectionProperties myConnectionProperties;
|
||||||
|
final LinkedList<BaseTask> myTasks = new LinkedList<>();
|
||||||
|
|
||||||
|
TaskExecutor(DriverTypeEnum.ConnectionProperties theConnectionProperties) {
|
||||||
|
myConnectionProperties = theConnectionProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive a task from the Builder
|
||||||
|
*/
|
||||||
|
public void addTask(BaseTask theTask) {
|
||||||
|
myTasks.add(theTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove and execute each task in the list.
|
||||||
|
*/
|
||||||
|
public void flushPendingTasks() throws SQLException {
|
||||||
|
while (!myTasks.isEmpty()) {
|
||||||
|
executeTask(myTasks.removeFirst());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void executeTask(BaseTask theTask) throws SQLException {
|
||||||
|
theTask.setDriverType(myConnectionProperties.getDriverType());
|
||||||
|
theTask.setConnectionProperties(myConnectionProperties);
|
||||||
|
theTask.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package ca.uhn.fhir.jpa.migrate.taskdef.containertests;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.testcontainers.containers.PostgreSQLContainer;
|
||||||
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nonnull;
|
||||||
|
|
||||||
|
@Testcontainers(disabledWithoutDocker=true)
|
||||||
|
public class Postgres12CollectedMigrationTest extends BaseCollectedMigrationTaskSuite {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
static TestContainerDatabaseMigrationExtension ourContainerExtension =
|
||||||
|
new TestContainerDatabaseMigrationExtension(
|
||||||
|
DriverTypeEnum.POSTGRES_9_4,
|
||||||
|
new PostgreSQLContainer<>("postgres:12.2"));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
protected DriverTypeEnum.ConnectionProperties getConnectionProperties() {
|
||||||
|
return ourContainerExtension.getConnectionProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package ca.uhn.fhir.jpa.migrate.taskdef.containertests;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.testcontainers.containers.PostgreSQLContainer;
|
||||||
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nonnull;
|
||||||
|
|
||||||
|
@Testcontainers(disabledWithoutDocker=true)
|
||||||
|
public class Postgres16CollectedMigrationTest extends BaseCollectedMigrationTaskSuite {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
static TestContainerDatabaseMigrationExtension ourContainerExtension =
|
||||||
|
new TestContainerDatabaseMigrationExtension(
|
||||||
|
DriverTypeEnum.POSTGRES_9_4,
|
||||||
|
new PostgreSQLContainer<>("postgres:16.3"));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
protected DriverTypeEnum.ConnectionProperties getConnectionProperties() {
|
||||||
|
return ourContainerExtension.getConnectionProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package ca.uhn.fhir.jpa.migrate.taskdef.containertests;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.testcontainers.containers.MSSQLServerContainer;
|
||||||
|
import org.testcontainers.utility.DockerImageName;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nonnull;
|
||||||
|
|
||||||
|
public class SqlServerAzureCollectedMigrationTests extends BaseCollectedMigrationTaskSuite {
|
||||||
|
@RegisterExtension
|
||||||
|
static TestContainerDatabaseMigrationExtension ourContainerExtension =
|
||||||
|
new TestContainerDatabaseMigrationExtension(
|
||||||
|
DriverTypeEnum.MSSQL_2012,
|
||||||
|
new MSSQLServerContainer<>(
|
||||||
|
DockerImageName.parse("mcr.microsoft.com/azure-sql-edge:latest")
|
||||||
|
.asCompatibleSubstituteFor("mcr.microsoft.com/mssql/server"))
|
||||||
|
.withEnv("ACCEPT_EULA", "Y")
|
||||||
|
.withEnv("MSSQL_PID", "Premium")); // Product id: Azure Premium vs Standard
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
protected DriverTypeEnum.ConnectionProperties getConnectionProperties() {
|
||||||
|
return ourContainerExtension.getConnectionProperties();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package ca.uhn.fhir.jpa.migrate.taskdef.containertests;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.testcontainers.containers.MSSQLServerContainer;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nonnull;
|
||||||
|
|
||||||
|
public class SqlServerEnterpriseCollectedMigrationTests extends BaseCollectedMigrationTaskSuite {
|
||||||
|
@RegisterExtension
|
||||||
|
static TestContainerDatabaseMigrationExtension ourContainerExtension =
|
||||||
|
new TestContainerDatabaseMigrationExtension(
|
||||||
|
DriverTypeEnum.MSSQL_2012,
|
||||||
|
new MSSQLServerContainer<>("mcr.microsoft.com/mssql/server:2019-latest")
|
||||||
|
.withEnv("ACCEPT_EULA", "Y")
|
||||||
|
.withEnv("MSSQL_PID", "Enterprise")); // Product id: Sql Server Enterprise vs Standard vs Developer vs ????
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
protected DriverTypeEnum.ConnectionProperties getConnectionProperties() {
|
||||||
|
return ourContainerExtension.getConnectionProperties();
|
||||||
|
}}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package ca.uhn.fhir.jpa.migrate.taskdef.containertests;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.testcontainers.containers.MSSQLServerContainer;
|
||||||
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nonnull;
|
||||||
|
|
||||||
|
@Testcontainers(disabledWithoutDocker=true)
|
||||||
|
public class SqlServerStandardCollectedMigrationTest extends BaseCollectedMigrationTaskSuite {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
static TestContainerDatabaseMigrationExtension ourContainerExtension =
|
||||||
|
new TestContainerDatabaseMigrationExtension(
|
||||||
|
DriverTypeEnum.MSSQL_2012,
|
||||||
|
new MSSQLServerContainer<>("mcr.microsoft.com/mssql/server:2019-latest")
|
||||||
|
.withEnv("ACCEPT_EULA", "Y")
|
||||||
|
.withEnv("MSSQL_PID", "Standard") // Product id: Sql Server Enterprise vs Standard vs Developer vs ????
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
protected DriverTypeEnum.ConnectionProperties getConnectionProperties() {
|
||||||
|
return ourContainerExtension.getConnectionProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package ca.uhn.fhir.jpa.migrate.taskdef.containertests;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
import org.junit.jupiter.api.extension.AfterAllCallback;
|
||||||
|
import org.junit.jupiter.api.extension.BeforeAllCallback;
|
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.testcontainers.containers.JdbcDatabaseContainer;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a database from TestContainers, and exposes ConnectionProperties for the migrator.
|
||||||
|
*/
|
||||||
|
public class TestContainerDatabaseMigrationExtension implements BeforeAllCallback, AfterAllCallback {
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(TestContainerDatabaseMigrationExtension.class);
|
||||||
|
|
||||||
|
final JdbcDatabaseContainer<?> myJdbcDatabaseContainer;
|
||||||
|
final DriverTypeEnum myDriverTypeEnum;
|
||||||
|
|
||||||
|
public TestContainerDatabaseMigrationExtension(
|
||||||
|
DriverTypeEnum theDriverTypeEnum,
|
||||||
|
JdbcDatabaseContainer<?> theJdbcDatabaseContainer) {
|
||||||
|
myDriverTypeEnum = theDriverTypeEnum;
|
||||||
|
myJdbcDatabaseContainer = theJdbcDatabaseContainer
|
||||||
|
// use a random password to avoid having open ports on hard-coded passwords
|
||||||
|
.withPassword("!@Aa" + RandomStringUtils.randomAlphanumeric(20));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeAll(ExtensionContext context) {
|
||||||
|
ourLog.info("Starting container {}", myJdbcDatabaseContainer.getContainerInfo());
|
||||||
|
myJdbcDatabaseContainer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterAll(ExtensionContext context) {
|
||||||
|
ourLog.info("Stopping container {}", myJdbcDatabaseContainer.getContainerInfo());
|
||||||
|
myJdbcDatabaseContainer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public DriverTypeEnum.ConnectionProperties getConnectionProperties() {
|
||||||
|
return myDriverTypeEnum.newConnectionProperties(myJdbcDatabaseContainer.getJdbcUrl(), myJdbcDatabaseContainer.getUsername(), myJdbcDatabaseContainer.getPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Collection of integration tests of migration tasks against real databases.
|
||||||
|
*/
|
||||||
|
package ca.uhn.fhir.jpa.migrate.taskdef.containertests;
|
Loading…
Reference in New Issue