diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java index a5bfbc6fb8f..9f6491c6b86 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java @@ -60,6 +60,8 @@ public class DaoConfig { * update setter javadoc if default changes */ private boolean myAllowExternalReferences = false; + private boolean myAllowContainsSearches = true; + /** * update setter javadoc if default changes */ @@ -1097,6 +1099,16 @@ public class DaoConfig { } + public boolean allowContainsSearches() { + + return myAllowContainsSearches; + } + + public void setAllowContainsSearches(boolean myAllowContainsSearches) { + + this.myAllowContainsSearches = myAllowContainsSearches; + } + public enum IndexEnabledEnum { ENABLED, DISABLED diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java index 417883ca0e0..9d157b8adcc 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java @@ -28,6 +28,7 @@ import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam; import ca.uhn.fhir.jpa.term.IHapiTerminologySvc; import ca.uhn.fhir.jpa.term.VersionIndependentConcept; import ca.uhn.fhir.jpa.util.BaseIterator; +import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; import ca.uhn.fhir.util.StopWatch; import ca.uhn.fhir.model.api.*; import ca.uhn.fhir.model.base.composite.BaseCodingDt; @@ -1090,6 +1091,11 @@ public class SearchBuilder implements ISearchBuilder { } else if (theParameter instanceof StringParam) { StringParam id = (StringParam) theParameter; rawSearchTerm = id.getValue(); + if ((id.isContains()) && + (!myCallingDao.getConfig().allowContainsSearches())) + { + throw new MethodNotAllowedException(":contains modifier is disabled on this server"); + } } else if (theParameter instanceof IPrimitiveDatatype) { IPrimitiveDatatype id = (IPrimitiveDatatype) theParameter; rawSearchTerm = id.getValueAsString(); @@ -1103,7 +1109,20 @@ public class SearchBuilder implements ISearchBuilder { } String likeExpression = BaseHapiFhirDao.normalizeString(rawSearchTerm); - likeExpression = createLeftMatchLikeExpression(likeExpression); + if (myCallingDao.getConfig().allowContainsSearches()) { + if (theParameter instanceof StringParam) { + if (((StringParam) theParameter).isContains()) { + likeExpression = createLeftAndRightMatchLikeExpression(likeExpression); + } else { + likeExpression = createLeftMatchLikeExpression(likeExpression); + } + } else { + likeExpression = createLeftMatchLikeExpression(likeExpression); + } + } + else { + likeExpression = createLeftMatchLikeExpression(likeExpression); + } Predicate singleCode = theBuilder.like(theFrom.get("myValueNormalized").as(String.class), likeExpression); if (theParameter instanceof StringParam && ((StringParam) theParameter).isExact()) { @@ -1997,6 +2016,10 @@ public class SearchBuilder implements ISearchBuilder { return likeExpression.replace("%", "[%]") + "%"; } + private static String createLeftAndRightMatchLikeExpression(String likeExpression) { + return "%" + likeExpression.replace("%", "[%]") + "%"; + } + private static Predicate createResourceLinkPathPredicate(IDao theCallingDao, FhirContext theContext, String theParamName, From theFrom, String theResourceType) { RuntimeResourceDefinition resourceDef = theContext.getResourceDefinition(theResourceType);