Skip to content

Commit 1319ca1

Browse files
Ensure streaming queries don't have limit clauses (#7382)
* Ensure streaming queries don't impose limit clauses on the sql when called in "synchronous" mode. * changelog
1 parent d033929 commit 1319ca1

File tree

3 files changed

+48
-16
lines changed

3 files changed

+48
-16
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
type: fix
3+
issue: 7382
4+
title: "When the fetchSizeDefaultMaximum setting was configured, streaming queries would have a limit clause that restricted the results.
5+
This has been corrected. To ensure streaming, use SearchParameterMap.setLoadSynchronous(true) when calling the dao searchForIdStream() method."

hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/SearchBuilder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3098,7 +3098,8 @@ private void fetchNext() {
30983098
}
30993099

31003100
private Integer calculateMaxResultsToFetch() {
3101-
if (myParams.getLoadSynchronousUpTo() != null) {
3101+
if (myParams.isLoadSynchronous()) {
3102+
// this might be null - we support this for streaming.
31023103
return myParams.getLoadSynchronousUpTo();
31033104
} else if (myParams.getOffset() != null && myParams.getCount() != null) {
31043105
return myParams.getEverythingMode() != null

hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QueryCountTest.java

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@
6969
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
7070
import ca.uhn.fhir.util.BundleBuilder;
7171
import jakarta.annotation.Nonnull;
72+
import org.assertj.core.api.Condition;
73+
import org.assertj.core.data.Index;
7274
import org.hl7.fhir.instance.model.api.IAnyResource;
7375
import org.hl7.fhir.instance.model.api.IBaseResource;
7476
import org.hl7.fhir.instance.model.api.IIdType;
@@ -198,22 +200,25 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
198200
@AfterEach
199201
public void afterResetDao() {
200202
mySubscriptionSettings.clearSupportedSubscriptionTypesForUnitTest();
201-
myStorageSettings.setAllowMultipleDelete(new JpaStorageSettings().isAllowMultipleDelete());
202-
myStorageSettings.setAutoCreatePlaceholderReferenceTargets(new JpaStorageSettings().isAutoCreatePlaceholderReferenceTargets());
203-
myStorageSettings.setAutoVersionReferenceAtPaths(new JpaStorageSettings().getAutoVersionReferenceAtPaths());
204-
myStorageSettings.setDeleteEnabled(new JpaStorageSettings().isDeleteEnabled());
205-
myStorageSettings.setHistoryCountMode(JpaStorageSettings.DEFAULT_HISTORY_COUNT_MODE);
206-
myStorageSettings.setIndexMissingFields(new JpaStorageSettings().getIndexMissingFields());
207-
myStorageSettings.setMassIngestionMode(new JpaStorageSettings().isMassIngestionMode());
208-
myStorageSettings.setMatchUrlCacheEnabled(new JpaStorageSettings().isMatchUrlCacheEnabled());
209-
myStorageSettings.setPopulateIdentifierInAutoCreatedPlaceholderReferenceTargets(new JpaStorageSettings().isPopulateIdentifierInAutoCreatedPlaceholderReferenceTargets());
210-
myStorageSettings.setResourceClientIdStrategy(new JpaStorageSettings().getResourceClientIdStrategy());
211-
myStorageSettings.setResourceMetaCountHardLimit(new JpaStorageSettings().getResourceMetaCountHardLimit());
212-
myStorageSettings.setRespectVersionsForSearchIncludes(new JpaStorageSettings().isRespectVersionsForSearchIncludes());
213-
myStorageSettings.setTagStorageMode(new JpaStorageSettings().getTagStorageMode());
203+
204+
JpaStorageSettings defaultStorageSettings = new JpaStorageSettings();
205+
myStorageSettings.setAllowMultipleDelete(defaultStorageSettings.isAllowMultipleDelete());
206+
myStorageSettings.setAutoCreatePlaceholderReferenceTargets(defaultStorageSettings.isAutoCreatePlaceholderReferenceTargets());
207+
myStorageSettings.setAutoVersionReferenceAtPaths(defaultStorageSettings.getAutoVersionReferenceAtPaths());
208+
myStorageSettings.setDeleteEnabled(defaultStorageSettings.isDeleteEnabled());
209+
myStorageSettings.setHistoryCountMode(defaultStorageSettings.getHistoryCountMode());
210+
myStorageSettings.setIndexMissingFields(defaultStorageSettings.getIndexMissingFields());
211+
myStorageSettings.setMassIngestionMode(defaultStorageSettings.isMassIngestionMode());
212+
myStorageSettings.setMatchUrlCacheEnabled(defaultStorageSettings.isMatchUrlCacheEnabled());
213+
myStorageSettings.setPopulateIdentifierInAutoCreatedPlaceholderReferenceTargets(defaultStorageSettings.isPopulateIdentifierInAutoCreatedPlaceholderReferenceTargets());
214+
myStorageSettings.setResourceClientIdStrategy(defaultStorageSettings.getResourceClientIdStrategy());
215+
myStorageSettings.setResourceMetaCountHardLimit(defaultStorageSettings.getResourceMetaCountHardLimit());
216+
myStorageSettings.setRespectVersionsForSearchIncludes(defaultStorageSettings.isRespectVersionsForSearchIncludes());
217+
myStorageSettings.setTagStorageMode(defaultStorageSettings.getTagStorageMode());
214218
myStorageSettings.setExpungeEnabled(false);
215-
myStorageSettings.setUniqueIndexesEnabled(new JpaStorageSettings().isUniqueIndexesEnabled());
216-
myStorageSettings.setUniqueIndexesCheckedBeforeSave(new JpaStorageSettings().isUniqueIndexesCheckedBeforeSave());
219+
myStorageSettings.setUniqueIndexesEnabled(defaultStorageSettings.isUniqueIndexesEnabled());
220+
myStorageSettings.setUniqueIndexesCheckedBeforeSave(defaultStorageSettings.isUniqueIndexesCheckedBeforeSave());
221+
myStorageSettings.setFetchSizeDefaultMaximum(defaultStorageSettings.getFetchSizeDefaultMaximum());
217222

218223
myFhirContext.getParserOptions().setStripVersionsFromReferences(true);
219224
TermReadSvcImpl.setForceDisableHibernateSearchForUnitTest(false);
@@ -4613,6 +4618,27 @@ public void testTransactionWithMultiplePreExistingInlineMatchUrls(boolean theMat
46134618
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
46144619
}
46154620

4621+
@Test
4622+
void testStreamingQueryDoesNotUseLimit() {
4623+
// given
4624+
myCaptureQueriesListener.clear();
4625+
myStorageSettings.setFetchSizeDefaultMaximum(100);
4626+
4627+
// when
4628+
Long count = this.runInTransaction(() ->
4629+
myPatientDao.searchForIdStream(new SearchParameterMap().setLoadSynchronous(true), mySrd, null)
4630+
.count());
4631+
4632+
// then
4633+
assertEquals(0, count);
4634+
myCaptureQueriesListener.logSelectQueries();
4635+
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueriesForCurrentThread();
4636+
Condition<SqlQuery> queryNotContainLimit = new Condition<>(query -> !query.getSql(false, false).matches(".*first .* rows.*"), "query does not have limit");
4637+
assertThat(selectQueries)
4638+
.hasSize(1)
4639+
.has(queryNotContainLimit, Index.atIndex(0));
4640+
}
4641+
46164642

46174643
private void assertQueryCount(int theExpectedSelectCount, int theExpectedUpdateCount, int theExpectedInsertCount, int theExpectedDeleteCount) {
46184644

0 commit comments

Comments
 (0)