diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml index bc427b6b7bc8..26b28e3c3e60 100644 --- a/hapi-deployable-pom/pom.xml +++ b/hapi-deployable-pom/pom.xml @@ -228,6 +228,7 @@ process-sources + true false apache_v2 true diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5748-avoid-lob-usage-in-batch2-and-search.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5748-avoid-lob-usage-in-batch2-and-search.yaml new file mode 100644 index 000000000000..802c32091b88 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5748-avoid-lob-usage-in-batch2-and-search.yaml @@ -0,0 +1,9 @@ +--- +type: perf +issue: 5748 +backport: 6.8.6 +title: "In the JPA server, several database columns related to Batch2 jobs and searching + have been reworked so that they no will longer use LOB datatypes going forward. This + is a significant advantage on Postgresql databases as it removes a significant use + of the inefficient `pg_largeobject` table, and should yield performance boosts for + MSSQL as well." diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2JobInstanceRepository.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2JobInstanceRepository.java index ee575c644785..18b8250472f0 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2JobInstanceRepository.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2JobInstanceRepository.java @@ -55,14 +55,15 @@ int updateInstanceStatusIfIn( int updateWorkChunksPurgedTrue(@Param("id") String theInstanceId); @Query( - "SELECT b from Batch2JobInstanceEntity b WHERE b.myDefinitionId = :defId AND b.myParamsJson = :params AND b.myStatus IN( :stats )") + "SELECT b from Batch2JobInstanceEntity b WHERE b.myDefinitionId = :defId AND (b.myParamsJson = :params OR b.myParamsJsonVc = :params) AND b.myStatus IN( :stats )") List findInstancesByJobIdParamsAndStatus( @Param("defId") String theDefinitionId, @Param("params") String theParams, @Param("stats") Set theStatus, Pageable thePageable); - @Query("SELECT b from Batch2JobInstanceEntity b WHERE b.myDefinitionId = :defId AND b.myParamsJson = :params") + @Query( + "SELECT b from Batch2JobInstanceEntity b WHERE b.myDefinitionId = :defId AND (b.myParamsJson = :params OR b.myParamsJsonVc = :params)") List findInstancesByJobIdAndParams( @Param("defId") String theDefinitionId, @Param("params") String theParams, Pageable thePageable); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2WorkChunkRepository.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2WorkChunkRepository.java index 8e6fea0339dd..1ce326cefd65 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2WorkChunkRepository.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2WorkChunkRepository.java @@ -65,7 +65,7 @@ Stream fetchChunksForStep( @Modifying @Query("UPDATE Batch2WorkChunkEntity e SET e.myStatus = :status, e.myEndTime = :et, " - + "e.myRecordsProcessed = :rp, e.myErrorCount = e.myErrorCount + :errorRetries, e.mySerializedData = null, " + + "e.myRecordsProcessed = :rp, e.myErrorCount = e.myErrorCount + :errorRetries, e.mySerializedData = null, e.mySerializedDataVc = null, " + "e.myWarningMessage = :warningMessage WHERE e.myId = :id") void updateChunkStatusAndClearDataForEndSuccess( @Param("id") String theChunkId, @@ -77,7 +77,7 @@ void updateChunkStatusAndClearDataForEndSuccess( @Modifying @Query( - "UPDATE Batch2WorkChunkEntity e SET e.myStatus = :status, e.myEndTime = :et, e.mySerializedData = null, e.myErrorMessage = :em WHERE e.myId IN(:ids)") + "UPDATE Batch2WorkChunkEntity e SET e.myStatus = :status, e.myEndTime = :et, e.mySerializedData = null, e.mySerializedDataVc = null, e.myErrorMessage = :em WHERE e.myId IN(:ids)") void updateAllChunksForInstanceStatusClearDataAndSetError( @Param("ids") List theChunkIds, @Param("et") Date theEndTime, diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2JobInstanceEntity.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2JobInstanceEntity.java index dd9205a8f306..889ec2aa95a1 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2JobInstanceEntity.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2JobInstanceEntity.java @@ -21,6 +21,7 @@ import ca.uhn.fhir.batch2.model.JobDefinition; import ca.uhn.fhir.batch2.model.StatusEnum; +import ca.uhn.fhir.jpa.model.util.JpaConstants; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -43,6 +44,7 @@ import static ca.uhn.fhir.batch2.model.JobDefinition.ID_MAX_LENGTH; import static ca.uhn.fhir.jpa.entity.Batch2WorkChunkEntity.ERROR_MSG_MAX_LENGTH; import static ca.uhn.fhir.jpa.entity.Batch2WorkChunkEntity.WARNING_MSG_MAX_LENGTH; +import static ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable.RES_TEXT_VC_MAX_LENGTH; import static org.apache.commons.lang3.StringUtils.left; @Entity @@ -93,13 +95,18 @@ public class Batch2JobInstanceEntity implements Serializable { @Column(name = "FAST_TRACKING", nullable = true) private Boolean myFastTracking; + // TODO: VC column added in 7.2.0 - Remove non-VC column later @Column(name = "PARAMS_JSON", length = PARAMS_JSON_MAX_LENGTH, nullable = true) private String myParamsJson; - @Lob + @Lob // TODO: VC column added in 7.2.0 - Remove non-VC column later @Column(name = "PARAMS_JSON_LOB", nullable = true) private String myParamsJsonLob; + @Column(name = "PARAMS_JSON_VC", nullable = true, length = RES_TEXT_VC_MAX_LENGTH) + @org.hibernate.annotations.Type(type = JpaConstants.ORG_HIBERNATE_TYPE_TEXT_TYPE) + private String myParamsJsonVc; + @Column(name = "CMB_RECS_PROCESSED", nullable = true) private Integer myCombinedRecordsProcessed; @@ -134,11 +141,15 @@ public class Batch2JobInstanceEntity implements Serializable { * Any output from the job can be held in this column * Even serialized json */ - @Lob + @Lob // TODO: VC column added in 7.2.0 - Remove non-VC column later @Basic(fetch = FetchType.LAZY) @Column(name = "REPORT", nullable = true, length = Integer.MAX_VALUE - 1) private String myReport; + @Column(name = "REPORT_VC", nullable = true, length = RES_TEXT_VC_MAX_LENGTH) + @org.hibernate.annotations.Type(type = JpaConstants.ORG_HIBERNATE_TYPE_TEXT_TYPE) + private String myReportVc; + public String getCurrentGatedStepId() { return myCurrentGatedStepId; } @@ -252,6 +263,9 @@ public void setStatus(StatusEnum theStatus) { } public String getParams() { + if (myParamsJsonVc != null) { + return myParamsJsonVc; + } if (myParamsJsonLob != null) { return myParamsJsonLob; } @@ -259,13 +273,9 @@ public String getParams() { } public void setParams(String theParams) { + myParamsJsonVc = theParams; myParamsJsonLob = null; myParamsJson = null; - if (theParams != null && theParams.length() > PARAMS_JSON_MAX_LENGTH) { - myParamsJsonLob = theParams; - } else { - myParamsJson = theParams; - } } public boolean getWorkChunksPurged() { @@ -301,11 +311,12 @@ public void setEstimatedTimeRemaining(String theEstimatedTimeRemaining) { } public String getReport() { - return myReport; + return myReportVc != null ? myReportVc : myReport; } public void setReport(String theReport) { - myReport = theReport; + myReportVc = theReport; + myReport = null; } public String getWarningMessages() { @@ -336,7 +347,7 @@ public String toString() { .append("progress", myProgress) .append("errorMessage", myErrorMessage) .append("estimatedTimeRemaining", myEstimatedTimeRemaining) - .append("report", myReport) + .append("report", getReport()) .append("warningMessages", myWarningMessages) .toString(); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2WorkChunkEntity.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2WorkChunkEntity.java index e65c8814faa7..338c6a883a9b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2WorkChunkEntity.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2WorkChunkEntity.java @@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.entity; import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; +import ca.uhn.fhir.jpa.model.util.JpaConstants; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -44,6 +45,7 @@ import static ca.uhn.fhir.batch2.model.JobDefinition.ID_MAX_LENGTH; import static ca.uhn.fhir.jpa.entity.Batch2JobInstanceEntity.STATUS_MAX_LENGTH; +import static ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable.RES_TEXT_VC_MAX_LENGTH; import static org.apache.commons.lang3.StringUtils.left; @Entity @@ -92,11 +94,15 @@ public class Batch2WorkChunkEntity implements Serializable { @Column(name = "TGT_STEP_ID", length = ID_MAX_LENGTH, nullable = false) private String myTargetStepId; - @Lob + @Lob // TODO: VC column added in 7.2.0 - Remove non-VC column later @Basic(fetch = FetchType.LAZY) @Column(name = "CHUNK_DATA", nullable = true, length = Integer.MAX_VALUE - 1) private String mySerializedData; + @Column(name = "CHUNK_DATA_VC", nullable = true, length = RES_TEXT_VC_MAX_LENGTH) + @org.hibernate.annotations.Type(type = JpaConstants.ORG_HIBERNATE_TYPE_TEXT_TYPE) + private String mySerializedDataVc; + @Column(name = "STAT", length = STATUS_MAX_LENGTH, nullable = false) @Enumerated(EnumType.STRING) private WorkChunkStatusEnum myStatus; @@ -263,11 +269,12 @@ public void setTargetStepId(String theTargetStepId) { } public String getSerializedData() { - return mySerializedData; + return mySerializedDataVc != null ? mySerializedDataVc : mySerializedData; } public void setSerializedData(String theSerializedData) { - mySerializedData = theSerializedData; + mySerializedData = null; + mySerializedDataVc = theSerializedData; } public WorkChunkStatusEnum getStatus() { @@ -309,7 +316,7 @@ public String toString() { .append("updateTime", myUpdateTime) .append("recordsProcessed", myRecordsProcessed) .append("targetStepId", myTargetStepId) - .append("serializedData", mySerializedData) + .append("serializedData", getSerializedData()) .append("status", myStatus) .append("errorMessage", myErrorMessage) .append("warningMessage", myWarningMessage) diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/BulkImportJobFileEntity.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/BulkImportJobFileEntity.java index 11a2998989f1..7beb524caab3 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/BulkImportJobFileEntity.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/BulkImportJobFileEntity.java @@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.entity; import ca.uhn.fhir.jpa.bulk.imprt.model.BulkImportJobFileJson; +import ca.uhn.fhir.jpa.model.util.JpaConstants; import java.io.Serializable; import java.nio.charset.StandardCharsets; @@ -36,6 +37,7 @@ import javax.persistence.SequenceGenerator; import javax.persistence.Table; +import static ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable.RES_TEXT_VC_MAX_LENGTH; import static org.apache.commons.lang3.StringUtils.left; @Entity @@ -66,10 +68,14 @@ public class BulkImportJobFileEntity implements Serializable { @Column(name = "FILE_DESCRIPTION", nullable = true, length = MAX_DESCRIPTION_LENGTH) private String myFileDescription; - @Lob - @Column(name = "JOB_CONTENTS", nullable = false) + @Lob // TODO: VC column added in 7.2.0 - Remove non-VC column later + @Column(name = "JOB_CONTENTS", nullable = true) private byte[] myContents; + @Column(name = "JOB_CONTENTS_VC", nullable = true, length = RES_TEXT_VC_MAX_LENGTH) + @org.hibernate.annotations.Type(type = JpaConstants.ORG_HIBERNATE_TYPE_TEXT_TYPE) + private String myContentsVc; + @Column(name = "TENANT_NAME", nullable = true, length = PartitionEntity.MAX_NAME_LENGTH) private String myTenantName; @@ -98,11 +104,16 @@ public void setFileSequence(int theFileSequence) { } public String getContents() { - return new String(myContents, StandardCharsets.UTF_8); + if (myContentsVc != null) { + return myContentsVc; + } else { + return new String(myContents, StandardCharsets.UTF_8); + } } public void setContents(String theContents) { - myContents = theContents.getBytes(StandardCharsets.UTF_8); + myContentsVc = theContents; + myContents = null; } public BulkImportJobFileJson toJson() { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Search.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Search.java index 7da0b2e22481..9f923b4d570a 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Search.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Search.java @@ -21,6 +21,7 @@ import ca.uhn.fhir.interceptor.model.RequestPartitionId; import ca.uhn.fhir.jpa.model.search.SearchStatusEnum; +import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.rest.param.DateRangeParam; @@ -30,6 +31,7 @@ import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.builder.ToStringBuilder; import org.hibernate.annotations.OptimisticLock; +import org.hibernate.annotations.Type; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -64,6 +66,7 @@ import javax.persistence.UniqueConstraint; import javax.persistence.Version; +import static ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable.RES_TEXT_VC_MAX_LENGTH; import static org.apache.commons.lang3.StringUtils.left; @Entity @@ -139,14 +142,22 @@ public class Search implements ICachedSearchDetails, Serializable { @Column(name = "RESOURCE_TYPE", length = 200, nullable = true) private String myResourceType; + /** * Note that this field may have the request partition IDs prepended to it */ - @Lob() + @Lob // TODO: VC column added in 7.2.0 - Remove non-VC column later @Basic(fetch = FetchType.LAZY) @Column(name = "SEARCH_QUERY_STRING", nullable = true, updatable = false, length = MAX_SEARCH_QUERY_STRING) private String mySearchQueryString; + /** + * Note that this field may have the request partition IDs prepended to it + */ + @Column(name = "SEARCH_QUERY_STRING_VC", nullable = true, length = RES_TEXT_VC_MAX_LENGTH) + @org.hibernate.annotations.Type(type = JpaConstants.ORG_HIBERNATE_TYPE_TEXT_TYPE) + private String mySearchQueryStringVc; + @Column(name = "SEARCH_QUERY_STRING_HASH", nullable = true, updatable = false) private Integer mySearchQueryStringHash; @@ -169,10 +180,14 @@ public class Search implements ICachedSearchDetails, Serializable { @Column(name = "OPTLOCK_VERSION", nullable = true) private Integer myVersion; - @Lob + @Lob // TODO: VC column added in 7.2.0 - Remove non-VC column later @Column(name = "SEARCH_PARAM_MAP", nullable = true) private byte[] mySearchParameterMap; + @Column(name = "SEARCH_PARAM_MAP_BIN", nullable = true, length = JpaConstants.ORG_HIBERNATE_TYPE_BINARY_TYPE_LENGTH) + @Type(type = JpaConstants.ORG_HIBERNATE_TYPE_BINARY_TYPE) + private byte[] mySearchParameterMapBin; + @Transient private transient SearchParameterMap mySearchParameterMapTransient; @@ -347,7 +362,7 @@ public void setResourceType(String theResourceType) { * Note that this field may have the request partition IDs prepended to it */ public String getSearchQueryString() { - return mySearchQueryString; + return mySearchQueryStringVc != null ? mySearchQueryStringVc : mySearchQueryString; } public void setSearchQueryString(String theSearchQueryString, RequestPartitionId theRequestPartitionId) { @@ -359,12 +374,13 @@ public void setSearchQueryString(String theSearchQueryString, RequestPartitionId // We want this field to always have a wide distribution of values in order // to avoid optimizers avoiding using it if it has lots of nulls, so in the // case of null, just put a value that will never be hit - mySearchQueryString = UUID.randomUUID().toString(); + mySearchQueryStringVc = UUID.randomUUID().toString(); } else { - mySearchQueryString = searchQueryString; + mySearchQueryStringVc = searchQueryString; } - mySearchQueryStringHash = mySearchQueryString.hashCode(); + mySearchQueryString = null; + mySearchQueryStringHash = mySearchQueryStringVc.hashCode(); } public SearchTypeEnum getSearchType() { @@ -463,8 +479,12 @@ public Optional getSearchParameterMap() { return Optional.of(mySearchParameterMapTransient); } SearchParameterMap searchParameterMap = null; - if (mySearchParameterMap != null) { - searchParameterMap = SerializationUtils.deserialize(mySearchParameterMap); + byte[] searchParameterMapSerialized = mySearchParameterMapBin; + if (searchParameterMapSerialized == null) { + searchParameterMapSerialized = mySearchParameterMap; + } + if (searchParameterMapSerialized != null) { + searchParameterMap = SerializationUtils.deserialize(searchParameterMapSerialized); mySearchParameterMapTransient = searchParameterMap; } return Optional.ofNullable(searchParameterMap); @@ -472,7 +492,8 @@ public Optional getSearchParameterMap() { public void setSearchParameterMap(SearchParameterMap theSearchParameterMap) { mySearchParameterMapTransient = theSearchParameterMap; - mySearchParameterMap = SerializationUtils.serialize(theSearchParameterMap); + mySearchParameterMapBin = SerializationUtils.serialize(theSearchParameterMap); + mySearchParameterMap = null; } @Override diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java index 9d2734a3217a..1909668f093d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java @@ -93,6 +93,45 @@ public HapiFhirJpaMigrationTasks(Set theFlags) { init640_after_20230126(); init660(); init680(); + init680_Part2(); + } + + private void init680_Part2() { + Builder version = forVersion(VersionEnum.V6_8_0); + + // Add additional LOB migration columns + version.onTable("BT2_JOB_INSTANCE") + .addColumn("20240227.1", "REPORT_VC") + .nullable() + .type(ColumnTypeEnum.TEXT); + version.onTable("BT2_JOB_INSTANCE") + .addColumn("20240227.2", "PARAMS_JSON_VC") + .nullable() + .type(ColumnTypeEnum.TEXT); + + version.onTable("BT2_WORK_CHUNK") + .addColumn("20240227.3", "CHUNK_DATA_VC") + .nullable() + .type(ColumnTypeEnum.TEXT); + + version.onTable("HFJ_SEARCH") + .addColumn("20240227.4", "SEARCH_QUERY_STRING_VC") + .nullable() + .type(ColumnTypeEnum.TEXT); + version.onTable("HFJ_SEARCH") + .addColumn("20240227.5", "SEARCH_PARAM_MAP_BIN") + .nullable() + .type(ColumnTypeEnum.BINARY); + + version.onTable("HFJ_BLK_IMPORT_JOBFILE") + .addColumn("20240227.6", "JOB_CONTENTS_VC") + .nullable() + .type(ColumnTypeEnum.TEXT); + + version.onTable("HFJ_BLK_IMPORT_JOBFILE") + .modifyColumn("20240227.7", "JOB_CONTENTS") + .nullable() + .withType(ColumnTypeEnum.BLOB); } protected void init680() { diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/util/JpaConstants.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/util/JpaConstants.java index b0fb197f4c43..b164ddbc268d 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/util/JpaConstants.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/util/JpaConstants.java @@ -301,6 +301,18 @@ public class JpaConstants { public static final String SUMMARY_OPERATION_URL = "http://hl7.org/fhir/uv/ips/OperationDefinition/summary"; public static final String ORG_HIBERNATE_TYPE_TEXT_TYPE = "org.hibernate.type.TextType"; + /** + * Columns annotated with this type must use a max length of {@link #ORG_HIBERNATE_TYPE_BINARY_TYPE_LENGTH} + */ + public static final String ORG_HIBERNATE_TYPE_BINARY_TYPE = "org.hibernate.type.BinaryType"; + /** + * This length is chosen because it's the max length supported by H2 - It is long enough + * that all the real databases replace it with an unlimited length type anyhow. + * + * @see #ORG_HIBERNATE_TYPE_BINARY_TYPE + */ + public static final int ORG_HIBERNATE_TYPE_BINARY_TYPE_LENGTH = 1000000000; + public static final String BULK_META_EXTENSION_EXPORT_IDENTIFIER = "https://hapifhir.org/NamingSystem/bulk-export-identifier"; public static final String BULK_META_EXTENSION_JOB_ID = "https://hapifhir.org/NamingSystem/bulk-export-job-id"; diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/JdbcUtils.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/JdbcUtils.java index b9863105de6c..d7ccc696bd19 100644 --- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/JdbcUtils.java +++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/JdbcUtils.java @@ -205,14 +205,7 @@ public static ColumnType getColumnType( case Types.BLOB: return new ColumnType(ColumnTypeEnum.BLOB, length); case Types.LONGVARBINARY: - if (DriverTypeEnum.MYSQL_5_7.equals(theConnectionProperties.getDriverType())) { - // See git - return new ColumnType(ColumnTypeEnum.BLOB, length); - } else { - throw new IllegalArgumentException( - Msg.code(32) + "Don't know how to handle datatype " + dataType - + " for column " + theColumnName + " on table " + theTableName); - } + return new ColumnType(ColumnTypeEnum.BINARY, length); case Types.VARBINARY: if (DriverTypeEnum.MSSQL_2012.equals(theConnectionProperties.getDriverType())) { // MS SQLServer seems to be mapping BLOB to VARBINARY under the covers, so we need diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ColumnTypeEnum.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ColumnTypeEnum.java index d78223f77736..ab779d3e66ac 100644 --- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ColumnTypeEnum.java +++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ColumnTypeEnum.java @@ -31,5 +31,8 @@ public enum ColumnTypeEnum { BLOB, CLOB, DOUBLE, - TEXT; + /** Long inline text */ + TEXT, + /** Long inline binary */ + BINARY; } diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ColumnTypeToDriverTypeToSqlType.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ColumnTypeToDriverTypeToSqlType.java index 03b222718cd2..9b359cf6608e 100644 --- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ColumnTypeToDriverTypeToSqlType.java +++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ColumnTypeToDriverTypeToSqlType.java @@ -127,9 +127,17 @@ private ColumnTypeToDriverTypeToSqlType() {} setColumnType(ColumnTypeEnum.TEXT, DriverTypeEnum.DERBY_EMBEDDED, "long varchar"); setColumnType(ColumnTypeEnum.TEXT, DriverTypeEnum.MARIADB_10_1, "longtext"); setColumnType(ColumnTypeEnum.TEXT, DriverTypeEnum.MYSQL_5_7, "longtext"); - setColumnType(ColumnTypeEnum.TEXT, DriverTypeEnum.ORACLE_12C, "long"); + setColumnType(ColumnTypeEnum.TEXT, DriverTypeEnum.ORACLE_12C, "clob"); setColumnType(ColumnTypeEnum.TEXT, DriverTypeEnum.POSTGRES_9_4, "text"); setColumnType(ColumnTypeEnum.TEXT, DriverTypeEnum.MSSQL_2012, "varchar(MAX)"); + + setColumnType(ColumnTypeEnum.BINARY, DriverTypeEnum.H2_EMBEDDED, "binary(1000000000)"); + setColumnType(ColumnTypeEnum.BINARY, DriverTypeEnum.DERBY_EMBEDDED, "varchar(1000000000) for bit data"); + setColumnType(ColumnTypeEnum.BINARY, DriverTypeEnum.MARIADB_10_1, "longblob"); + setColumnType(ColumnTypeEnum.BINARY, DriverTypeEnum.MYSQL_5_7, "longblob"); + setColumnType(ColumnTypeEnum.BINARY, DriverTypeEnum.ORACLE_12C, "blob"); + setColumnType(ColumnTypeEnum.BINARY, DriverTypeEnum.POSTGRES_9_4, "bytea"); + setColumnType(ColumnTypeEnum.BINARY, DriverTypeEnum.MSSQL_2012, "varbinary(MAX)"); } public static Map> getColumnTypeToDriverTypeToSqlType() { diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ModifyColumnTask.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ModifyColumnTask.java index 7cb486079d87..b28216172c3e 100644 --- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ModifyColumnTask.java +++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ModifyColumnTask.java @@ -133,9 +133,10 @@ public void doExecute() throws SQLException { } break; case ORACLE_12C: - String oracleNullableStmt = !alreadyCorrectNullable ? notNull : ""; - sql = "alter table " + getTableName() + " modify ( " + getColumnName() + " " + type + oracleNullableStmt - + " )"; + String oracleNullableStmt = alreadyCorrectNullable ? "" : notNull; + String oracleTypeStmt = alreadyOfCorrectType ? "" : type; + sql = "alter table " + getTableName() + " modify ( " + getColumnName() + " " + oracleTypeStmt + " " + + oracleNullableStmt + " )"; break; case MSSQL_2012: sql = "alter table " + getTableName() + " alter column " + getColumnName() + " " + type + notNull; diff --git a/pom.xml b/pom.xml index b66a3fbac915..236024752234 100644 --- a/pom.xml +++ b/pom.xml @@ -2438,6 +2438,7 @@ true false UTF-8 + true