Compare commits

..

6 Commits

Author SHA1 Message Date
Michael Buckley 75b894e9b4 fixmes 2024-09-27 17:16:08 -04:00
Michael Buckley 93d520a422 cleanup 2024-09-27 17:13:52 -04:00
Michael Buckley e7fed79e5c cleanup 2024-09-27 17:13:27 -04:00
Michael Buckley 8ecc7728c7 changelog 2024-09-27 17:08:37 -04:00
Michael Buckley 40a2a7ceb7 spotless 2024-09-27 17:02:46 -04:00
Michael Buckley 75f7defc74 Give up on nullable join
:not joins require sub-selects
and the nullability can't
support an in(select ) clause.

Bring in flag, and set based on partition settings
2024-09-27 17:02:31 -04:00
8 changed files with 126 additions and 69 deletions

View File

@ -0,0 +1,4 @@
---
type: add
issue: 6325
title: "Add support for including the partitioning column in search query joins."

View File

@ -55,6 +55,7 @@ import ca.uhn.fhir.jpa.search.builder.predicate.StringPredicateBuilder;
import ca.uhn.fhir.jpa.search.builder.predicate.TagPredicateBuilder;
import ca.uhn.fhir.jpa.search.builder.predicate.TokenPredicateBuilder;
import ca.uhn.fhir.jpa.search.builder.predicate.UriPredicateBuilder;
import ca.uhn.fhir.jpa.search.builder.sql.ColumnTupleObject;
import ca.uhn.fhir.jpa.search.builder.sql.PredicateBuilderFactory;
import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
@ -359,7 +360,7 @@ public class QueryStack {
case STRING:
StringPredicateBuilder stringPredicateBuilder = mySqlBuilder.createStringPredicateBuilder();
addSortCustomJoin(
resourceLinkPredicateBuilder.getColumnTargetResourceId(),
resourceLinkPredicateBuilder.getJoinColumnsForTarget(),
stringPredicateBuilder,
stringPredicateBuilder.createHashIdentityPredicate(targetType, theChain));
@ -370,7 +371,7 @@ public class QueryStack {
case TOKEN:
TokenPredicateBuilder tokenPredicateBuilder = mySqlBuilder.createTokenPredicateBuilder();
addSortCustomJoin(
resourceLinkPredicateBuilder.getColumnTargetResourceId(),
resourceLinkPredicateBuilder.getJoinColumnsForTarget(),
tokenPredicateBuilder,
tokenPredicateBuilder.createHashIdentityPredicate(targetType, theChain));
@ -381,7 +382,7 @@ public class QueryStack {
case DATE:
DatePredicateBuilder datePredicateBuilder = mySqlBuilder.createDatePredicateBuilder();
addSortCustomJoin(
resourceLinkPredicateBuilder.getColumnTargetResourceId(),
resourceLinkPredicateBuilder.getJoinColumnsForTarget(),
datePredicateBuilder,
datePredicateBuilder.createHashIdentityPredicate(targetType, theChain));
@ -475,16 +476,16 @@ public class QueryStack {
BaseJoiningPredicateBuilder theFromJoiningPredicateBuilder,
BaseJoiningPredicateBuilder theToJoiningPredicateBuilder,
Condition theCondition) {
addSortCustomJoin(
theFromJoiningPredicateBuilder.getResourceIdColumn(), theToJoiningPredicateBuilder, theCondition);
addSortCustomJoin(theFromJoiningPredicateBuilder.getJoinColumns(), theToJoiningPredicateBuilder, theCondition);
}
private void addSortCustomJoin(
DbColumn theFromDbColumn,
DbColumn theFromDbColumn[],
BaseJoiningPredicateBuilder theToJoiningPredicateBuilder,
Condition theCondition) {
ComboCondition onCondition =
mySqlBuilder.createOnCondition(theFromDbColumn, theToJoiningPredicateBuilder.getResourceIdColumn());
mySqlBuilder.createOnCondition(theFromDbColumn, theToJoiningPredicateBuilder.getJoinColumns());
if (theCondition != null) {
onCondition.addCondition(theCondition);
@ -492,7 +493,7 @@ public class QueryStack {
mySqlBuilder.addCustomJoin(
SelectQuery.JoinType.LEFT_OUTER,
theFromDbColumn.getTable(),
theFromDbColumn[0].getTable(),
theToJoiningPredicateBuilder.getTable(),
onCondition);
}
@ -1476,12 +1477,12 @@ public class QueryStack {
public void addGrouping() {
BaseJoiningPredicateBuilder firstPredicateBuilder = mySqlBuilder.getOrCreateFirstPredicateBuilder();
mySqlBuilder.getSelect().addGroupings(firstPredicateBuilder.getResourceIdColumn());
mySqlBuilder.getSelect().addGroupings(firstPredicateBuilder.getJoinColumns());
}
public void addOrdering() {
BaseJoiningPredicateBuilder firstPredicateBuilder = mySqlBuilder.getOrCreateFirstPredicateBuilder();
mySqlBuilder.getSelect().addOrderings(firstPredicateBuilder.getResourceIdColumn());
mySqlBuilder.getSelect().addOrderings(firstPredicateBuilder.getJoinColumns());
}
public Condition createPredicateReferenceForEmbeddedChainedSearchResource(
@ -1529,7 +1530,7 @@ public class QueryStack {
for (LeafNodeDefinition leafNodeDefinition : referenceLinks.get(nextReferenceLink)) {
SearchQueryBuilder builder;
if (wantChainedAndNormal) {
builder = mySqlBuilder.newChildSqlBuilder();
builder = mySqlBuilder.newChildSqlBuilder(mySqlBuilder.isIncludePartitionIdInJoins());
} else {
builder = mySqlBuilder;
}
@ -1574,8 +1575,15 @@ public class QueryStack {
if (wantChainedAndNormal) {
if (theSourceJoinColumn == null) {
retVal = new InCondition(
mySqlBuilder.getOrCreateFirstPredicateBuilder(false).getResourceIdColumn(), union);
BaseJoiningPredicateBuilder root = mySqlBuilder.getOrCreateFirstPredicateBuilder(false);
DbColumn[] joinColumns = root.getJoinColumns();
Object joinColumnObject;
if (joinColumns.length == 1) {
joinColumnObject = joinColumns[0];
} else {
joinColumnObject = ColumnTupleObject.from(joinColumns);
}
retVal = new InCondition(joinColumnObject, union);
} else {
// -- for the resource link, need join with target_resource_id
retVal = new InCondition(theSourceJoinColumn, union);
@ -2050,7 +2058,8 @@ public class QueryStack {
BaseJoiningPredicateBuilder join;
if (paramInverted) {
SearchQueryBuilder sqlBuilder = mySqlBuilder.newChildSqlBuilder();
boolean selectPartitionId = myPartitionSettings.isPartitionIdsInPrimaryKeys();
SearchQueryBuilder sqlBuilder = mySqlBuilder.newChildSqlBuilder(selectPartitionId);
TagPredicateBuilder tagSelector = sqlBuilder.addTagPredicateBuilder(null);
sqlBuilder.addPredicate(
tagSelector.createPredicateTag(tagType, tokens, theParamName, theRequestPartitionId));
@ -2058,7 +2067,14 @@ public class QueryStack {
join = mySqlBuilder.getOrCreateFirstPredicateBuilder();
Expression subSelect = new Subquery(sql);
tagPredicate = new InCondition(join.getResourceIdColumn(), subSelect).setNegate(true);
Object left;
if (selectPartitionId) {
left = new ColumnTupleObject(join.getJoinColumns());
} else {
left = join.getResourceIdColumn();
}
tagPredicate = new InCondition(left, subSelect).setNegate(true);
} else {
// Tag table can't be a query root because it will include deleted resources, and can't select by
@ -2221,7 +2237,8 @@ public class QueryStack {
BaseJoiningPredicateBuilder join;
if (paramInverted) {
SearchQueryBuilder sqlBuilder = theSqlBuilder.newChildSqlBuilder();
boolean selectPartitionId = myPartitionSettings.isPartitionIdsInPrimaryKeys();
SearchQueryBuilder sqlBuilder = theSqlBuilder.newChildSqlBuilder(selectPartitionId);
TokenPredicateBuilder tokenSelector = sqlBuilder.addTokenPredicateBuilder(null);
sqlBuilder.addPredicate(tokenSelector.createPredicateToken(
tokens, theResourceName, theSpnamePrefix, theSearchParam, theRequestPartitionId));
@ -2230,13 +2247,16 @@ public class QueryStack {
join = theSqlBuilder.getOrCreateFirstPredicateBuilder();
DbColumn[] leftColumns;
if (theSourceJoinColumn == null) {
predicate = new InCondition(join.getResourceIdColumn(), subSelect).setNegate(true);
leftColumns = join.getJoinColumns();
} else {
// -- for the resource link, need join with target_resource_id
predicate = new InCondition(theSourceJoinColumn, subSelect).setNegate(true);
leftColumns = theSourceJoinColumn;
}
Object left = new ColumnTupleObject(leftColumns);
predicate = new InCondition(left, subSelect).setNegate(true);
} else {
Boolean isMissing = theList.get(0).getMissing();
if (isMissing != null) {

View File

@ -55,8 +55,9 @@ import com.healthmarketscience.sqlbuilder.FunctionCall;
import com.healthmarketscience.sqlbuilder.InCondition;
import com.healthmarketscience.sqlbuilder.OrderObject;
import com.healthmarketscience.sqlbuilder.SelectQuery;
import com.healthmarketscience.sqlbuilder.UnaryCondition;
import com.healthmarketscience.sqlbuilder.dbspec.Join;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbJoin;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSchema;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSpec;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbTable;
@ -74,7 +75,6 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
@ -102,6 +102,7 @@ public class SearchQueryBuilder {
private final SqlObjectFactory mySqlBuilderFactory;
private final boolean myCountQuery;
private final Dialect myDialect;
private final boolean mySelectPartitionId;
private boolean myMatchNothing;
private ResourceTablePredicateBuilder myResourceTableRoot;
private boolean myHaveAtLeastOnePredicate;
@ -135,7 +136,8 @@ public class SearchQueryBuilder {
UUID.randomUUID() + "-",
theDialectProvider.getDialect(),
theCountQuery,
new ArrayList<>());
new ArrayList<>(),
thePartitionSettings.isPartitionIdsInPrimaryKeys());
}
/**
@ -151,7 +153,8 @@ public class SearchQueryBuilder {
String theBindVariableSubstitutionBase,
Dialect theDialect,
boolean theCountQuery,
ArrayList<Object> theBindVariableValues) {
ArrayList<Object> theBindVariableValues,
boolean theSelectPartitionId) {
myFhirContext = theFhirContext;
myStorageSettings = theStorageSettings;
myPartitionSettings = thePartitionSettings;
@ -173,6 +176,7 @@ public class SearchQueryBuilder {
myBindVariableSubstitutionBase = theBindVariableSubstitutionBase;
myBindVariableValues = theBindVariableValues;
mySelectPartitionId = theSelectPartitionId;
}
public FhirContext getFhirContext() {
@ -359,10 +363,11 @@ public class SearchQueryBuilder {
mySelect.addCustomJoin(theJoinType, theFromTable, theToTable, theCondition);
}
public ComboCondition createOnCondition(DbColumn theSourceColumn, DbColumn theTargetColumn) {
public ComboCondition createOnCondition(DbColumn[] theSourceColumn, DbColumn[] theTargetColumn) {
ComboCondition onCondition = ComboCondition.and();
onCondition.addCondition(BinaryCondition.equalTo(theSourceColumn, theTargetColumn));
for (int i = 0; i < theSourceColumn.length; i += 1) {
onCondition.addCondition(BinaryCondition.equalTo(theSourceColumn[0], theTargetColumn[0]));
}
return onCondition;
}
@ -434,8 +439,14 @@ public class SearchQueryBuilder {
mySelect.addCustomColumns(
FunctionCall.count().setIsDistinct(true).addColumnParams(root.getResourceIdColumn()));
} else {
mySelectedResourceIdColumn = root.getResourceIdColumn();
mySelect.addColumns(mySelectedResourceIdColumn);
if (mySelectPartitionId) {
mySelectedResourceIdColumn = root.getResourceIdColumn();
mySelectedPartitionIdColumn = root.getPartitionIdColumn();
mySelect.addColumns(mySelectedPartitionIdColumn, mySelectedResourceIdColumn);
} else {
mySelectedResourceIdColumn = root.getResourceIdColumn();
mySelect.addColumns(mySelectedResourceIdColumn);
}
}
mySelect.addFromTable(root.getTable());
myFirstPredicateBuilder = root;
@ -460,6 +471,9 @@ public class SearchQueryBuilder {
return toJoinColumns(partitionIdColumn, resourceIdColumn);
}
/**
* Remove or keep partition_id columns depending on settings.
*/
@Nonnull
public DbColumn[] toJoinColumns(DbColumn partitionIdColumn, DbColumn resourceIdColumn) {
if (isIncludePartitionIdInJoins()) {
@ -470,7 +484,7 @@ public class SearchQueryBuilder {
}
public boolean isIncludePartitionIdInJoins() {
return true;
return mySelectPartitionId && myPartitionSettings.isPartitionIdsInPrimaryKeys();
}
public void addJoin(DbTable theFromTable, DbTable theToTable, DbColumn[] theFromColumn, DbColumn[] theToColumn) {
@ -484,29 +498,8 @@ public class SearchQueryBuilder {
DbColumn[] theToColumn,
SelectQuery.JoinType theJoinType) {
assert theFromColumn.length == theToColumn.length;
assert theFromColumn.length > 0;
// create custom join condition, allowing nullable columns.
var onCondition = ComboCondition.and();
for (int i = 0; i < theFromColumn.length; ++i) {
boolean isNullable =
theFromColumn[i].getColumnNameSQL().toLowerCase(Locale.ROOT).contains("partition_id");
onCondition.addCondition(buildJoinColumnCondition(isNullable, theFromColumn[i], theToColumn[i]));
}
mySelect.addCustomJoin(theJoinType, theFromTable, theToTable, onCondition);
}
private static @Nonnull Condition buildJoinColumnCondition(
boolean theColumnNullability, DbColumn theFromColumn, DbColumn theToColumn) {
var normalEqualCondition = BinaryCondition.equalTo(theFromColumn, theToColumn);
if (!theColumnNullability) {
return normalEqualCondition;
} else {
// the column can be null
// we must combine raw = with IS NULL checks.
var orBothNullCondition =
ComboCondition.and(UnaryCondition.isNull(theFromColumn), UnaryCondition.isNull(theToColumn));
return ComboCondition.or(normalEqualCondition, orBothNullCondition);
}
Join join = new DbJoin(mySpec, theFromTable, theToTable, theFromColumn, theToColumn);
mySelect.addJoins(theJoinType, join);
}
/**
@ -842,7 +835,7 @@ public class SearchQueryBuilder {
}
}
public SearchQueryBuilder newChildSqlBuilder() {
public SearchQueryBuilder newChildSqlBuilder(boolean theSelectPartitionId) {
return new SearchQueryBuilder(
myFhirContext,
myStorageSettings,
@ -853,7 +846,8 @@ public class SearchQueryBuilder {
myBindVariableSubstitutionBase,
myDialect,
false,
myBindVariableValues);
myBindVariableValues,
theSelectPartitionId);
}
public SelectQuery getSelect() {

View File

@ -107,6 +107,7 @@ public class SearchQueryExecutor implements ISearchQueryExecutor {
* is managed by Spring has been started before this method is called.
*/
HapiTransactionService.requireTransaction();
ourLog.trace("About to execute SQL: {}. Parameters: {}", sql, Arrays.toString(args));
Query nativeQuery = myEntityManager.createNativeQuery(sql);
org.hibernate.query.Query<?> hibernateQuery = (org.hibernate.query.Query<?>) nativeQuery;
@ -114,8 +115,6 @@ public class SearchQueryExecutor implements ISearchQueryExecutor {
hibernateQuery.setParameter(i, args[i - 1]);
}
ourLog.trace("About to execute SQL: {}. Parameters: {}", sql, Arrays.toString(args));
/*
* These settings help to ensure that we use a search cursor
* as opposed to loading all search results into memory
@ -146,13 +145,20 @@ public class SearchQueryExecutor implements ISearchQueryExecutor {
myNext = NO_MORE;
} else {
Object nextRow = Objects.requireNonNull(myResultSet.next());
Number next;
// We should typically get two columns back, the first is the partition ID and the second
// is the resource ID. But if we're doing a count query, we'll get a single column in an array
// or maybe even just a single non array value depending on how the platform handles it.
if (nextRow instanceof Number) {
next = (Number) nextRow;
myNext = ((Number) nextRow).longValue();
} else {
next = (Number) ((Object[]) nextRow)[0];
Object[] nextRowAsArray = (Object[]) nextRow;
if (nextRowAsArray.length == 1) {
myNext = (Long) nextRowAsArray[0];
} else {
Integer nextPartitionId = (Integer) nextRowAsArray[0];
myNext = (Long) nextRowAsArray[1];
}
}
myNext = next.longValue();
}
} catch (Exception e) {

View File

@ -33,8 +33,27 @@ public class PartitionSettings {
private Integer myDefaultPartitionId;
private boolean myAlwaysOpenNewTransactionForDifferentPartition;
private boolean myConditionalCreateDuplicateIdentifiersEnabled = false;
private boolean myPartitionIdsInPrimaryKeys = false;
public PartitionSettings() {}
/**
* Is the table partition column (usually PARTITION_ID)
* participating in primary and foreign keys.
* Affects sql joins, sql in() expressions, etc.
*/
public boolean isPartitionIdsInPrimaryKeys() {
return myPartitionIdsInPrimaryKeys;
}
/**
* Inform the query engine if the primary and foreign keys
* of the partitioned tables include the partition column.
*/
public void setPartitionIdsInPrimaryKeys(boolean thePartitionIdsInPrimaryKeys) {
myPartitionIdsInPrimaryKeys = thePartitionIdsInPrimaryKeys;
}
/**
* Should we always open a new database transaction if the partition context changes
*

View File

@ -4557,7 +4557,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
assertThat(patients).as(patients.toString()).containsExactly(obsId1);
String searchQuery = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true);
ourLog.info("Search query:\n{}", searchQuery);
assertThat(countMatches(searchQuery.toLowerCase(), "partition")).as(searchQuery).isEqualTo(0 /* criteria */ + 8 /* joins */);
assertThat(countMatches(searchQuery.toLowerCase(), "partition")).as(searchQuery).isEqualTo(0);
assertThat(countMatches(searchQuery.toLowerCase(), "join")).as(searchQuery).isEqualTo(2);
assertThat(countMatches(searchQuery.toLowerCase(), "hash_identity")).as(searchQuery).isEqualTo(2);
// - query is changed 'or' is removed

View File

@ -1,10 +1,10 @@
package ca.uhn.fhir.jpa.dao.r4;
import static org.junit.jupiter.api.Assertions.assertEquals;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam;
@ -17,9 +17,11 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
@ -52,6 +54,18 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
}
@Test
public void testSortJoinIncludesPartitionId() {
myCaptureQueriesListener.clear();
SearchParameterMap map = SearchParameterMap.newSynchronous(Patient.SP_ACTIVE, new TokenParam("true"));
map.setSort(new SortSpec(Patient.SP_NAME));
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_TOKEN t0 ON (t1.RES_ID = t0.RES_ID) LEFT OUTER JOIN HFJ_SPIDX_STRING t2 ON ((t1.RES_ID = t2.RES_ID) AND (t2.HASH_IDENTITY = ?)) WHERE (t0.HASH_VALUE = ?) ORDER BY t2.SP_VALUE_NORMALIZED ASC NULLS LAST", sql);
}
/**
* Two regular search params - Should use HFJ_RESOURCE as root
*/
@ -65,7 +79,7 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
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.PARTITION_ID = t0.PARTITION_ID) OR ((t1.PARTITION_ID IS NULL) AND (t0.PARTITION_ID IS NULL))) AND (t1.RES_ID = t0.RES_ID)) INNER JOIN HFJ_SPIDX_TOKEN t2 ON (((t1.PARTITION_ID = t2.PARTITION_ID) OR ((t1.PARTITION_ID IS NULL) AND (t2.PARTITION_ID IS NULL))) AND (t1.RES_ID = t2.RES_ID)) WHERE (((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?)) AND (t2.HASH_SYS_AND_VALUE = ?))", sql);
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
@ -86,7 +100,7 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
assertEquals(3, myCaptureQueriesListener.countSelectQueries());
// Query 1 - Find resources: Make sure we search for tag type+system+code always
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
assertEquals("SELECT t0.RES_ID FROM HFJ_RESOURCE t0 INNER JOIN HFJ_RES_TAG t1 ON (((t0.PARTITION_ID = t1.PARTITION_ID) OR ((t0.PARTITION_ID IS NULL) AND (t1.PARTITION_ID IS NULL))) AND (t0.RES_ID = t1.RES_ID)) INNER JOIN HFJ_TAG_DEF t2 ON (t1.TAG_ID = t2.TAG_ID) WHERE (((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) AND ((t2.TAG_TYPE = ?) AND (t2.TAG_SYSTEM = ?) AND (t2.TAG_CODE = ?)))", sql);
assertEquals("SELECT t0.RES_ID FROM HFJ_RESOURCE t0 INNER JOIN HFJ_RES_TAG t1 ON (t0.RES_ID = t1.RES_ID) INNER JOIN HFJ_TAG_DEF t2 ON (t1.TAG_ID = t2.TAG_ID) WHERE (((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) AND ((t2.TAG_TYPE = ?) AND (t2.TAG_SYSTEM = ?) AND (t2.TAG_CODE = ?)))", sql);
// Query 2 - Load resourece contents
sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(1).getSql(false, false);
assertThat(sql).contains("where rsv1_0.RES_ID in (?)");

View File

@ -1327,7 +1327,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
// Only the read columns should be used, no criteria use partition
assertThat(searchSql).as(searchSql).contains("PARTITION_ID = '1'");
assertThat(StringUtils.countMatches(searchSql, "PARTITION_ID")).as(searchSql).isEqualTo(2 /* criteria */ + 4 /* joins */); // If this switches to 1 that would be fine
assertThat(StringUtils.countMatches(searchSql, "PARTITION_ID")).as(searchSql).isEqualTo(2); // If this switches to 1 that would be fine
}
// Read in null Partition
@ -1443,7 +1443,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(1).getSql(true, false).toUpperCase();
ourLog.info("Search SQL:\n{}", searchSql);
assertThat(searchSql).as(searchSql).contains("PARTITION_ID = '1'");
assertThat(StringUtils.countMatches(searchSql, "PARTITION_ID")).as(searchSql).isEqualTo(2 /* criteria */ + 4 /* joins */); // If this switches to 1 that would be fine
assertThat(StringUtils.countMatches(searchSql, "PARTITION_ID")).as(searchSql).isEqualTo(2); // If this switches to 1 that would be fine
}
// Read in null Partition
@ -2383,7 +2383,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true);
ourLog.info("Search SQL:\n{}", searchSql);
assertThat(StringUtils.countMatches(searchSql, "PARTITION_ID")).as(searchSql).isEqualTo(0 /* criteria */ + 4 /* joins */);
assertThat(StringUtils.countMatches(searchSql, "PARTITION_ID")).as(searchSql).isEqualTo(0);
assertThat(StringUtils.countMatches(searchSql, "TAG_SYSTEM = 'http://system'")).as(searchSql).isEqualTo(1);
assertThat(StringUtils.countMatches(searchSql, ".HASH_SYS_AND_VALUE =")).as(searchSql).isEqualTo(1);
@ -2457,7 +2457,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true);
ourLog.info("Search SQL:\n{}", searchSql);
assertEquals(0 /* criteria */ + 4 /* joins */, StringUtils.countMatches(searchSql, "PARTITION_ID"));
assertEquals(0, StringUtils.countMatches(searchSql, "PARTITION_ID"));
assertEquals(1, StringUtils.countMatches(searchSql, "TAG_SYSTEM = 'http://system'"));
}
@ -2483,7 +2483,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
ourLog.info("Search SQL:\n{}", searchSql);
assertEquals(2, StringUtils.countMatches(searchSql, "JOIN"));
assertEquals(1 /* criteria */ + 4 /* joins */, StringUtils.countMatches(searchSql, "PARTITION_ID"));
assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID"));
assertEquals(1, StringUtils.countMatches(searchSql, "TAG_SYSTEM = 'http://system'"));
}