diff --git a/node/src/main/kotlin/net/corda/node/services/vault/HibernateQueryCriteriaParser.kt b/node/src/main/kotlin/net/corda/node/services/vault/HibernateQueryCriteriaParser.kt index c26c414019..c6ee750546 100644 --- a/node/src/main/kotlin/net/corda/node/services/vault/HibernateQueryCriteriaParser.kt +++ b/node/src/main/kotlin/net/corda/node/services/vault/HibernateQueryCriteriaParser.kt @@ -612,12 +612,15 @@ class HibernateQueryCriteriaParser(val contractStateType: Class("stateRef"), entityRoot.get>("compositeKey").get("stateRef")) - } else { - criteriaBuilder.equal(vaultStates.get("stateRef"), entityRoot.get("stateRef")) + if (entityRoot != vaultStates){ // to avoid self join + val joinPredicate = if(IndirectStatePersistable::class.java.isAssignableFrom(entityRoot.javaType)) { + criteriaBuilder.equal(vaultStates.get("stateRef"), entityRoot.get>("compositeKey").get("stateRef")) + } + else { + criteriaBuilder.equal(vaultStates.get("stateRef"), entityRoot.get("stateRef")) + } + predicateSet.add(joinPredicate) } - predicateSet.add(joinPredicate) // resolve general criteria expressions @Suppress("UNCHECKED_CAST") diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt index 2a5f12e994..f66e903bc4 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt @@ -501,6 +501,40 @@ abstract class VaultQueryTestsBase : VaultQueryParties { assertThat(queriedStates).containsExactlyElementsOf(allStates) } } + + @Test(timeout=300_000) + fun `query with sort criteria and pagination on large volume of states should complete in time`() { + val numberOfStates = 1000 + val pageSize = 1000 + + for (i in 1..50) { + database.transaction { + vaultFiller.fillWithSomeTestLinearStates(numberOfStates, linearNumber = 100L) + } + } + + val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) + + val sortAttribute = SortAttribute.Custom(DummyLinearStateSchemaV1.PersistentDummyLinearState::class.java, "stateRef") + + Sort.Direction.values().forEach { sortDirection -> + + val sorting = Sort(listOf(Sort.SortColumn(sortAttribute, sortDirection))) + + val start = System.currentTimeMillis() + val queriedStates = mutableListOf>() + var pageNumber = 0 + while (pageNumber * pageSize < numberOfStates) { + val paging = PageSpecification(pageNumber = pageNumber + 1, pageSize = pageSize) + val page = vaultService.queryBy(sorting = sorting, paging = paging, criteria = criteria) + queriedStates += page.states + pageNumber++ + } + + val elapsed = System.currentTimeMillis() - start + assertThat(elapsed).isLessThan(1000) + } + } @Test(timeout=300_000) fun `unconsumed states with count`() {