fix oracle issue

This commit is contained in:
Ken Stevens 2022-09-19 17:56:14 -04:00
parent 388e191ab3
commit 9a14e02f85
9 changed files with 108 additions and 47 deletions

View File

@ -52,7 +52,7 @@ public class HapiMigrator {
public HapiMigrator(DriverTypeEnum theDriverType, DataSource theDataSource, String theMigrationTableName) {
myDriverType = theDriverType;
myDataSource = theDataSource;
myHapiMigrationStorageSvc = new HapiMigrationStorageSvc(new HapiMigrationDao(theDataSource, theMigrationTableName));
myHapiMigrationStorageSvc = new HapiMigrationStorageSvc(new HapiMigrationDao(theDataSource, theDriverType, theMigrationTableName));
}
public DataSource getDataSource() {

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.migrate.dao;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
import ca.uhn.fhir.jpa.migrate.entity.HapiMigrationEntity;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.VersionEnum;
@ -20,11 +21,6 @@ import java.util.Set;
import java.util.stream.Collectors;
public class HapiMigrationDao {
static {
// required for most databases for boolean columns
System.setProperty("com.healthmarketscience.sqlbuilder.useBooleanLiterals", "true");
}
private static final Logger ourLog = LoggerFactory.getLogger(HapiMigrationDao.class);
private final JdbcTemplate myJdbcTemplate;
@ -32,18 +28,18 @@ public class HapiMigrationDao {
private final MigrationQueryBuilder myMigrationQueryBuilder;
private final DataSource myDataSource;
public HapiMigrationDao(DataSource theDataSource, String theMigrationTablename) {
public HapiMigrationDao(DataSource theDataSource, DriverTypeEnum theDriverType, String theMigrationTablename) {
myDataSource = theDataSource;
myJdbcTemplate = new JdbcTemplate(theDataSource);
myMigrationTablename = theMigrationTablename;
myMigrationQueryBuilder = new MigrationQueryBuilder(theMigrationTablename);
myMigrationQueryBuilder = new MigrationQueryBuilder(theDriverType, theMigrationTablename);
}
public Set<MigrationVersion> fetchSuccessfulMigrationVersions() {
String query = myMigrationQueryBuilder.findSuccessfulVersionQuery();
List<String> result = myJdbcTemplate.queryForList(query, String.class);
return result.stream()
List<HapiMigrationEntity> allEntries = findAll();
return allEntries.stream()
.filter(HapiMigrationEntity::getSuccess)
.map(HapiMigrationEntity::getVersion)
.map(MigrationVersion::fromVersion)
.collect(Collectors.toSet());
}
@ -112,6 +108,6 @@ public class HapiMigrationDao {
}
public List<HapiMigrationEntity> findAll() {
return myJdbcTemplate.query(myMigrationQueryBuilder.findAll(), HapiMigrationEntity.rowMapper());
return myJdbcTemplate.query(myMigrationQueryBuilder.findAllQuery(), HapiMigrationEntity.rowMapper());
}
}

View File

@ -1,7 +1,10 @@
package ca.uhn.fhir.jpa.migrate.dao;
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
import ca.uhn.fhir.jpa.migrate.entity.HapiMigrationEntity;
import com.healthmarketscience.sqlbuilder.BinaryCondition;
import ca.uhn.fhir.jpa.migrate.taskdef.ColumnTypeEnum;
import ca.uhn.fhir.jpa.migrate.taskdef.ColumnTypeToDriverTypeToSqlType;
import com.healthmarketscience.common.util.AppendableExt;
import com.healthmarketscience.sqlbuilder.CreateIndexQuery;
import com.healthmarketscience.sqlbuilder.CreateTableQuery;
import com.healthmarketscience.sqlbuilder.DeleteQuery;
@ -9,6 +12,8 @@ import com.healthmarketscience.sqlbuilder.FunctionCall;
import com.healthmarketscience.sqlbuilder.InsertQuery;
import com.healthmarketscience.sqlbuilder.JdbcEscape;
import com.healthmarketscience.sqlbuilder.SelectQuery;
import com.healthmarketscience.sqlbuilder.SqlObject;
import com.healthmarketscience.sqlbuilder.ValidationContext;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSchema;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSpec;
@ -16,6 +21,7 @@ import com.healthmarketscience.sqlbuilder.dbspec.basic.DbTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.sql.Types;
public class MigrationQueryBuilder {
@ -34,13 +40,14 @@ public class MigrationQueryBuilder {
private final DbColumn myInstalledOnCol;
private final DbColumn myExecutionTimeCol;
private final DbColumn mySuccessCol;
private final String myBuildSuccessfulVersionQuery;
private final String myDeleteAll;
private final String myHighestKeyQuery;
private final DriverTypeEnum myDriverType;
private final String myMigrationTablename;
private final String myBooleanType;
public MigrationQueryBuilder(String theMigrationTablename) {
public MigrationQueryBuilder(DriverTypeEnum theDriverType, String theMigrationTablename) {
myDriverType = theDriverType;
myMigrationTablename = theMigrationTablename;
mySpec = new DbSpec();
@ -71,26 +78,15 @@ public class MigrationQueryBuilder {
myExecutionTimeCol = myTable.addColumn("\"execution_time\"", Types.INTEGER, null);
myExecutionTimeCol.notNull();
mySuccessCol = myTable.addColumn("\"success\"", Types.BOOLEAN, null);
myBooleanType = ColumnTypeToDriverTypeToSqlType.getColumnTypeToDriverTypeToSqlType().get(ColumnTypeEnum.BOOLEAN).get(theDriverType);
mySuccessCol = myTable.addColumn("\"success\"", myBooleanType, null);
mySuccessCol.notNull();
myBuildSuccessfulVersionQuery = buildFindSuccessfulVersionQuery();
myDeleteAll = new DeleteQuery(myTable).toString();
myHighestKeyQuery = buildHighestKeyQuery();
}
private String buildFindSuccessfulVersionQuery() {
return new SelectQuery()
.addColumns(myVersionCol)
.addCondition(BinaryCondition.equalTo(mySuccessCol, true))
.validate()
.toString();
}
public String findSuccessfulVersionQuery() {
return myBuildSuccessfulVersionQuery;
}
public String deleteAll() {
return myDeleteAll;
}
@ -117,10 +113,33 @@ public class MigrationQueryBuilder {
.addColumn(myInstalledByCol, theEntity.getInstalledBy())
.addColumn(myInstalledOnCol, JdbcEscape.timestamp(theEntity.getInstalledOn()))
.addColumn(myExecutionTimeCol, theEntity.getExecutionTime())
.addColumn(mySuccessCol, theEntity.getSuccess())
.addColumn(mySuccessCol, getBooleanValue(theEntity.getSuccess()))
.validate()
.toString();
}
/**
sqlbuilder doesn't know about different database types, so we have to manually map boolean columns ourselves :-(
I'm gaining a new appreciation for Hibernate. I tried using hibernate for maintaining this table, but it added
a lot of overhead for managing just one table. Seeing this sort of nonsense though makes me wonder if we should
just use it instead of sqlbuilder. Disappointed that sqlbuilder doesn't handle boolean well out of the box.
(It does support a static option via System.setProperty("com.healthmarketscience.sqlbuilder.useBooleanLiterals", "true");
but that only works at classloading time which isn't much help to us.
*/
private SqlObject getBooleanValue(Boolean theBoolean) {
SqlObject retval = new SqlObject() {
@Override
protected void collectSchemaObjects(ValidationContext vContext) {}
@Override
public void appendTo(AppendableExt app) throws IOException {
String stringValue = ColumnTypeToDriverTypeToSqlType.toBooleanValue(myDriverType, theBoolean);
app.append(stringValue);
}
};
return retval;
}
public String createTableStatement() {
@ -137,7 +156,7 @@ public class MigrationQueryBuilder {
.toString();
}
public String findAll() {
public String findAllQuery() {
return new SelectQuery()
.addFromTable(myTable)
.addAllColumns()

View File

@ -115,9 +115,4 @@ public abstract class BaseTableColumnTypeTask extends BaseTableColumnTask {
}
return myColumnType.name();
}
public ColumnTypeToDriverTypeToSqlType getColumnTypeToDriverTypeToSqlType() {
return myColumnTypeToDriverTypeToSqlType;
}
}

View File

@ -27,7 +27,6 @@ import org.apache.commons.lang3.builder.HashCodeBuilder;
import java.util.Objects;
public abstract class BaseTableTask extends BaseTask {
protected final ColumnTypeToDriverTypeToSqlType myColumnTypeToDriverTypeToSqlType = new ColumnTypeToDriverTypeToSqlType();
private String myTableName;
@ -57,7 +56,7 @@ public abstract class BaseTableTask extends BaseTask {
}
protected String getSqlType(ColumnTypeEnum theColumnType, Long theColumnLength) {
String retVal = myColumnTypeToDriverTypeToSqlType.getColumnTypeToDriverTypeToSqlType().get(theColumnType).get(getDriverType());
String retVal = ColumnTypeToDriverTypeToSqlType.getColumnTypeToDriverTypeToSqlType().get(theColumnType).get(getDriverType());
Objects.requireNonNull(retVal);
if (theColumnType == ColumnTypeEnum.STRING) {

View File

@ -26,10 +26,12 @@ import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
import java.util.HashMap;
import java.util.Map;
public class ColumnTypeToDriverTypeToSqlType {
Map<ColumnTypeEnum, Map<DriverTypeEnum, String>> myColumnTypeToDriverTypeToSqlType = new HashMap<>();
public final class ColumnTypeToDriverTypeToSqlType {
public ColumnTypeToDriverTypeToSqlType() {
private ColumnTypeToDriverTypeToSqlType() {}
static Map<ColumnTypeEnum, Map<DriverTypeEnum, String>> myColumnTypeToDriverTypeToSqlType = new HashMap<>();
static {
setColumnType(ColumnTypeEnum.INT, DriverTypeEnum.H2_EMBEDDED, "integer");
setColumnType(ColumnTypeEnum.INT, DriverTypeEnum.DERBY_EMBEDDED, "integer");
setColumnType(ColumnTypeEnum.INT, DriverTypeEnum.MARIADB_10_1, "integer");
@ -111,15 +113,26 @@ public class ColumnTypeToDriverTypeToSqlType {
setColumnType(ColumnTypeEnum.CLOB, DriverTypeEnum.MSSQL_2012, "varchar(MAX)");
}
public Map<ColumnTypeEnum, Map<DriverTypeEnum, String>> getColumnTypeToDriverTypeToSqlType() {
public static Map<ColumnTypeEnum, Map<DriverTypeEnum, String>> getColumnTypeToDriverTypeToSqlType() {
return myColumnTypeToDriverTypeToSqlType;
}
private void setColumnType(ColumnTypeEnum theColumnType, DriverTypeEnum theDriverType, String theColumnTypeSql) {
private static void setColumnType(ColumnTypeEnum theColumnType, DriverTypeEnum theDriverType, String theColumnTypeSql) {
Map<DriverTypeEnum, String> columnSqlType = myColumnTypeToDriverTypeToSqlType.computeIfAbsent(theColumnType, k -> new HashMap<>());
if (columnSqlType.containsKey(theDriverType)) {
throw new IllegalStateException(Msg.code(65) + "Duplicate key: " + theDriverType);
}
columnSqlType.put(theDriverType, theColumnTypeSql);
}
public static String toBooleanValue(DriverTypeEnum theDriverType, Boolean theBoolean) {
switch (theDriverType) {
case H2_EMBEDDED:
case DERBY_EMBEDDED:
case POSTGRES_9_4:
return theBoolean.toString();
default:
return theBoolean ? "1" : "0";
}
}
}

View File

@ -14,7 +14,7 @@ public abstract class BaseMigrationTest {
@BeforeAll
public static void beforeAll() {
ourHapiMigrationDao = new HapiMigrationDao(getDataSource(), TABLE_NAME);
ourHapiMigrationDao = new HapiMigrationDao(getDataSource(), DriverTypeEnum.H2_EMBEDDED, TABLE_NAME);
ourHapiMigrationDao.createMigrationTableIfRequired();
ourHapiMigrationStorageSvc = new HapiMigrationStorageSvc(ourHapiMigrationDao);
}

View File

@ -0,0 +1,39 @@
package ca.uhn.fhir.jpa.migrate.dao;
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
import ca.uhn.fhir.jpa.migrate.entity.HapiMigrationEntity;
import org.junit.jupiter.api.Test;
import java.util.Date;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.endsWith;
class MigrationQueryBuilderTest {
private static final String TABLE = "TEST_TABLE_NAME";
@Test
void derby_insert() {
MigrationQueryBuilder mqb = new MigrationQueryBuilder(DriverTypeEnum.DERBY_EMBEDDED, TABLE);
HapiMigrationEntity entity = buildEntity();
String insertSql = mqb.insertStatement(entity);
assertThat(insertSql, endsWith(",NULL,true)"));
}
@Test
void oracle_insert() {
MigrationQueryBuilder mqb = new MigrationQueryBuilder(DriverTypeEnum.ORACLE_12C, TABLE);
HapiMigrationEntity entity = buildEntity();
String insertSql = mqb.insertStatement(entity);
assertThat(insertSql, endsWith(",NULL,1)"));
}
private HapiMigrationEntity buildEntity() {
HapiMigrationEntity retval = new HapiMigrationEntity();
retval.setInstalledOn(new Date());
retval.setSuccess(true);
return retval;
}
}

View File

@ -92,7 +92,7 @@ public abstract class BaseTest {
myConnectionProperties = testDatabaseDetails.myConnectionProperties;
myDataSource = testDatabaseDetails.myDataSource;
myMigrator = testDatabaseDetails.myMigrator;
myHapiMigrationDao = new HapiMigrationDao(testDatabaseDetails.myDataSource, SchemaMigrator.HAPI_FHIR_MIGRATION_TABLENAME);
myHapiMigrationDao = new HapiMigrationDao(testDatabaseDetails.myDataSource, testDatabaseDetails.getDriverType(), SchemaMigrator.HAPI_FHIR_MIGRATION_TABLENAME);
myHapiMigrationDao.createMigrationTableIfRequired();
myHapiMigrationStorageSvc = new HapiMigrationStorageSvc(myHapiMigrationDao);