From fcf6ef51c580bf99d5b3e2ac49ab624b46bb3fa1 Mon Sep 17 00:00:00 2001 From: Pavel_Bortnik Date: Sat, 7 Mar 2026 20:04:27 +0300 Subject: [PATCH 1/3] EPMRPP-112329 || Adopt gist queries --- .../commons/querygen/Condition.java | 7 ++-- .../ta/reportportal/dao/LogRepository.java | 5 ++- .../dao/LogRepositoryCustomImpl.java | 23 ++++++++--- .../reportportal/dao/TestItemRepository.java | 17 ++++---- .../dao/TestItemRepositoryCustomImpl.java | 41 ++++++++++++------- 5 files changed, 60 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/epam/ta/reportportal/commons/querygen/Condition.java b/src/main/java/com/epam/ta/reportportal/commons/querygen/Condition.java index 3bd11ed66..430025e85 100644 --- a/src/main/java/com/epam/ta/reportportal/commons/querygen/Condition.java +++ b/src/main/java/com/epam/ta/reportportal/commons/querygen/Condition.java @@ -16,7 +16,7 @@ package com.epam.ta.reportportal.commons.querygen; -import static com.epam.reportportal.rules.commons.validation .BusinessRule.expect; +import static com.epam.reportportal.rules.commons.validation.BusinessRule.expect; import static com.epam.reportportal.rules.commons.validation.BusinessRule.fail; import static com.epam.reportportal.rules.commons.validation.Suppliers.formattedSupplier; import static com.epam.reportportal.rules.exception.ErrorType.INCORRECT_FILTER_PARAMETERS; @@ -153,8 +153,9 @@ public Object castValue(CriteriaHolder criteriaHolder, String values, ErrorType @Override public org.jooq.Condition toCondition(FilterCondition filter, CriteriaHolder criteriaHolder) { validate(criteriaHolder, filter.getValue(), false, INCORRECT_FILTER_PARAMETERS); - return DSL.condition( - DSL.inline(filter.getValue()) + " @> " + criteriaHolder.getAggregateCriteria()); + Field aggregateField = DSL.field(criteriaHolder.getAggregateCriteria(), String.class); + return aggregateField.eq(filter.getValue()) + .or(aggregateField.like(filter.getValue() + ".%")); } @Override diff --git a/src/main/java/com/epam/ta/reportportal/dao/LogRepository.java b/src/main/java/com/epam/ta/reportportal/dao/LogRepository.java index 49fb637d3..c0ff6dd9c 100644 --- a/src/main/java/com/epam/ta/reportportal/dao/LogRepository.java +++ b/src/main/java/com/epam/ta/reportportal/dao/LogRepository.java @@ -46,13 +46,14 @@ WITH ParentPath AS ( ) ), TargetPath AS ( - SELECT cast(concat(pp.path, '.', :itemId) as ltree) AS path + SELECT concat(pp.path, '.', :itemId) AS path FROM ParentPath pp ), FilteredItems AS ( SELECT ti.item_id FROM test_item ti - WHERE ti.path <@ (SELECT path FROM TargetPath) + WHERE ti.path::text = (SELECT path FROM TargetPath) + OR ti.path::text LIKE (SELECT path FROM TargetPath) || '.%' ) SELECT log.id AS logId, diff --git a/src/main/java/com/epam/ta/reportportal/dao/LogRepositoryCustomImpl.java b/src/main/java/com/epam/ta/reportportal/dao/LogRepositoryCustomImpl.java index 039a8f11e..a0e45c49e 100644 --- a/src/main/java/com/epam/ta/reportportal/dao/LogRepositoryCustomImpl.java +++ b/src/main/java/com/epam/ta/reportportal/dao/LogRepositoryCustomImpl.java @@ -178,7 +178,10 @@ public Map> findAllIndexUnderTestItemByLaunchIdAndTestItemI .join(childItemTable) .on(LOG.ITEM_ID.eq(childItemTable.ITEM_ID)) .join(parentItemTable) - .on(DSL.sql(childItemTable.PATH + " <@ " + parentItemTable.PATH)) + .on(childItemTable.PATH.cast(String.class).eq(parentItemTable.PATH.cast(String.class)) + .or(childItemTable.PATH.cast(String.class) + .like(parentItemTable.PATH.cast(String.class).concat(".%"))) + ) .leftJoin(CLUSTERS) .on(LOG.CLUSTER_ID.eq(CLUSTERS.ID)) .where(childItemTable.LAUNCH_ID.eq(launchId)) @@ -263,7 +266,10 @@ public List findIdsUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(Lon .join(childItemTable) .on(LOG.ITEM_ID.eq(childItemTable.ITEM_ID)) .join(parentItemTable) - .on(DSL.sql(childItemTable.PATH + " <@ " + parentItemTable.PATH)) + .on(childItemTable.PATH.cast(String.class).eq(parentItemTable.PATH.cast(String.class)) + .or(childItemTable.PATH.cast(String.class) + .like(parentItemTable.PATH.cast(String.class).concat(".%"))) + ) .where(childItemTable.LAUNCH_ID.eq(launchId)) .and(parentItemTable.LAUNCH_ID.eq(launchId)) .and(parentItemTable.ITEM_ID.in(itemIds)) @@ -462,7 +468,9 @@ public List findMessagesByLaunchIdAndItemIdAndPathAndLevelGte(Long launc .and(TEST_ITEM.LAUNCH_ID.eq(launchId)) .and(TEST_ITEM.ITEM_ID.eq(itemId) .or(TEST_ITEM.HAS_STATS.eq(false) - .and(DSL.sql(TEST_ITEM.PATH + " <@ cast(? AS LTREE)", path))))) + .and(TEST_ITEM.PATH.cast(String.class).eq(path) + .or(TEST_ITEM.PATH.cast(String.class).like(path + ".%")) + )))) .fetch(LOG.LOG_MESSAGE); } @@ -477,7 +485,9 @@ public List findIdsByLaunchIdAndItemIdAndPathAndLevelGte(Long launchId, Lo .and(TEST_ITEM.LAUNCH_ID.eq(launchId)) .and(TEST_ITEM.ITEM_ID.eq(itemId) .or(TEST_ITEM.HAS_STATS.eq(false) - .and(DSL.sql(TEST_ITEM.PATH + " <@ cast(? AS LTREE)", path))))) + .and(TEST_ITEM.PATH.cast(String.class).eq(path) + .or(TEST_ITEM.PATH.cast(String.class).like(path + ".%")) + )))) .fetch(LOG.ID); } @@ -529,7 +539,10 @@ private SelectConditionStep buildLogsUnderItemsQuery(Long laun .join(childItemTable) .on(LOG.ITEM_ID.eq(childItemTable.ITEM_ID)) .join(parentItemTable) - .on(DSL.sql(childItemTable.PATH + " <@ " + parentItemTable.PATH)); + .on(childItemTable.PATH.cast(String.class).eq(parentItemTable.PATH.cast(String.class)) + .or(childItemTable.PATH.cast(String.class) + .like(parentItemTable.PATH.cast(String.class).concat(".%"))) + ); if (includeAttachments) { logsSelect = logsSelect.leftJoin(ATTACHMENT).on(LOG.ATTACHMENT_ID.eq(ATTACHMENT.ID)); diff --git a/src/main/java/com/epam/ta/reportportal/dao/TestItemRepository.java b/src/main/java/com/epam/ta/reportportal/dao/TestItemRepository.java index e471125b6..c5c606822 100644 --- a/src/main/java/com/epam/ta/reportportal/dao/TestItemRepository.java +++ b/src/main/java/com/epam/ta/reportportal/dao/TestItemRepository.java @@ -226,7 +226,7 @@ List findIdsByHasChildrenAndLaunchIdAndStatusOrderedByPathLevel( */ @Query(value = "SELECT test_item.item_id FROM test_item JOIN test_item_results result ON test_item.item_id = result.result_id " - + " WHERE CAST(:parentPath AS LTREE) @> test_item.path AND CAST(:parentPath AS LTREE) != test_item.path " + + " WHERE test_item.path::text LIKE :parentPath || '.%' " + " AND NOT test_item.has_children AND result.status = CAST(:#{#status.name()} AS STATUS_ENUM) ORDER BY test_item.item_id LIMIT :pageSize OFFSET :pageOffset", nativeQuery = true) List findIdsByNotHasChildrenAndParentPathAndStatus(@Param("parentPath") String parentPath, @Param("status") StatusEnum status, @@ -245,7 +245,7 @@ List findIdsByNotHasChildrenAndParentPathAndStatus(@Param("parentPath") St */ @Query(value = "SELECT test_item.item_id FROM test_item JOIN test_item_results result ON test_item.item_id = result.result_id " - + " WHERE CAST(:parentPath AS LTREE) @> test_item.path AND CAST(:parentPath AS LTREE) != test_item.path " + + " WHERE test_item.path::text LIKE :parentPath || '.%' " + " AND test_item.has_children AND result.status = CAST(:#{#status.name()} AS STATUS_ENUM)" + " ORDER BY nlevel(test_item.path) DESC, test_item.item_id LIMIT :pageSize OFFSET :pageOffset", nativeQuery = true) List findIdsByHasChildrenAndParentPathAndStatusOrderedByPathLevel( @@ -318,7 +318,7 @@ List findIdsByHasChildrenAndParentPathAndStatusOrderedByPathLevel( * @param itemPath Current item path in a tree * @return True if has */ - @Query(value = "SELECT EXISTS(SELECT 1 FROM test_item t WHERE t.path <@ CAST(:itemPath AS LTREE) AND t.item_id != :itemId LIMIT 1)", nativeQuery = true) + @Query(value = "SELECT EXISTS(SELECT 1 FROM test_item t WHERE t.path::text LIKE :itemPath || '.%' LIMIT 1)", nativeQuery = true) boolean hasChildren(@Param("itemId") Long itemId, @Param("itemPath") String itemPath); /** @@ -340,14 +340,14 @@ List findIdsByHasChildrenAndParentPathAndStatusOrderedByPathLevel( */ @Query(value = "SELECT EXISTS(SELECT 1 FROM test_item ti JOIN test_item_results tir ON ti.item_id = tir.result_id" - + " WHERE ti.path @> CAST(:itemPath AS LTREE) AND ti.has_stats = TRUE AND ti.item_id != :itemId AND tir.status = CAST(:#{#status.name()} AS STATUS_ENUM) LIMIT 1)", nativeQuery = true) + + " WHERE :itemPath LIKE ti.path::text || '.%' AND ti.has_stats = TRUE AND ti.item_id != :itemId AND tir.status = CAST(:#{#status.name()} AS STATUS_ENUM) LIMIT 1)", nativeQuery = true) boolean hasParentWithStatus(@Param("itemId") Long itemId, @Param("itemPath") String itemPath, @Param("status") StatusEnum status); /** * Check for existence of descendants with statuses NOT EQUAL to provided status * - * @param parentId {@link TestItem#getParent()} ID + * @param parentId {@link TestItem#getParentId()} ()} ID * @param statuses {@link StatusEnum#name()} Array * @return 'true' if items with statuses NOT EQUAL to provided status exist, otherwise 'false' */ @@ -374,7 +374,7 @@ boolean hasDescendantsNotInStatus(@Param("parentId") Long parentId, join test_item_results tir ON ti.item_id = tir.result_id WHERE ti.launch_id = :launchId - AND ti.path <@ Cast(:parentPath AS LTREE) + AND ti.path::text LIKE :parentPath || '.%' AND ti.item_id != :parentId AND Cast(tir.status AS VARCHAR) IN (:statuses)) """, nativeQuery = true) @@ -473,7 +473,7 @@ Optional findLatestIdByUniqueIdAndLaunchIdAndParentIdAndItemIdNotEqual( * @param path Path of {@link TestItem} * @return {@link List} of test item ids */ - @Query(value = "SELECT item_id FROM test_item WHERE path <@ CAST(:path AS LTREE)", nativeQuery = true) + @Query(value = "SELECT item_id FROM test_item WHERE path::text = :path OR path::text LIKE :path || '.%'", nativeQuery = true) List selectAllDescendantsIds(@Param("path") String path); void deleteAllByItemIdIn(Collection ids); @@ -539,8 +539,7 @@ Optional findLatestIdByTestCaseHashAndLaunchIdAndParentId( right join test_item ti on ti.item_id = a.item_id where ti.launch_id = :launchId and ti.has_stats = false - and ti.path <@ CAST(:path AS LTREE) - and ti.item_id != :itemId + and ti.path::text LIKE :path || '.%' order by ti.item_id, a.id """, nativeQuery = true diff --git a/src/main/java/com/epam/ta/reportportal/dao/TestItemRepositoryCustomImpl.java b/src/main/java/com/epam/ta/reportportal/dao/TestItemRepositoryCustomImpl.java index fc8339ee5..de151ed33 100644 --- a/src/main/java/com/epam/ta/reportportal/dao/TestItemRepositoryCustomImpl.java +++ b/src/main/java/com/epam/ta/reportportal/dao/TestItemRepositoryCustomImpl.java @@ -881,8 +881,8 @@ public Optional> selectPath(String uuid) { } /** - * {@link Log} entities are searched from the whole tree under {@link TestItem} that matched to the provided - * `launchId` and `autoAnalyzed` conditions + * {@link Log} entities are searched from the whole tree under {@link TestItem} that matched to + * the provided `launchId` and `autoAnalyzed` conditions */ @Override public List selectIdsByAnalyzedWithLevelGteExcludingIssueTypes(boolean autoAnalyzed, @@ -911,13 +911,18 @@ public List selectIdsByAnalyzedWithLevelGteExcludingIssueTypes(boolean aut .andNot(outerItemTable.HAS_CHILDREN) .and(issueCondition) .and(DSL.exists(DSL.selectOne() - .from(nestedItemTable) - .join(LOG) - .on(nestedItemTable.ITEM_ID.eq(LOG.ITEM_ID)) - .where(nestedItemTable.LAUNCH_ID.eq(launchId)) - .andNot(nestedItemTable.HAS_STATS) - .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel)) - .and(DSL.sql(outerItemTable.PATH + " @> " + nestedItemTable.PATH)))) + .from(nestedItemTable) + .join(LOG) + .on(nestedItemTable.ITEM_ID.eq(LOG.ITEM_ID)) + .where(nestedItemTable.LAUNCH_ID.eq(launchId)) + .andNot(nestedItemTable.HAS_STATS) + .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel)) + .and(nestedItemTable.PATH.cast(String.class) + .eq(outerItemTable.PATH.cast(String.class)) + .or(nestedItemTable.PATH.cast(String.class) + .like(outerItemTable.PATH.cast(String.class).concat(".%")))) + ) + ) .unionAll(DSL.selectDistinct(TEST_ITEM.ITEM_ID.as(ID)) .from(TEST_ITEM) .join(TEST_ITEM_RESULTS) @@ -1043,7 +1048,8 @@ public List selectIdsUnderByStringLogMessage(Long launchId, Collection " + child.PATH) + .on(child.PATH.cast(String.class) + .like(TEST_ITEM.PATH.cast(String.class).concat(".%"))) .and(TEST_ITEM.ITEM_ID.notEqual(child.ITEM_ID)) .join(LOG) .on(child.ITEM_ID.eq(LOG.ITEM_ID)) @@ -1063,7 +1069,8 @@ public List selectLogIdsUnderWithLogLevelCondition(Long launchId, Collecti return dsl.selectDistinct(LOG.ID) .from(TEST_ITEM) .join(child) - .on(TEST_ITEM.PATH + " @> " + child.PATH) + .on(child.PATH.cast(String.class) + .like(TEST_ITEM.PATH.cast(String.class).concat(".%"))) .and(TEST_ITEM.ITEM_ID.notEqual(child.ITEM_ID)) .join(LOG) .on(child.ITEM_ID.eq(LOG.ITEM_ID)) @@ -1081,7 +1088,8 @@ public List selectIdsUnderByRegexLogMessage(Long launchId, Collection " + child.PATH) + .on(child.PATH.cast(String.class) + .like(TEST_ITEM.PATH.cast(String.class).concat(".%"))) .and(TEST_ITEM.ITEM_ID.notEqual(child.ITEM_ID)) .join(LOG) .on(child.ITEM_ID.eq(LOG.ITEM_ID)) @@ -1151,8 +1159,13 @@ public List findAllNestedStepsByIds(Collection ids, Queryable .join(ATTACHMENT) .on(LOG.ATTACHMENT_ID.eq(ATTACHMENT.ID)) .where(nested.HAS_STATS.isFalse() - .and(DSL.sql(fieldName(NESTED, TEST_ITEM.PATH.getName()) + " <@ cast(? AS LTREE)", - TEST_ITEM.PATH)))) + .and(fieldName(NESTED, TEST_ITEM.PATH.getName()).cast(String.class) + .eq(TEST_ITEM.PATH.cast(String.class)) + .or(fieldName(NESTED, TEST_ITEM.PATH.getName()).cast(String.class) + .like(TEST_ITEM.PATH.cast(String.class).concat(".%"))) + ) + ) + ) .as(ATTACHMENTS_COUNT) ) .from(TEST_ITEM) From df65019a402a61690cd27770a8291667d572e3c5 Mon Sep 17 00:00:00 2001 From: Pavel_Bortnik Date: Sat, 7 Mar 2026 20:39:44 +0300 Subject: [PATCH 2/3] EPMRPP-112329 || Adopt gist queries --- .../com/epam/ta/reportportal/commons/querygen/Condition.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/epam/ta/reportportal/commons/querygen/Condition.java b/src/main/java/com/epam/ta/reportportal/commons/querygen/Condition.java index 430025e85..ef35435e6 100644 --- a/src/main/java/com/epam/ta/reportportal/commons/querygen/Condition.java +++ b/src/main/java/com/epam/ta/reportportal/commons/querygen/Condition.java @@ -153,7 +153,7 @@ public Object castValue(CriteriaHolder criteriaHolder, String values, ErrorType @Override public org.jooq.Condition toCondition(FilterCondition filter, CriteriaHolder criteriaHolder) { validate(criteriaHolder, filter.getValue(), false, INCORRECT_FILTER_PARAMETERS); - Field aggregateField = DSL.field(criteriaHolder.getAggregateCriteria(), String.class); + Field aggregateField = DSL.field(criteriaHolder.getAggregateCriteria()).cast(String.class); return aggregateField.eq(filter.getValue()) .or(aggregateField.like(filter.getValue() + ".%")); } From b0552185c8521d1ad083d3500045a228e6bd9f71 Mon Sep 17 00:00:00 2001 From: Pavel_Bortnik Date: Tue, 17 Mar 2026 11:59:15 +0300 Subject: [PATCH 3/3] EPMRPP-112329 || Update nested logs of retry item query --- .../ta/reportportal/dao/LogRepository.java | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/epam/ta/reportportal/dao/LogRepository.java b/src/main/java/com/epam/ta/reportportal/dao/LogRepository.java index c0ff6dd9c..b150d598e 100644 --- a/src/main/java/com/epam/ta/reportportal/dao/LogRepository.java +++ b/src/main/java/com/epam/ta/reportportal/dao/LogRepository.java @@ -36,24 +36,14 @@ public interface LogRepository extends ReportPortalRepository, LogRep List findLogsByLogTime(Timestamp timestamp); @Query(value = """ - WITH ParentPath AS ( - SELECT path - FROM test_item ti2 - WHERE ti2.item_id = ( - SELECT parent_id - FROM test_item ti3 - WHERE ti3.item_id = :itemId - ) - ), - TargetPath AS ( - SELECT concat(pp.path, '.', :itemId) AS path - FROM ParentPath pp - ), - FilteredItems AS ( + WITH RECURSIVE item_tree AS ( + SELECT item_id + FROM test_item + WHERE item_id = :itemId + UNION ALL SELECT ti.item_id FROM test_item ti - WHERE ti.path::text = (SELECT path FROM TargetPath) - OR ti.path::text LIKE (SELECT path FROM TargetPath) || '.%' + INNER JOIN item_tree it ON ti.parent_id = it.item_id ) SELECT log.id AS logId, @@ -63,7 +53,7 @@ FilteredItems AS ( clusters.index_id AS clusterId FROM log LEFT JOIN clusters ON log.cluster_id = clusters.id - WHERE log.item_id IN (SELECT item_id FROM FilteredItems) + WHERE log.item_id IN (SELECT item_id FROM item_tree) AND log.log_level >= :logLevel; """, nativeQuery = true) List findNestedLogsOfRetryItem(@Param("itemId") Long itemId,