Add hash identity token mode (#6375)

* Add hash identity token mode

* Spotless

* Test fix
This commit is contained in:
James Agnew 2024-10-16 18:08:43 -04:00 committed by GitHub
parent d4227baf2a
commit 4ab958a58f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 161 additions and 30 deletions

View File

@ -0,0 +1,6 @@
---
type: add
issue: 6375
title: "A new experimental JPA setting has been added to JpaStorageSettings which
causes searches for token SearchParameters to include a predicate on the
HASH_IDENTITY column even if it is not needed because other hashes are in use."

View File

@ -48,6 +48,7 @@ import ca.uhn.fhir.rest.param.TokenParamModifier;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.util.FhirVersionIndependentConcept; import ca.uhn.fhir.util.FhirVersionIndependentConcept;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.healthmarketscience.sqlbuilder.BinaryCondition; import com.healthmarketscience.sqlbuilder.BinaryCondition;
import com.healthmarketscience.sqlbuilder.Condition; import com.healthmarketscience.sqlbuilder.Condition;
@ -78,6 +79,7 @@ public class TokenPredicateBuilder extends BaseSearchParamPredicateBuilder {
private final DbColumn myColumnHashValue; private final DbColumn myColumnHashValue;
private final DbColumn myColumnSystem; private final DbColumn myColumnSystem;
private final DbColumn myColumnValue; private final DbColumn myColumnValue;
private final DbColumn myColumnHashIdentity;
@Autowired @Autowired
private IValidationSupport myValidationSupport; private IValidationSupport myValidationSupport;
@ -97,6 +99,7 @@ public class TokenPredicateBuilder extends BaseSearchParamPredicateBuilder {
public TokenPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) { public TokenPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_SPIDX_TOKEN")); super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_SPIDX_TOKEN"));
myColumnResId = getTable().addColumn("RES_ID"); myColumnResId = getTable().addColumn("RES_ID");
myColumnHashIdentity = getTable().addColumn("HASH_IDENTITY");
myColumnHashSystem = getTable().addColumn("HASH_SYS"); myColumnHashSystem = getTable().addColumn("HASH_SYS");
myColumnHashSystemAndValue = getTable().addColumn("HASH_SYS_AND_VALUE"); myColumnHashSystemAndValue = getTable().addColumn("HASH_SYS_AND_VALUE");
myColumnHashValue = getTable().addColumn("HASH_VALUE"); myColumnHashValue = getTable().addColumn("HASH_VALUE");
@ -104,6 +107,16 @@ public class TokenPredicateBuilder extends BaseSearchParamPredicateBuilder {
myColumnValue = getTable().addColumn("SP_VALUE"); myColumnValue = getTable().addColumn("SP_VALUE");
} }
@Override
public DbColumn getColumnHashIdentity() {
return myColumnHashIdentity;
}
@VisibleForTesting
public void setStorageSettingsForUnitTest(JpaStorageSettings theStorageSettings) {
myStorageSettings = theStorageSettings;
}
@Override @Override
public DbColumn getResourceIdColumn() { public DbColumn getResourceIdColumn() {
return myColumnResId; return myColumnResId;
@ -257,6 +270,14 @@ public class TokenPredicateBuilder extends BaseSearchParamPredicateBuilder {
} else { } else {
predicate = createPredicateOrList(theResourceName, paramName, sortedCodesList, true); predicate = createPredicateOrList(theResourceName, paramName, sortedCodesList, true);
if (myStorageSettings.isIncludeHashIdentityForTokenSearches()) {
long hashIdentity = BaseResourceIndexedSearchParam.calculateHashIdentity(
getPartitionSettings(), theRequestPartitionId, theResourceName, paramName);
Condition hashIdentityPredicate =
BinaryCondition.equalTo(getColumnHashIdentity(), generatePlaceholder(hashIdentity));
predicate = QueryParameterUtils.toAndPredicate(hashIdentityPredicate, predicate);
}
} }
return predicate; return predicate;

View File

@ -38,13 +38,13 @@ import jakarta.persistence.Lob;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany; import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne; import jakarta.persistence.OneToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.persistence.Transient; import jakarta.persistence.Transient;
import jakarta.persistence.UniqueConstraint; import jakarta.persistence.UniqueConstraint;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.Length; import org.hibernate.Length;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.OptimisticLock; import org.hibernate.annotations.OptimisticLock;
import java.io.Serializable; import java.io.Serializable;
@ -78,7 +78,9 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id @Id
@SequenceGenerator(name = "SEQ_RESOURCE_HISTORY_ID", sequenceName = "SEQ_RESOURCE_HISTORY_ID") @GenericGenerator(
name = "SEQ_RESOURCE_HISTORY_ID",
type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESOURCE_HISTORY_ID") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESOURCE_HISTORY_ID")
@Column(name = "PID") @Column(name = "PID")
private Long myId; private Long myId;

View File

@ -29,9 +29,9 @@ import jakarta.persistence.Id;
import jakarta.persistence.Index; import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint; import jakarta.persistence.UniqueConstraint;
import org.hibernate.annotations.GenericGenerator;
import java.io.Serializable; import java.io.Serializable;
@ -49,7 +49,7 @@ public class ResourceHistoryTag extends BaseTag implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@SequenceGenerator(name = "SEQ_HISTORYTAG_ID", sequenceName = "SEQ_HISTORYTAG_ID") @GenericGenerator(name = "SEQ_HISTORYTAG_ID", type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_HISTORYTAG_ID") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_HISTORYTAG_ID")
@Id @Id
@Column(name = "PID") @Column(name = "PID")

View File

@ -29,7 +29,6 @@ import jakarta.persistence.Id;
import jakarta.persistence.Index; import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.builder.CompareToBuilder;
@ -37,6 +36,7 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.GenericGenerator;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
/** /**
@ -76,7 +76,9 @@ public class ResourceIndexedComboStringUnique extends BaseResourceIndexedCombo
public static final String IDX_IDXCMPSTRUNIQ_STRING = "IDX_IDXCMPSTRUNIQ_STRING"; public static final String IDX_IDXCMPSTRUNIQ_STRING = "IDX_IDXCMPSTRUNIQ_STRING";
public static final String IDX_IDXCMPSTRUNIQ_RESOURCE = "IDX_IDXCMPSTRUNIQ_RESOURCE"; public static final String IDX_IDXCMPSTRUNIQ_RESOURCE = "IDX_IDXCMPSTRUNIQ_RESOURCE";
@SequenceGenerator(name = "SEQ_IDXCMPSTRUNIQ_ID", sequenceName = "SEQ_IDXCMPSTRUNIQ_ID") @GenericGenerator(
name = "SEQ_IDXCMPSTRUNIQ_ID",
type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_IDXCMPSTRUNIQ_ID") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_IDXCMPSTRUNIQ_ID")
@Id @Id
@Column(name = "PID") @Column(name = "PID")

View File

@ -31,13 +31,13 @@ import jakarta.persistence.Id;
import jakarta.persistence.Index; import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.persistence.Transient; import jakarta.persistence.Transient;
import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.hibernate.annotations.GenericGenerator;
@Entity @Entity
@Table( @Table(
@ -51,7 +51,9 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
public class ResourceIndexedComboTokenNonUnique extends BaseResourceIndexedCombo public class ResourceIndexedComboTokenNonUnique extends BaseResourceIndexedCombo
implements Comparable<ResourceIndexedComboTokenNonUnique>, IResourceIndexComboSearchParameter { implements Comparable<ResourceIndexedComboTokenNonUnique>, IResourceIndexComboSearchParameter {
@SequenceGenerator(name = "SEQ_IDXCMBTOKNU_ID", sequenceName = "SEQ_IDXCMBTOKNU_ID") @GenericGenerator(
name = "SEQ_IDXCMBTOKNU_ID",
type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_IDXCMBTOKNU_ID") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_IDXCMBTOKNU_ID")
@Id @Id
@Column(name = "PID") @Column(name = "PID")

View File

@ -35,12 +35,12 @@ import jakarta.persistence.Id;
import jakarta.persistence.Index; import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.GenericGenerator;
@Embeddable @Embeddable
@EntityListeners(IndexStorageOptimizationListener.class) @EntityListeners(IndexStorageOptimizationListener.class)
@ -67,7 +67,7 @@ public class ResourceIndexedSearchParamCoords extends BaseResourceIndexedSearchP
public Double myLongitude; public Double myLongitude;
@Id @Id
@SequenceGenerator(name = "SEQ_SPIDX_COORDS", sequenceName = "SEQ_SPIDX_COORDS") @GenericGenerator(name = "SEQ_SPIDX_COORDS", type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_COORDS") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_COORDS")
@Column(name = "SP_ID") @Column(name = "SP_ID")
private Long myId; private Long myId;

View File

@ -39,7 +39,6 @@ import jakarta.persistence.Id;
import jakarta.persistence.Index; import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.persistence.Temporal; import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType; import jakarta.persistence.TemporalType;
@ -49,6 +48,7 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
import org.hl7.fhir.r4.model.DateTimeType; import org.hl7.fhir.r4.model.DateTimeType;
@ -107,7 +107,7 @@ public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchPar
private transient String myOriginalValue; private transient String myOriginalValue;
@Id @Id
@SequenceGenerator(name = "SEQ_SPIDX_DATE", sequenceName = "SEQ_SPIDX_DATE") @GenericGenerator(name = "SEQ_SPIDX_DATE", type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_DATE") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_DATE")
@Column(name = "SP_ID") @Column(name = "SP_ID")
private Long myId; private Long myId;

View File

@ -35,12 +35,12 @@ import jakarta.persistence.Id;
import jakarta.persistence.Index; import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ScaledNumberField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ScaledNumberField;
import org.hibernate.type.SqlTypes; import org.hibernate.type.SqlTypes;
@ -68,7 +68,7 @@ public class ResourceIndexedSearchParamNumber extends BaseResourceIndexedSearchP
public BigDecimal myValue; public BigDecimal myValue;
@Id @Id
@SequenceGenerator(name = "SEQ_SPIDX_NUMBER", sequenceName = "SEQ_SPIDX_NUMBER") @GenericGenerator(name = "SEQ_SPIDX_NUMBER", type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_NUMBER") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_NUMBER")
@Column(name = "SP_ID") @Column(name = "SP_ID")
private Long myId; private Long myId;

View File

@ -35,12 +35,12 @@ import jakarta.persistence.Id;
import jakarta.persistence.Index; import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ScaledNumberField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ScaledNumberField;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -74,7 +74,9 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id @Id
@SequenceGenerator(name = "SEQ_SPIDX_QUANTITY", sequenceName = "SEQ_SPIDX_QUANTITY") @GenericGenerator(
name = "SEQ_SPIDX_QUANTITY",
type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_QUANTITY") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_QUANTITY")
@Column(name = "SP_ID") @Column(name = "SP_ID")
private Long myId; private Long myId;

View File

@ -36,13 +36,13 @@ import jakarta.persistence.Id;
import jakarta.persistence.Index; import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.fhir.ucum.Pair; import org.fhir.ucum.Pair;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ScaledNumberField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ScaledNumberField;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -80,7 +80,9 @@ public class ResourceIndexedSearchParamQuantityNormalized extends BaseResourceIn
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id @Id
@SequenceGenerator(name = "SEQ_SPIDX_QUANTITY_NRML", sequenceName = "SEQ_SPIDX_QUANTITY_NRML") @GenericGenerator(
name = "SEQ_SPIDX_QUANTITY_NRML",
type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_QUANTITY_NRML") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_QUANTITY_NRML")
@Column(name = "SP_ID") @Column(name = "SP_ID")
private Long myId; private Long myId;

View File

@ -37,12 +37,12 @@ import jakarta.persistence.Id;
import jakarta.persistence.Index; import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.GenericGenerator;
import static ca.uhn.fhir.jpa.model.util.SearchParamHash.hashSearchParam; import static ca.uhn.fhir.jpa.model.util.SearchParamHash.hashSearchParam;
import static org.apache.commons.lang3.StringUtils.defaultString; import static org.apache.commons.lang3.StringUtils.defaultString;
@ -78,7 +78,7 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id @Id
@SequenceGenerator(name = "SEQ_SPIDX_STRING", sequenceName = "SEQ_SPIDX_STRING") @GenericGenerator(name = "SEQ_SPIDX_STRING", type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_STRING") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_STRING")
@Column(name = "SP_ID") @Column(name = "SP_ID")
private Long myId; private Long myId;

View File

@ -39,13 +39,13 @@ import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.PrePersist; import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate; import jakarta.persistence.PreUpdate;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
import static ca.uhn.fhir.jpa.model.util.SearchParamHash.hashSearchParam; import static ca.uhn.fhir.jpa.model.util.SearchParamHash.hashSearchParam;
@ -89,7 +89,7 @@ public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchPa
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Id @Id
@SequenceGenerator(name = "SEQ_SPIDX_TOKEN", sequenceName = "SEQ_SPIDX_TOKEN") @GenericGenerator(name = "SEQ_SPIDX_TOKEN", type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_TOKEN") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_TOKEN")
@Column(name = "SP_ID") @Column(name = "SP_ID")
private Long myId; private Long myId;

View File

@ -36,12 +36,12 @@ import jakarta.persistence.Id;
import jakarta.persistence.Index; import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
import static ca.uhn.fhir.jpa.model.util.SearchParamHash.hashSearchParam; import static ca.uhn.fhir.jpa.model.util.SearchParamHash.hashSearchParam;
@ -76,7 +76,7 @@ public class ResourceIndexedSearchParamUri extends BaseResourceIndexedSearchPara
public String myUri; public String myUri;
@Id @Id
@SequenceGenerator(name = "SEQ_SPIDX_URI", sequenceName = "SEQ_SPIDX_URI") @GenericGenerator(name = "SEQ_SPIDX_URI", type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_URI") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_URI")
@Column(name = "SP_ID") @Column(name = "SP_ID")
private Long myId; private Long myId;

View File

@ -31,7 +31,6 @@ import jakarta.persistence.Id;
import jakarta.persistence.Index; import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.persistence.Temporal; import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType; import jakarta.persistence.TemporalType;
@ -39,6 +38,7 @@ import jakarta.persistence.Transient;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
@ -63,7 +63,7 @@ public class ResourceLink extends BaseResourceIndex {
public static final int SRC_PATH_LENGTH = 500; public static final int SRC_PATH_LENGTH = 500;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@SequenceGenerator(name = "SEQ_RESLINK_ID", sequenceName = "SEQ_RESLINK_ID") @GenericGenerator(name = "SEQ_RESLINK_ID", type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESLINK_ID") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESLINK_ID")
@Id @Id
@Column(name = "PID") @Column(name = "PID")

View File

@ -29,13 +29,13 @@ import jakarta.persistence.Id;
import jakarta.persistence.Index; import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint; import jakarta.persistence.UniqueConstraint;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.GenericGenerator;
@Entity @Entity
@Table( @Table(
@ -53,7 +53,7 @@ public class ResourceTag extends BaseTag {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@SequenceGenerator(name = "SEQ_RESTAG_ID", sequenceName = "SEQ_RESTAG_ID") @GenericGenerator(name = "SEQ_RESTAG_ID", type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESTAG_ID") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESTAG_ID")
@Id @Id
@Column(name = "PID") @Column(name = "PID")

View File

@ -31,7 +31,6 @@ import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.PrePersist; import jakarta.persistence.PrePersist;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.persistence.Transient; import jakarta.persistence.Transient;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
@ -39,6 +38,7 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.GenericGenerator;
import java.io.Serializable; import java.io.Serializable;
@ -57,7 +57,9 @@ public class SearchParamPresentEntity extends BasePartitionable implements Seria
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id @Id
@SequenceGenerator(name = "SEQ_RESPARMPRESENT_ID", sequenceName = "SEQ_RESPARMPRESENT_ID") @GenericGenerator(
name = "SEQ_RESPARMPRESENT_ID",
type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESPARMPRESENT_ID") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESPARMPRESENT_ID")
@Column(name = "PID") @Column(name = "PID")
private Long myId; private Long myId;

View File

@ -8,6 +8,7 @@ import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.UriParam; import ca.uhn.fhir.rest.param.UriParam;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
@ -18,6 +19,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -140,6 +142,38 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
return myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false); return myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
} }
/**
* One regular search params - Doesn't need HFJ_RESOURCE as root
*/
@Test
public void testSingleRegularSearchParam() {
myCaptureQueriesListener.clear();
SearchParameterMap map = SearchParameterMap.newSynchronous(Patient.SP_NAME, new StringParam("FOO"));
myPatientDao.search(map);
assertEquals(1, myCaptureQueriesListener.countSelectQueries());
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
assertEquals("SELECT t0.RES_ID FROM HFJ_SPIDX_STRING t0 WHERE ((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?))", sql);
}
/**
* Two regular search params - Should use HFJ_RESOURCE as root
*/
@Test
public void testTwoRegularSearchParams() {
myCaptureQueriesListener.clear();
SearchParameterMap map = SearchParameterMap.newSynchronous()
.add(Patient.SP_NAME, new StringParam("FOO"))
.add(Patient.SP_GENDER, new TokenParam("a", "b"));
myPatientDao.search(map);
assertEquals(1, myCaptureQueriesListener.countSelectQueries());
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
assertEquals("SELECT t1.RES_ID FROM HFJ_RESOURCE t1 INNER JOIN HFJ_SPIDX_STRING t0 ON (t1.RES_ID = t0.RES_ID) INNER JOIN HFJ_SPIDX_TOKEN t2 ON (t1.RES_ID = t2.RES_ID) WHERE (((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?)) AND (t2.HASH_SYS_AND_VALUE = ?))", sql);
}
@Test @Test
public void testSearchByProfile_VersionedMode() { public void testSearchByProfile_VersionedMode() {
@ -207,6 +241,27 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
myStorageSettings.setMarkResourcesForReindexingUponSearchParameterChange(reindexParamCache); myStorageSettings.setMarkResourcesForReindexingUponSearchParameterChange(reindexParamCache);
} }
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testSearchByToken_IncludeHashIdentity(boolean theIncludeHashIdentity) {
// Setup
myStorageSettings.setIncludeHashIdentityForTokenSearches(theIncludeHashIdentity);
// Test
myCaptureQueriesListener.clear();
SearchParameterMap params = SearchParameterMap.newSynchronous(Patient.SP_IDENTIFIER, new TokenParam("http://foo", "bar"));
IBundleProvider outcome = myPatientDao.search(params, mySrd);
assertEquals(0, outcome.sizeOrThrowNpe());
// Verify
if (theIncludeHashIdentity) {
assertEquals("SELECT t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE ((t0.HASH_IDENTITY = '7001889285610424179') AND (t0.HASH_SYS_AND_VALUE = '-2780914544385068076'))", myCaptureQueriesListener.getSelectQueries().get(0).getSql(true, false));
} else {
assertEquals("SELECT t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE (t0.HASH_SYS_AND_VALUE = '-2780914544385068076')", myCaptureQueriesListener.getSelectQueries().get(0).getSql(true, false));
}
}
public static class MyPartitionInterceptor { public static class MyPartitionInterceptor {
@Hook(STORAGE_PARTITION_IDENTIFY_ANY) @Hook(STORAGE_PARTITION_IDENTIFY_ANY)

View File

@ -389,6 +389,8 @@ public abstract class BaseJpaTest extends BaseTest {
JpaStorageSettings defaultConfig = new JpaStorageSettings(); JpaStorageSettings defaultConfig = new JpaStorageSettings();
myStorageSettings.setAdvancedHSearchIndexing(defaultConfig.isAdvancedHSearchIndexing()); myStorageSettings.setAdvancedHSearchIndexing(defaultConfig.isAdvancedHSearchIndexing());
myStorageSettings.setAllowContainsSearches(defaultConfig.isAllowContainsSearches()); myStorageSettings.setAllowContainsSearches(defaultConfig.isAllowContainsSearches());
myStorageSettings.setIncludeHashIdentityForTokenSearches(defaultConfig.isIncludeHashIdentityForTokenSearches());
} }
@AfterEach @AfterEach

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.search.builder.predicate;
import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.interceptor.model.RequestPartitionId; import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.model.config.PartitionSettings; import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder; import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
@ -58,6 +59,7 @@ public class TokenPredicateBuilderTest {
when(mySearchQueryBuilder.addTable(Mockito.anyString())).thenReturn(table); when(mySearchQueryBuilder.addTable(Mockito.anyString())).thenReturn(table);
when(mySearchQueryBuilder.getPartitionSettings()).thenReturn(new PartitionSettings()); when(mySearchQueryBuilder.getPartitionSettings()).thenReturn(new PartitionSettings());
myTokenPredicateBuilder = new TokenPredicateBuilder(mySearchQueryBuilder); myTokenPredicateBuilder = new TokenPredicateBuilder(mySearchQueryBuilder);
myTokenPredicateBuilder.setStorageSettingsForUnitTest(new JpaStorageSettings());
} }
@AfterEach @AfterEach

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
import ca.uhn.fhir.system.HapiSystemProperties; import ca.uhn.fhir.system.HapiSystemProperties;
import ca.uhn.fhir.util.HapiExtensions; import ca.uhn.fhir.util.HapiExtensions;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import com.google.common.annotations.Beta;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import jakarta.annotation.Nonnull; import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
@ -368,6 +369,16 @@ public class JpaStorageSettings extends StorageSettings {
*/ */
private boolean myWriteToLegacyLobColumns = false; private boolean myWriteToLegacyLobColumns = false;
/**
* If this is enabled (default is {@literal false}), searches on token indexes will
* include the {@literal HASH_IDENTITY} column on all generated FHIR search query SQL.
* This is an experimental flag that may be changed or removed in a future release.
*
* @since 7.6.0
*/
@Beta
private boolean myIncludeHashIdentityForTokenSearches = false;
/** /**
* Constructor * Constructor
*/ */
@ -396,6 +407,28 @@ public class JpaStorageSettings extends StorageSettings {
} }
} }
/**
* If this is enabled (default is {@literal false}), searches on token indexes will
* include the {@literal HASH_IDENTITY} column on all generated FHIR search query SQL.
* This is an experimental flag that may be changed or removed in a future release.
*
* @since 7.6.0
*/
public boolean isIncludeHashIdentityForTokenSearches() {
return myIncludeHashIdentityForTokenSearches;
}
/**
* If this is enabled (default is {@literal false}), searches on token indexes will
* include the {@literal HASH_IDENTITY} column on all generated FHIR search query SQL.
* This is an experimental flag that may be changed or removed in a future release.
*
* @since 7.6.0
*/
public void setIncludeHashIdentityForTokenSearches(boolean theIncludeHashIdentityForTokenSearches) {
myIncludeHashIdentityForTokenSearches = theIncludeHashIdentityForTokenSearches;
}
/** /**
* @since 5.7.0 * @since 5.7.0
* @deprecated This setting no longer does anything as of HAPI FHIR 7.0.0 * @deprecated This setting no longer does anything as of HAPI FHIR 7.0.0