diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml new file mode 100644 index 00000000000..ad6bbd02d1f --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 5877 +title: "Previously, updating a tokenParam with a value greater than 200 characters would raise a SQLException. +This issue has been fixed." diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamToken.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamToken.java index 2a8ba6e8d03..9066f9f25db 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamToken.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamToken.java @@ -36,6 +36,7 @@ import jakarta.persistence.Index; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.PrePersist; +import jakarta.persistence.PreUpdate; import jakarta.persistence.SequenceGenerator; import jakarta.persistence.Table; import org.apache.commons.lang3.StringUtils; @@ -429,6 +430,7 @@ public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchPa * We don't truncate earlier in the flow because the index hashes MUST be calculated on the full string. */ @PrePersist + @PreUpdate public void truncateFieldsForDB() { mySystem = StringUtils.truncate(mySystem, MAX_LENGTH); myValue = StringUtils.truncate(myValue, MAX_LENGTH); diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4Test.java index 649359d3937..d0e33aaba8c 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4Test.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4Test.java @@ -54,7 +54,6 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.util.ClasspathUtil; -import com.google.common.base.Charsets; import com.google.common.collect.Lists; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomStringUtils; @@ -83,6 +82,7 @@ import org.hl7.fhir.r4.model.CompartmentDefinition; import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.Condition; import org.hl7.fhir.r4.model.Consent; +import org.hl7.fhir.r4.model.ContactPoint; import org.hl7.fhir.r4.model.DateTimeType; import org.hl7.fhir.r4.model.DateType; import org.hl7.fhir.r4.model.Device; @@ -157,9 +157,11 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasLength; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.matchesPattern; import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.startsWith; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -247,6 +249,42 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test { return retVal; } + @Test + public void testUpdateResource_whenTokenPropertyAssignedTooLargeValue_willTruncateLargeValueOnUpdate(){ + // given + final String modifiedEmailPrefix = "modified"; + final String originalEmail = RandomStringUtils.randomAlphanumeric(ResourceIndexedSearchParamToken.MAX_LENGTH) + "@acme.corp"; + final String modifiedEmail = modifiedEmailPrefix + originalEmail; + + // when + Patient pt1 = new Patient(); + pt1.setActive(true); + pt1.addName().setFamily("FAM"); + pt1.addTelecom().setSystem(ContactPoint.ContactPointSystem.EMAIL).setValue(originalEmail); + + myPatientDao.create(pt1).getId().toUnqualifiedVersionless(); + + pt1.getTelecomFirstRep().setValue(modifiedEmail); + + IIdType id1 = myPatientDao.update(pt1).getId().toUnqualifiedVersionless(); + + // then + runInTransaction(() -> { + List paramValues = myResourceIndexedSearchParamTokenDao + .findAll() + .stream() + .filter(t -> defaultString(t.getSystem()).equals("email")) + .map(t -> t.getValue()) + .collect(Collectors.toList()); + + assertThat(paramValues, hasSize(2)); + + for (String tokenValue : paramValues) { + assertThat(tokenValue, startsWith(modifiedEmailPrefix)); + assertThat(tokenValue, hasLength(ResourceIndexedSearchParamToken.MAX_LENGTH)); + } + }); + } @Test public void testDeletedResourcesAreReindexed() {