This is an automated email from the ASF dual-hosted git repository.

amashenkov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new b0b043262b9 IGNITE-27084 Sql. Improve printout of searchBounds in 
EXPLAIN (#7150)
b0b043262b9 is described below

commit b0b043262b95756ccadea01244625fd723798432
Author: Andrew V. Mashenkov <[email protected]>
AuthorDate: Thu Dec 11 14:39:01 2025 +0300

    IGNITE-27084 Sql. Improve printout of searchBounds in EXPLAIN (#7150)
---
 .../internal/sql/engine/ItOrToUnionRuleTest.java   |   2 +-
 .../internal/sql/engine/ItSecondaryIndexTest.java  | 120 +++++++++----------
 .../integrationTest/sql/group1/explain/scan.test   |   6 +-
 .../engine/rel/explain/RelTreeToTextWriter.java    | 132 ++++++++++++++++++++-
 .../src/test/resources/tpcds/plan/q9.plan          |   2 +-
 .../src/test/resources/tpch/plan/q1.plan           |   2 +-
 .../src/test/resources/tpch/plan/q10.plan          |   2 +-
 .../src/test/resources/tpch/plan/q12.plan          |   2 +-
 .../src/test/resources/tpch/plan/q14.plan          |   2 +-
 .../src/test/resources/tpch/plan/q15.plan          |   4 +-
 .../src/test/resources/tpch/plan/q17.plan          |   2 +-
 .../src/test/resources/tpch/plan/q2.plan           |   2 +-
 .../src/test/resources/tpch/plan/q20.plan          |   2 +-
 .../src/test/resources/tpch/plan/q21.plan          |   4 +-
 .../src/test/resources/tpch/plan/q22.plan          |   2 +-
 .../src/test/resources/tpch/plan/q3.plan           |   4 +-
 .../src/test/resources/tpch/plan/q4.plan           |   4 +-
 .../src/test/resources/tpch/plan/q6.plan           |   2 +-
 .../src/test/resources/tpch/plan/variant_q12.plan  |   2 +-
 .../src/test/resources/tpch/plan/variant_q14.plan  |   2 +-
 .../src/test/resources/tpch/plan/variant_q8.plan   |   2 +-
 .../internal/sql/engine/util/QueryChecker.java     |  15 +++
 22 files changed, 229 insertions(+), 88 deletions(-)

diff --git 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItOrToUnionRuleTest.java
 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItOrToUnionRuleTest.java
index d1c8e209e69..f59d95f8215 100644
--- 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItOrToUnionRuleTest.java
+++ 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItOrToUnionRuleTest.java
@@ -145,7 +145,7 @@ public class ItOrToUnionRuleTest extends 
BaseSqlIntegrationTest {
                 .disableRules("LogicalTableScanConverterRule")
                 .matches(not(containsUnion()))
                 .matches(containsIndexScan("PUBLIC", "PRODUCTS", 
"IDX_SUBCATEGORY"))
-                .matches(containsString("searchBounds: [MultiBounds"))
+                .matches(containsString("searchBounds: <_UTF-8'Camera Lens'>, 
<_UTF-8'Other'>"))
                 .returns(3, "Photo", 1, "Camera Lens", 12, "Lens 1")
                 .returns(4, "Photo", 1, "Other", 12, "Charger 1")
                 .returns(6, "Video", 2, "Camera Lens", 22, "Lens 3")
diff --git 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
index 64ba0de1fcb..98a66e47e02 100644
--- 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
+++ 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
@@ -207,7 +207,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     public void testKeyGreaterThanFilter() {
         assertQuery("SELECT * FROM Developer WHERE id>? and id<?")
                 .withParams(3, 12)
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
"DEVELOPER_PK"))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
"DEVELOPER_PK", "(<?0>..<?1>)"))
                 .returns(4, "Strauss", 2, "Munich", 66)
                 .returns(5, "Vagner", 4, "Leipzig", 70)
                 .returns(6, "Chaikovsky", 5, "Votkinsk", 53)
@@ -222,7 +222,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testKeyGreaterThanOrEqualsFilter() {
         assertQuery("SELECT * FROM Developer WHERE id>=3 and id<12")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
"DEVELOPER_PK"))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
"DEVELOPER_PK", "[<3>..<12>)"))
                 .returns(3, "Bach", 1, "Leipzig", 55)
                 .returns(4, "Strauss", 2, "Munich", 66)
                 .returns(5, "Vagner", 4, "Leipzig", 70)
@@ -238,7 +238,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testKeyLessThanFilter() {
         assertQuery("SELECT * FROM Developer WHERE id<3")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
"DEVELOPER_PK"))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
"DEVELOPER_PK", "[..<3>)"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .returns(2, "Beethoven", 2, "Vienna", 44)
                 .check();
@@ -247,7 +247,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testKeyLessThanOrEqualsFilter() {
         assertQuery("SELECT * FROM Developer WHERE id<=2")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
"DEVELOPER_PK"))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
"DEVELOPER_PK", "[..<2>]"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .returns(2, "Beethoven", 2, "Vienna", 44)
                 .check();
@@ -258,7 +258,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testIndexedFieldEqualsFilter() {
         assertQuery("SELECT * FROM Developer WHERE depId=2")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"<2>"))
                 .returns(2, "Beethoven", 2, "Vienna", 44)
                 .returns(4, "Strauss", 2, "Munich", 66)
                 .check();
@@ -267,7 +267,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testIndexedFieldGreaterThanFilter() {
         assertQuery("SELECT * FROM Developer WHERE depId>21")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"(<21>..<null:INTEGER>)"))
                 .returns(23, "Musorgskii", 22, "", -1)
                 .check();
     }
@@ -275,7 +275,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testIndexedFieldGreaterThanOrEqualsFilter() {
         assertQuery("SELECT * FROM Developer WHERE depId>=21")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"[<21>..<null:INTEGER>)"))
                 .returns(22, "Prokofiev", 21, "", -1)
                 .returns(23, "Musorgskii", 22, "", -1)
                 .check();
@@ -285,7 +285,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     public void testIndexedFieldLessThanFilter() {
         assertQuery("SELECT * FROM Developer WHERE depId<?")
                 .withParams(3)
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"[..<?0>)"))
                 .returns(2, "Beethoven", 2, "Vienna", 44)
                 .returns(3, "Bach", 1, "Leipzig", 55)
                 .returns(4, "Strauss", 2, "Munich", 66)
@@ -296,7 +296,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     public void testIndexedFieldLessThanOrEqualsFilter() {
         assertQuery("SELECT * FROM Developer WHERE depId<=?")
                 .withParams(2)
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"[..<?0>]"))
                 .returns(2, "Beethoven", 2, "Vienna", 44)
                 .returns(3, "Bach", 1, "Leipzig", 55)
                 .returns(4, "Strauss", 2, "Munich", 66)
@@ -404,7 +404,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testComplexIndexCondition1() {
         assertQuery("SELECT * FROM Developer WHERE name='Mozart' AND depId=3")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX, "<_UTF-8'Mozart', 3>"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -413,7 +413,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     public void testComplexIndexCondition2() {
         assertQuery("SELECT * FROM Developer WHERE depId=? AND name=?")
                 .withParams(3, "Mozart")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX, "<?1, ?0>"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -421,7 +421,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testComplexIndexCondition3() {
         assertQuery("SELECT * FROM Developer WHERE name='Mozart' AND depId=3 
AND city='Vienna'")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX, "<_UTF-8'Mozart', 3, _UTF-8'Vienna'>"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -451,14 +451,14 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testComplexIndexCondition4() {
         assertQuery("SELECT * FROM Developer WHERE name='Mozart' AND depId=3 
AND city='Leipzig'")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX, "<_UTF-8'Mozart', 3, _UTF-8'Leipzig'>"))
                 .check();
     }
 
     @Test
     public void testComplexIndexCondition5() {
         assertQuery("SELECT * FROM Developer WHERE name='Mozart' AND 
city='Vienna'")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_CITY_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_CITY_IDX, "<_UTF-8'Mozart', _UTF-8'Vienna'>"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -466,7 +466,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testComplexIndexCondition6() {
         assertQuery("SELECT * FROM Developer WHERE name>='Mozart' AND depId=3")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"<3>"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -474,7 +474,8 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testComplexIndexCondition7() {
         assertQuery("SELECT * FROM Developer WHERE name='Mozart' AND depId>=2")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX,
+                        "(<_UTF-8'Mozart', null:INTEGER>..<_UTF-8'Mozart', 
2>]"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -482,7 +483,8 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testComplexIndexCondition8() {
         assertQuery("SELECT * FROM Developer WHERE name='Mozart' AND depId>=2 
AND age>20")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX,
+                        "(<_UTF-8'Mozart', null:INTEGER>..<_UTF-8'Mozart', 
2>]"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -508,7 +510,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testComplexIndexCondition11() {
         assertQuery("SELECT * FROM Developer WHERE name>='Mozart' AND depId=3 
AND city>='Vienna'")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"<3>"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -516,7 +518,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testComplexIndexCondition12() {
         assertQuery("SELECT * FROM Developer WHERE name='Mozart' AND depId=3 
AND city='Vienna'")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX, "<_UTF-8'Mozart', 3, _UTF-8'Vienna'>"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -524,7 +526,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testComplexIndexCondition13() {
         assertQuery("SELECT * FROM Developer WHERE name='Mozart' AND depId>=3 
AND city='Vienna'")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_CITY_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_CITY_IDX, "<_UTF-8'Mozart', _UTF-8'Vienna'>"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -532,7 +534,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testComplexIndexCondition14() {
         assertQuery("SELECT * FROM Developer WHERE name>='Mozart' AND depId=3 
AND city>='Vienna'")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"<3>"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -548,7 +550,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testComplexIndexCondition16() {
         assertQuery("SELECT * FROM Developer WHERE age=33 AND (city='Vienna' 
AND depId=3)")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"<3>"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -573,7 +575,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     public void testOrCondition2() {
         assertQuery("SELECT * FROM Developer WHERE name='Mozart' AND (depId=1 
OR depId=3)")
                 .matches(not(containsUnion()))
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX, "<_UTF-8'Mozart', 1>, <_UTF-8'Mozart', 3>"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -582,7 +584,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     public void testOrCondition3() {
         assertQuery("SELECT * FROM Developer WHERE name='Mozart' AND (age > 22 
AND (depId=1 OR depId=3))")
                 .matches(not(containsUnion()))
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
NAME_DEPID_CITY_IDX, "<_UTF-8'Mozart', 1>, <_UTF-8'Mozart', 3>"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .check();
     }
@@ -590,7 +592,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testOrCondition4() {
         assertQuery("SELECT * FROM Developer WHERE depId=1 OR (name='Mozart' 
AND depId=3)")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"<1>"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .returns(3, "Bach", 1, "Leipzig", 55)
                 .check();
@@ -612,7 +614,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     @Test
     public void testOrderByKey() {
         assertQuery("SELECT * FROM Developer WHERE id<=4 ORDER BY id")
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
"DEVELOPER_PK"))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", 
"DEVELOPER_PK", "[..<4>]"))
                 .returns(1, "Mozart", 3, "Vienna", 33)
                 .returns(2, "Beethoven", 2, "Vienna", 44)
                 .returns(3, "Bach", 1, "Leipzig", 55)
@@ -797,9 +799,8 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
         assertQuery("SELECT * FROM T1 WHERE val > 4")
                 .disableRules("LogicalTableScanConverterRule")
                 .matches(anyOf(
-                        containsIndexScan("PUBLIC", "T1", "T1_IDX"),
-                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_LAST_IDX"),
-                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_FIRST_IDX")
+                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_LAST_IDX", "(<4>..<null:INTEGER>)"),
+                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_FIRST_IDX", "(<4>..]")
                 ))
                 .returns(5, 5)
                 .returns(6, 6)
@@ -813,35 +814,27 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     public void testIndexBoundsMerge() {
         assertQuery("SELECT id FROM Developer WHERE depId < 2 AND depId < ?")
                 .withParams(3)
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
-                .matches(containsString("searchBounds: [RangeBounds 
[shouldComputeLower=true, lowerBound=null, lowerInclude=true," 
-                        + " shouldComputeUpper=true, upperBound=$LEAST2(2, 
?0), upperInclude=false]]"))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"[..<$LEAST2(2, ?0)>)"))
                 .returns(3)
                 .check();
 
         assertQuery("SELECT id FROM Developer WHERE depId > 19 AND depId > ?")
                 .withParams(20)
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
-                .matches(containsString("searchBounds: [RangeBounds 
[shouldComputeLower=true, lowerBound=$GREATEST2(19, ?0)," 
-                        + " lowerInclude=false, shouldComputeUpper=true, 
upperBound=null:INTEGER, upperInclude=false]]"))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"(<$GREATEST2(19, ?0)>..<null:INTEGER>)"))
                 .returns(22)
                 .returns(23)
                 .check();
 
         assertQuery("SELECT id FROM Developer WHERE depId > 20 AND depId > ?")
                 .withParams(19)
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
-                .matches(containsString("searchBounds: [RangeBounds 
[shouldComputeLower=true, lowerBound=$GREATEST2(20, ?0)," 
-                        + " lowerInclude=false, shouldComputeUpper=true, 
upperBound=null:INTEGER, upperInclude=false]]"))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"(<$GREATEST2(20, ?0)>..<null:INTEGER>)"))
                 .returns(22)
                 .returns(23)
                 .check();
 
         assertQuery("SELECT id FROM Developer WHERE depId >= 20 AND depId > ?")
                 .withParams(19)
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
-                .matches(containsString("searchBounds: [RangeBounds 
[shouldComputeLower=true, lowerBound=$GREATEST2(20, ?0)," 
-                        + " lowerInclude=true, shouldComputeUpper=true, 
upperBound=null:INTEGER, upperInclude=false]]"))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"[<$GREATEST2(20, ?0)>..<null:INTEGER>)"))
                 .returns(21)
                 .returns(22)
                 .returns(23)
@@ -849,9 +842,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
 
         assertQuery("SELECT id FROM Developer WHERE depId BETWEEN ? AND ? AND 
depId > 19")
                 .withParams(19, 21)
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
-                .matches(containsString("searchBounds: [RangeBounds 
[shouldComputeLower=true, lowerBound=$GREATEST2(?0, 19)," 
-                        + " lowerInclude=true, shouldComputeUpper=true, 
upperBound=?1, upperInclude=true]]"))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"[<$GREATEST2(?0, 19)>..<?1>]"))
                 .returns(21)
                 .returns(22)
                 .check();
@@ -859,9 +850,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
         // Index with DESC ordering.
         assertQuery("SELECT id FROM Birthday WHERE name BETWEEN 'B' AND 'D' 
AND name > ?")
                 .withParams("Bach")
-                .matches(containsIndexScan("PUBLIC", "BIRTHDAY", 
NAME_DATE_IDX))
-                .matches(containsString("searchBounds: [RangeBounds 
[shouldComputeLower=true, lowerBound=$GREATEST2(_UTF-8'B', ?0)," 
-                        + " lowerInclude=true, shouldComputeUpper=true, 
upperBound=_UTF-8'D', upperInclude=true]]"))
+                .matches(containsIndexScan("PUBLIC", "BIRTHDAY", 
NAME_DATE_IDX, "[<$GREATEST2(_UTF-8'B', ?0)>..<_UTF-8'D'>]"))
                 .returns(2)
                 .returns(6)
                 .check();
@@ -876,8 +865,8 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
                 .disableRules("LogicalTableScanConverterRule")
                 .matches(anyOf(
                         containsIndexScan("PUBLIC", "T1", "T1_IDX"),
-                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_LAST_IDX"),
-                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_FIRST_IDX")
+                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_LAST_IDX", "[..<5>]"),
+                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_FIRST_IDX", "(<null:INTEGER>..<5>]")
                 ))
                 .returns(3, 3)
                 .returns(4, 4)
@@ -912,7 +901,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
     public void testComplexIndexExpression() {
         assertQuery("SELECT id FROM Developer WHERE depId BETWEEN ? - 1 AND ? 
+ 1")
                 .withParams(20, 20)
-                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX, 
"[<-(?0, 1)>..<+(?1, 1)>]"))
                 .returns(20)
                 .returns(21)
                 .returns(22)
@@ -920,7 +909,8 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
 
         assertQuery("SELECT id FROM Birthday WHERE name = 
SUBSTRING(?::VARCHAR, 1, 4)")
                 .withParams("BachBach")
-                .matches(containsIndexScan("PUBLIC", "BIRTHDAY", 
NAME_DATE_IDX))
+                .matches(containsIndexScan("PUBLIC", "BIRTHDAY", NAME_DATE_IDX,
+                        "<SUBSTRING(CAST(?0):VARCHAR CHARACTER SET \"UTF-8\", 
1, 4)>"))
                 .returns(3)
                 .check();
 
@@ -935,8 +925,8 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
         assertQuery("SELECT * FROM T1 WHERE val is null")
                 .matches(anyOf(
                         containsIndexScan("PUBLIC", "T1", "T1_IDX"),
-                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_LAST_IDX"),
-                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_FIRST_IDX")
+                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_LAST_IDX", "<null:INTEGER>"),
+                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_FIRST_IDX", "<null:INTEGER>")
                 ))
                 .matches(not(containsUnion()))
                 .returns(1, null)
@@ -951,8 +941,8 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
                 .disableRules("LogicalTableScanConverterRule")
                 .matches(anyOf(
                         containsIndexScan("PUBLIC", "T1", "T1_IDX"),
-                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_LAST_IDX"),
-                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_FIRST_IDX")
+                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_LAST_IDX", "<null:INTEGER>, [..<5>]"),
+                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_FIRST_IDX", "(<null:INTEGER>..<5>], <null:INTEGER>")
                 ))
                 .matches(not(containsUnion()))
                 .returns(1, null)
@@ -970,8 +960,8 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
                 .disableRules("LogicalTableScanConverterRule")
                 .matches(anyOf(
                         containsIndexScan("PUBLIC", "T1", "T1_IDX"),
-                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_LAST_IDX"),
-                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_FIRST_IDX")
+                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_LAST_IDX", "<null:INTEGER>, [<5>..<null:INTEGER>)"),
+                        containsIndexScan("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_FIRST_IDX", "<null:INTEGER>, [<5>..]")
                 ))
                 .matches(not(containsUnion()))
                 .returns(1, null)
@@ -1017,27 +1007,30 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
 
             assertQuery("SELECT /*+ FORCE_INDEX(t_idx) */ * FROM t WHERE i1 = 
?")
                     .withParams(null)
-                    .matches(containsIndexScan("PUBLIC", "T", "T_IDX"))
+                    .matches(containsIndexScan("PUBLIC", "T", "T_IDX", 
"<CAST(?0):INTEGER>"))
                     .check();
 
             assertQuery("SELECT /*+ FORCE_INDEX(t_idx) */ * FROM t WHERE i1 = 
1 AND i2 = ?")
                     .withParams(new Object[] { null })
-                    .matches(containsIndexScan("PUBLIC", "T", "T_IDX"))
+                    .matches(containsIndexScan("PUBLIC", "T", "T_IDX", "<1, 
CAST(?0):INTEGER>"))
                     .check();
 
             // Multi ranges.
             assertQuery("SELECT /*+ FORCE_INDEX(t_idx) */ * FROM t WHERE i1 IN 
(1, 2, 3) AND i2 = ?")
                     .withParams(new Object[] { null })
-                    .matches(containsIndexScan("PUBLIC", "T", "T_IDX"))
+                    .matches(containsIndexScan("PUBLIC", "T", "T_IDX",
+                            "<1, CAST(?0):INTEGER>, <2, CAST(?0):INTEGER>, <3, 
CAST(?0):INTEGER>"))
                     .check();
 
             assertQuery("SELECT /*+ FORCE_INDEX(t_idx) */ i1, i2 FROM t WHERE 
i1 IN (1, 2) AND i2 IS NULL")
-                    .matches(containsIndexScan("PUBLIC", "T", "T_IDX"))
+                    .matches(containsIndexScan("PUBLIC", "T", "T_IDX",
+                            "<1, null:INTEGER>, <2, null:INTEGER>"))
                     .returns(1, null)
                     .check();
 
             assertQuery("SELECT i1, i2 FROM t WHERE i2 IS NULL ORDER BY i1")
                     .matches(containsIndexScanIgnoreBounds("PUBLIC", "T", 
"T_IDX"))
+                    .matches(not(containsString("searchBounds:")))
                     .returns(1, null)
                     .returns(3, null)
                     .check();
@@ -1207,6 +1200,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
         assertQuery("SELECT val FROM t1 ORDER BY val ASC NULLS FIRST")
                 .matches(containsIndexScanIgnoreBounds("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_FIRST_IDX"))
                 .matches(not(matches("Sort")))
+                .matches(not(containsString("searchBounds:")))
                 .ordered()
                 .returns(null)
                 .returns(null)
@@ -1220,6 +1214,7 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
         assertQuery("SELECT val FROM t1 ORDER BY val ASC NULLS LAST")
                 .matches(containsIndexScanIgnoreBounds("PUBLIC", "T1", 
"T1_VAL_ASC_NULLS_LAST_IDX"))
                 .matches(not(matches("Sort")))
+                .matches(not(containsString("searchBounds:")))
                 .ordered()
                 .returns(3)
                 .returns(4)
@@ -1277,7 +1272,8 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
 
         assertQuery(format("SELECT /*+ FORCE_INDEX(tt_val_id_idx_hash) */ id, 
val1 " 
                 + " FROM tt_{} WHERE val1 IN (2, 3, 6) AND val2 IN (3, 17, 
-38)", id))
-                .matches(containsIndexScan("PUBLIC", "T", 
"TT_VAL_ID_IDX_HASH"))
+                .matches(containsIndexScan("PUBLIC", "T", "TT_VAL_ID_IDX_HASH",
+                        "<2, -38>, <2, 17>, <2, 3>, <3, -38>, <3, 17>, <3, 3>, 
<6, -38>, <6, 17>, <6, 3>"))
                 .returns(3, 3)
                 .returns(17, 3)
                 .check();
diff --git 
a/modules/sql-engine/src/integrationTest/sql/group1/explain/scan.test 
b/modules/sql-engine/src/integrationTest/sql/group1/explain/scan.test
index 48d9b6e596c..6df982ba767 100644
--- a/modules/sql-engine/src/integrationTest/sql/group1/explain/scan.test
+++ b/modules/sql-engine/src/integrationTest/sql/group1/explain/scan.test
@@ -317,7 +317,7 @@ Exchange
       index: TEST_TABLE_IDX
       type: SORTED
       predicate: >(C1, 1)
-      searchBounds: [RangeBounds [shouldComputeLower=true, lowerBound=1, 
lowerInclude=false, shouldComputeUpper=true, upperBound=null:INTEGER, 
upperInclude=false]]
+      searchBounds: (<1>..<null:INTEGER>)
       fieldNames: [C1]
       collation: [C1 ASC]
       est: (rows=1)
@@ -334,7 +334,7 @@ Exchange
       index: TEST_TABLE_IDX
       type: SORTED
       predicate: AND(SEARCH(C1, Sarg[1, 2, 3]), 
>(CAST(CURRENT_TIMESTAMP):TIMESTAMP(0) NOT NULL, 1970-01-01 00:00:00))
-      searchBounds: [MultiBounds [bounds=ArrayList [ExactBounds [bound=1], 
ExactBounds [bound=2], ExactBounds [bound=3]]]]
+      searchBounds: <1>, <2>, <3>
       fieldNames: [C1]
       collation: [C1 ASC]
       est: (rows=1)
@@ -354,7 +354,7 @@ Exchange
       index: HASH_IDX
       type: HASH
       predicate: =(C2, 10)
-      searchBounds: [ExactBounds [bound=10]]
+      searchBounds: <10>
       fieldNames: [C1]
       est: (rows=1)
 
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/explain/RelTreeToTextWriter.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/explain/RelTreeToTextWriter.java
index 7b8dd9808ca..547c6c77724 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/explain/RelTreeToTextWriter.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/explain/RelTreeToTextWriter.java
@@ -24,9 +24,11 @@ import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Deque;
 import java.util.EnumMap;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -46,6 +48,9 @@ import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.ignite.internal.sql.engine.prepare.bounds.ExactBounds;
+import org.apache.ignite.internal.sql.engine.prepare.bounds.MultiBounds;
+import org.apache.ignite.internal.sql.engine.prepare.bounds.RangeBounds;
 import org.apache.ignite.internal.sql.engine.prepare.bounds.SearchBounds;
 import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
 import org.apache.ignite.internal.sql.engine.schema.IgniteIndex;
@@ -53,11 +58,15 @@ import 
org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
 import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.apache.ignite.lang.util.IgniteNameUtils;
 import org.apache.ignite.table.QualifiedNameHelper;
+import org.jetbrains.annotations.Nullable;
 
 class RelTreeToTextWriter {
     static final int NEXT_OPERATOR_INDENT = 2;
     private static final int OPERATOR_ATTRIBUTES_INDENT = 2 * 
NEXT_OPERATOR_INDENT;
 
+    private static final String OPEN_TUPLE_SYMBOL = "<";
+    private static final String CLOSE_TUPLE_SYMBOL = ">";
+
     private static boolean needToAddFieldNames(IgniteRel rel) {
         List<RelNode> inputs = rel.getInputs();
 
@@ -284,7 +293,7 @@ class RelTreeToTextWriter {
 
         @Override
         public IgniteRelWriter addSearchBounds(List<SearchBounds> 
searchBounds) {
-            attributes.put(AttributeName.SEARCH_BOUNDS, 
searchBounds.toString());
+            attributes.put(AttributeName.SEARCH_BOUNDS, 
beautifySearchBounds(searchBounds));
 
             return this;
         }
@@ -332,6 +341,127 @@ class RelTreeToTextWriter {
         }
     }
 
+    private static String beautifySearchBounds(List<SearchBounds> 
searchBounds) {
+        List<SearchBounds> current = Arrays.asList(new 
SearchBounds[searchBounds.size()]);
+        List<String> result = new ArrayList<>();
+
+        processSearchBoundsRecursively(new ArrayList<>(searchBounds), 0, 
current, result);
+
+        return result.stream().sorted().collect(Collectors.joining(", "));
+    }
+
+    private static void processSearchBoundsRecursively(
+            List<SearchBounds> searchBounds,
+            int i,
+            List<SearchBounds> current,
+            List<String> result
+    ) {
+        if (i >= searchBounds.size() || searchBounds.get(i) == null) {
+            if (!current.isEmpty()) {
+                result.add(beautifyPlainSearchBounds(current));
+            }
+
+            return;
+        }
+
+        SearchBounds bound = searchBounds.get(i);
+
+        switch (bound.type()) {
+            case EXACT:
+            case RANGE: {
+                current.set(i, bound);
+                processSearchBoundsRecursively(searchBounds, i + 1, current, 
result);
+                current.set(i, null);
+                break;
+            }
+            case MULTI: {
+                for (SearchBounds bounds : ((MultiBounds) bound).bounds()) {
+                    current.set(i, bounds);
+                    if (bounds != null) {
+                        processSearchBoundsRecursively(searchBounds, i + 1, 
current, result);
+                    } else if (!current.isEmpty()) {
+                        result.add(beautifyPlainSearchBounds(current));
+                    }
+                }
+                current.set(i, null);
+
+                break;
+            }
+            default:
+                throw new IllegalStateException();
+        }
+    }
+
+    private static String beautifyPlainSearchBounds(List<SearchBounds> 
searchBound) {
+        assert !searchBound.isEmpty();
+
+        boolean exactBounds = true;
+        boolean includeLower = true;
+        boolean includeUpper = true;
+        List<String> lowerBound = new ArrayList<>(searchBound.size());
+        List<String> upperBound = new ArrayList<>(searchBound.size());
+
+        for (int i = 0; i < searchBound.size(); i++) {
+            SearchBounds current = searchBound.get(i);
+
+            if (current == null) {
+                break;
+            }
+
+            switch (current.type()) {
+                case EXACT:
+                    String lookupKey = ((ExactBounds) 
current).bound().toString();
+
+                    lowerBound.add(lookupKey);
+                    upperBound.add(lookupKey);
+
+                    break;
+                case RANGE:
+                    exactBounds = false;
+                    RangeBounds rangeBounds = (RangeBounds) current;
+
+                    RexNode lower = rangeBounds.lowerBound();
+                    RexNode upper = rangeBounds.upperBound();
+                    if (lower != null && lowerBound.size() == i) {
+                        lowerBound.add(beautifyConditionalBound(lower, 
rangeBounds.shouldComputeLower()));
+                    }
+                    if (upper != null && upperBound.size() == i) {
+                        upperBound.add(beautifyConditionalBound(upper, 
rangeBounds.shouldComputeUpper()));
+                    }
+
+                    includeLower = includeLower && rangeBounds.lowerInclude();
+                    includeUpper = includeUpper && rangeBounds.upperInclude();
+
+                    break;
+                case MULTI:
+                default:
+                    throw new IllegalStateException();
+            }
+        }
+
+        if (exactBounds) {
+            return beautifyTuple(lowerBound);
+        } else {
+            return (includeLower ? "[" : "(")
+                    + (lowerBound.isEmpty() ? "" : beautifyTuple(lowerBound))
+                    + ".."
+                    + (upperBound.isEmpty() ? "" : beautifyTuple(upperBound))
+                    + (includeUpper ? "]" : ")");
+        }
+    }
+
+    private static String beautifyTuple(List<String> bound) {
+        return 
bound.stream().takeWhile(Objects::nonNull).collect(Collectors.joining(", ", 
OPEN_TUPLE_SYMBOL, CLOSE_TUPLE_SYMBOL));
+    }
+
+    private static String beautifyConditionalBound(RexNode bound, @Nullable 
RexNode condition) {
+        if (condition != null && !condition.isAlwaysTrue()) {
+            return condition + " ? " + bound + " : inf";
+        } else {
+            return bound.toString();
+        }
+    }
+
     static String dumpTree(IgniteRel rootRel, int initialLevel) {
         RelInfoHolder root = collectRelInfo(rootRel);
 
diff --git a/modules/sql-engine/src/test/resources/tpcds/plan/q9.plan 
b/modules/sql-engine/src/test/resources/tpcds/plan/q9.plan
index 3f9ddc04a17..3761975b5a5 100644
--- a/modules/sql-engine/src/test/resources/tpcds/plan/q9.plan
+++ b/modules/sql-engine/src/test/resources/tpcds/plan/q9.plan
@@ -84,7 +84,7 @@ Project
                                       index: REASON_PK
                                       type: HASH
                                       predicate: =(R_REASON_SK, 1)
-                                      searchBounds: [ExactBounds [bound=1]]
+                                      searchBounds: <1>
                                       fieldNames: [R_REASON_SK]
                                       est: (rows=1)
                                 Project
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q1.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/q1.plan
index 081944b1708..f82e2fed9e6 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q1.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q1.plan
@@ -27,7 +27,7 @@ Sort
                 index: L_SD
                 type: SORTED
                 predicate: <=(L_SHIPDATE, 1998-09-02)
-                searchBounds: [RangeBounds [shouldComputeLower=true, 
lowerBound=null, lowerInclude=true, shouldComputeUpper=true, 
upperBound=1998-09-02, upperInclude=true]]
+                searchBounds: [..<1998-09-02>]
                 fieldNames: [L_RETURNFLAG, L_LINESTATUS, L_QUANTITY, 
L_EXTENDEDPRICE, $f4, $f5, L_DISCOUNT]
                 projection: [L_RETURNFLAG, L_LINESTATUS, L_QUANTITY, 
L_EXTENDEDPRICE, *(L_EXTENDEDPRICE, -(1, L_DISCOUNT)), *(*(L_EXTENDEDPRICE, 
-(1, L_DISCOUNT)), +(1, L_TAX)), L_DISCOUNT]
                 collation: []
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q10.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/q10.plan
index 559f8f7922f..a356aba7d38 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q10.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q10.plan
@@ -39,7 +39,7 @@ Sort
                   index: O_OD
                   type: SORTED
                   predicate: SEARCH(O_ORDERDATE, 
Sarg[[1993-10-01..1994-01-01)])
-                  searchBounds: [RangeBounds [shouldComputeLower=true, 
lowerBound=1993-10-01, lowerInclude=true, shouldComputeUpper=true, 
upperBound=1994-01-01, upperInclude=false]]
+                  searchBounds: [<1993-10-01>..<1994-01-01>)
                   fieldNames: [O_ORDERKEY, O_CUSTKEY, O_ORDERDATE]
                   collation: [O_ORDERDATE ASC]
                   est: (rows=375000)
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q12.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/q12.plan
index 88565dfcd8a..d6e10143d12 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q12.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q12.plan
@@ -34,7 +34,7 @@ Sort
                   index: L_RD
                   type: SORTED
                   predicate: AND(SEARCH(L_SHIPMODE, 
Sarg[_UTF-8'MAIL':VARCHAR(10) CHARACTER SET "UTF-8", _UTF-8'SHIP':VARCHAR(10) 
CHARACTER SET "UTF-8"]:VARCHAR(10) CHARACTER SET "UTF-8"), <(L_COMMITDATE, 
L_RECEIPTDATE), <(L_SHIPDATE, L_COMMITDATE), SEARCH(L_RECEIPTDATE, 
Sarg[[1994-01-01..1995-01-01)]))
-                  searchBounds: [RangeBounds [shouldComputeLower=true, 
lowerBound=1994-01-01, lowerInclude=true, shouldComputeUpper=true, 
upperBound=1995-01-01, upperInclude=false]]
+                  searchBounds: [<1994-01-01>..<1995-01-01>)
                   fieldNames: [L_ORDERKEY, L_SHIPDATE, L_COMMITDATE, 
L_RECEIPTDATE, L_SHIPMODE]
                   collation: [L_RECEIPTDATE ASC]
                   est: (rows=213218)
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q14.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/q14.plan
index 7b966d1efa6..5c2e74e1ab5 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q14.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q14.plan
@@ -33,7 +33,7 @@ Project
                   index: L_SD
                   type: SORTED
                   predicate: SEARCH(L_SHIPDATE, Sarg[[1995-09-01..1995-10-01)])
-                  searchBounds: [RangeBounds [shouldComputeLower=true, 
lowerBound=1995-09-01, lowerInclude=true, shouldComputeUpper=true, 
upperBound=1995-10-01, upperInclude=false]]
+                  searchBounds: [<1995-09-01>..<1995-10-01>)
                   fieldNames: [L_PARTKEY, L_EXTENDEDPRICE, L_DISCOUNT, 
L_SHIPDATE]
                   collation: [L_SHIPDATE ASC]
                   est: (rows=1500304)
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q15.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/q15.plan
index 4c20d166e18..24c118a010c 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q15.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q15.plan
@@ -31,7 +31,7 @@ Project
                   index: L_SD
                   type: SORTED
                   predicate: SEARCH(L_SHIPDATE, Sarg[[1996-01-01..1996-04-01)])
-                  searchBounds: [RangeBounds [shouldComputeLower=true, 
lowerBound=1996-01-01, lowerInclude=true, shouldComputeUpper=true, 
upperBound=1996-04-01, upperInclude=false]]
+                  searchBounds: [<1996-01-01>..<1996-04-01>)
                   fieldNames: [L_SUPPKEY, $f1]
                   projection: [L_SUPPKEY, *(L_EXTENDEDPRICE, -(1, L_DISCOUNT))]
                   collation: []
@@ -63,7 +63,7 @@ Project
                       index: L_SD
                       type: SORTED
                       predicate: SEARCH(L_SHIPDATE, 
Sarg[[1996-01-01..1996-04-01)])
-                      searchBounds: [RangeBounds [shouldComputeLower=true, 
lowerBound=1996-01-01, lowerInclude=true, shouldComputeUpper=true, 
upperBound=1996-04-01, upperInclude=false]]
+                      searchBounds: [<1996-01-01>..<1996-04-01>)
                       fieldNames: [L_SUPPKEY, $f1]
                       projection: [L_SUPPKEY, *(L_EXTENDEDPRICE, -(1, 
L_DISCOUNT))]
                       collation: []
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q17.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/q17.plan
index a420557c943..7ee58d1225a 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q17.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q17.plan
@@ -80,7 +80,7 @@ Project
                           index: L_PK_SK
                           type: SORTED
                           predicate: =(L_PARTKEY, $cor1.P_PARTKEY)
-                          searchBounds: [ExactBounds [bound=$cor1.P_PARTKEY]]
+                          searchBounds: <$cor1.P_PARTKEY>
                           fieldNames: [L_QUANTITY]
                           collation: []
                           est: (rows=1998405)
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q2.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/q2.plan
index 22a319d024c..91a2cf8bbc7 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q2.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q2.plan
@@ -104,7 +104,7 @@ Sort
                     index: PS_PK
                     type: SORTED
                     predicate: =($cor1.P_PARTKEY, PS_PARTKEY)
-                    searchBounds: [ExactBounds [bound=$cor1.P_PARTKEY]]
+                    searchBounds: <$cor1.P_PARTKEY>
                     fieldNames: [PS_PARTKEY, PS_SUPPKEY, PS_SUPPLYCOST]
                     collation: [PS_PARTKEY ASC]
                     est: (rows=266400)
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q20.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/q20.plan
index 01ea48efb0c..05ec0fbc822 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q20.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q20.plan
@@ -91,7 +91,7 @@ Project
                           index: L_SK_PK
                           type: SORTED
                           predicate: AND(=(L_PARTKEY, $cor2.PS_PARTKEY), 
=(L_SUPPKEY, $cor2.PS_SUPPKEY), SEARCH(L_SHIPDATE, 
Sarg[[1994-01-01..1995-01-01)]))
-                          searchBounds: [ExactBounds [bound=$cor2.PS_SUPPKEY], 
ExactBounds [bound=$cor2.PS_PARTKEY]]
+                          searchBounds: <$cor2.PS_SUPPKEY, $cor2.PS_PARTKEY>
                           fieldNames: [L_QUANTITY]
                           collation: []
                           est: (rows=166367)
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q21.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/q21.plan
index 375592959f6..2fd781cad74 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q21.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q21.plan
@@ -103,7 +103,7 @@ Sort
                         index: L_OK
                         type: SORTED
                         predicate: AND(=(L_ORDERKEY, $cor6.L_ORDERKEY), 
<>(L_SUPPKEY, $cor6.L_SUPPKEY))
-                        searchBounds: [ExactBounds [bound=$cor6.L_ORDERKEY]]
+                        searchBounds: <$cor6.L_ORDERKEY>
                         fieldNames: [i]
                         projection: [true]
                         collation: []
@@ -126,7 +126,7 @@ Sort
                     index: L_OK
                     type: SORTED
                     predicate: AND(=(L_ORDERKEY, $cor5.L_ORDERKEY), 
<>(L_SUPPKEY, $cor5.L_SUPPKEY), >(L_RECEIPTDATE, L_COMMITDATE))
-                    searchBounds: [ExactBounds [bound=$cor5.L_ORDERKEY]]
+                    searchBounds: <$cor5.L_ORDERKEY>
                     fieldNames: [i]
                     projection: [true]
                     collation: []
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q22.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/q22.plan
index dc6d74685cd..c3ecf99edae 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q22.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q22.plan
@@ -80,7 +80,7 @@ Sort
                     index: O_CK
                     type: SORTED
                     predicate: =(O_CUSTKEY, $cor1.C_CUSTKEY)
-                    searchBounds: [ExactBounds [bound=$cor1.C_CUSTKEY]]
+                    searchBounds: <$cor1.C_CUSTKEY>
                     fieldNames: [i]
                     projection: [true]
                     collation: []
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q3.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/q3.plan
index e137694299b..697975b4e48 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q3.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q3.plan
@@ -27,7 +27,7 @@ Sort
                 index: L_SD
                 type: SORTED
                 predicate: >(L_SHIPDATE, 1995-03-15)
-                searchBounds: [RangeBounds [shouldComputeLower=true, 
lowerBound=1995-03-15, lowerInclude=false, shouldComputeUpper=true, 
upperBound=null:DATE, upperInclude=false]]
+                searchBounds: (<1995-03-15>..<null:DATE>)
                 fieldNames: [L_ORDERKEY, L_EXTENDEDPRICE, L_DISCOUNT, 
L_SHIPDATE]
                 collation: [L_SHIPDATE ASC]
                 est: (rows=3000608)
@@ -43,7 +43,7 @@ Sort
                   index: O_OD
                   type: SORTED
                   predicate: <(O_ORDERDATE, 1995-03-15)
-                  searchBounds: [RangeBounds [shouldComputeLower=true, 
lowerBound=null, lowerInclude=true, shouldComputeUpper=true, 
upperBound=1995-03-15, upperInclude=false]]
+                  searchBounds: [..<1995-03-15>)
                   fieldNames: [O_ORDERKEY, O_CUSTKEY, O_ORDERDATE, 
O_SHIPPRIORITY]
                   collation: [O_ORDERDATE ASC]
                   est: (rows=750000)
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q4.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/q4.plan
index 317fb82720f..4028daa5e3c 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q4.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q4.plan
@@ -24,7 +24,7 @@ ColocatedSortAggregate
               index: O_OD
               type: SORTED
               predicate: SEARCH(O_ORDERDATE, Sarg[[1993-07-01..1993-10-01)])
-              searchBounds: [RangeBounds [shouldComputeLower=true, 
lowerBound=1993-07-01, lowerInclude=true, shouldComputeUpper=true, 
upperBound=1993-10-01, upperInclude=false]]
+              searchBounds: [<1993-07-01>..<1993-10-01>)
               fieldNames: [O_ORDERKEY, O_ORDERPRIORITY]
               collation: []
               est: (rows=375000)
@@ -50,7 +50,7 @@ ColocatedSortAggregate
                   index: L_OK
                   type: SORTED
                   predicate: AND(=(L_ORDERKEY, $cor1.O_ORDERKEY), 
<(L_COMMITDATE, L_RECEIPTDATE))
-                  searchBounds: [ExactBounds [bound=$cor1.O_ORDERKEY]]
+                  searchBounds: <$cor1.O_ORDERKEY>
                   fieldNames: [i]
                   projection: [true]
                   collation: []
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q6.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/q6.plan
index 75f7477a41f..95fc33752af 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q6.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q6.plan
@@ -18,7 +18,7 @@ ReduceSortAggregate
           index: L_SD
           type: SORTED
           predicate: AND(SEARCH(L_SHIPDATE, Sarg[[1994-01-01..1995-01-01)]), 
SEARCH(L_DISCOUNT, Sarg[[0.05:DECIMAL(4, 2)..0.07:DECIMAL(4, 2)]]:DECIMAL(4, 
2)), <(L_QUANTITY, 24.00))
-          searchBounds: [RangeBounds [shouldComputeLower=true, 
lowerBound=1994-01-01, lowerInclude=true, shouldComputeUpper=true, 
upperBound=1995-01-01, upperInclude=false]]
+          searchBounds: [<1994-01-01>..<1995-01-01>)
           fieldNames: [$f0]
           projection: [*(L_EXTENDEDPRICE, L_DISCOUNT)]
           collation: []
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/variant_q12.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/variant_q12.plan
index 5567323023a..80cae2cead0 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/variant_q12.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/variant_q12.plan
@@ -34,7 +34,7 @@ Sort
                   index: L_RD
                   type: SORTED
                   predicate: AND(SEARCH(L_SHIPMODE, 
Sarg[_UTF-8'MAIL':VARCHAR(10) CHARACTER SET "UTF-8", _UTF-8'SHIP':VARCHAR(10) 
CHARACTER SET "UTF-8"]:VARCHAR(10) CHARACTER SET "UTF-8"), <(L_COMMITDATE, 
L_RECEIPTDATE), <(L_SHIPDATE, L_COMMITDATE), SEARCH(L_RECEIPTDATE, 
Sarg[[1994-01-01..1995-01-01)]))
-                  searchBounds: [RangeBounds [shouldComputeLower=true, 
lowerBound=1994-01-01, lowerInclude=true, shouldComputeUpper=true, 
upperBound=1995-01-01, upperInclude=false]]
+                  searchBounds: [<1994-01-01>..<1995-01-01>)
                   fieldNames: [L_ORDERKEY, L_SHIPDATE, L_COMMITDATE, 
L_RECEIPTDATE, L_SHIPMODE]
                   collation: [L_RECEIPTDATE ASC]
                   est: (rows=213218)
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/variant_q14.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/variant_q14.plan
index a32bcb88501..d7ab149b3a7 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/variant_q14.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/variant_q14.plan
@@ -33,7 +33,7 @@ Project
                   index: L_SD
                   type: SORTED
                   predicate: SEARCH(L_SHIPDATE, Sarg[[1995-09-01..1995-10-01)])
-                  searchBounds: [RangeBounds [shouldComputeLower=true, 
lowerBound=1995-09-01, lowerInclude=true, shouldComputeUpper=true, 
upperBound=1995-10-01, upperInclude=false]]
+                  searchBounds: [<1995-09-01>..<1995-10-01>)
                   fieldNames: [L_PARTKEY, L_EXTENDEDPRICE, L_DISCOUNT, 
L_SHIPDATE]
                   collation: [L_SHIPDATE ASC]
                   est: (rows=1500304)
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/variant_q8.plan 
b/modules/sql-engine/src/test/resources/tpch/plan/variant_q8.plan
index 81687549644..085c19c6542 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/variant_q8.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/variant_q8.plan
@@ -49,7 +49,7 @@ Sort
                       index: O_OD
                       type: SORTED
                       predicate: SEARCH(O_ORDERDATE, 
Sarg[[1995-01-01..1996-12-31]])
-                      searchBounds: [RangeBounds [shouldComputeLower=true, 
lowerBound=1995-01-01, lowerInclude=true, shouldComputeUpper=true, 
upperBound=1996-12-31, upperInclude=true]]
+                      searchBounds: [<1995-01-01>..<1996-12-31>]
                       fieldNames: [O_ORDERKEY, O_CUSTKEY, O_ORDERDATE]
                       collation: [O_ORDERDATE ASC]
                       est: (rows=375000)
diff --git 
a/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/QueryChecker.java
 
b/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/QueryChecker.java
index 73b0365092c..b762f862dea 100644
--- 
a/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/QueryChecker.java
+++ 
b/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/QueryChecker.java
@@ -125,6 +125,21 @@ public interface QueryChecker {
                 + ".*?searchBounds: ");
     }
 
+    /**
+     * Ignite index scan matcher.
+     *
+     * @param schema Schema name.
+     * @param tblName Table name.
+     * @param idxName Index name.
+     * @param searchBounds Search bounds.
+     * @return Matcher.
+     */
+    static Matcher<String> containsIndexScan(String schema, String tblName, 
String idxName, String searchBounds) {
+        return matchesOnce("IndexScan.*?table: " + QualifiedName.of(schema, 
tblName).toCanonicalForm()
+                + ".*?index: " + idxName
+                + ".*?searchBounds: " + Pattern.quote(searchBounds));
+    }
+
     /**
      * Ignite index scan matcher which ignores search bounds.
      *

Reply via email to