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 f18c63e788 IGNITE-18479 Sort out and merge Calcite tickets to Ignite 
3.0 (step 9) (#1629)
f18c63e788 is described below

commit f18c63e7880d4b4e1ca5819c57a38679048653df
Author: ygerzhedovich <[email protected]>
AuthorDate: Thu Feb 23 15:13:15 2023 +0300

    IGNITE-18479 Sort out and merge Calcite tickets to Ignite 3.0 (step 9) 
(#1629)
---
 .../ignite/internal/util/BoundedPriorityQueue.java |  70 +++++++++++
 .../ignite/jdbc/ItJdbcConnectionSelfTest.java      | 139 +--------------------
 .../internal/sql/engine/ItAggregatesTest.java      |  17 +++
 .../internal/sql/engine/ItDataTypesTest.java       | 129 +++++++++++++++++++
 .../sql/engine/ItDynamicParameterTest.java         |  17 +--
 .../internal/sql/engine/ItSecondaryIndexTest.java  |  25 ++++
 .../internal/sql/engine/ItSqlOperatorsTest.java    |   2 +
 .../blob/{test_blob.test_ignore => test_blob.test} |   1 -
 .../sql/types/blob/test_blob.test_ignore_old       | 106 ----------------
 ...unction.test_ignore => test_blob_function.test} |   1 -
 ...perator.test_ignore => test_blob_operator.test} |   6 +-
 .../types/blob/test_blob_operator.test_ignore_old  |  65 ----------
 ...ob_string.test_ignore => test_blob_string.test} |   1 -
 .../internal/sql/engine/exec/ExecutionContext.java |   8 ++
 .../sql/engine/exec/LogicalRelImplementor.java     |   6 +-
 .../sql/engine/exec/exp/RexToLixTranslator.java    |  13 +-
 .../sql/engine/exec/exp/agg/Accumulators.java      |  80 ++++++++++++
 .../internal/sql/engine/exec/rel/SortNode.java     |  70 ++++++++++-
 .../sql/engine/metadata/IgniteMdRowCount.java      |   7 ++
 .../sql/engine/metadata/cost/IgniteCost.java       |   6 +
 .../internal/sql/engine/rel/IgniteLimit.java       |  32 +----
 .../ignite/internal/sql/engine/rel/IgniteSort.java |  74 ++++++++---
 .../sql/engine/rule/SortConverterRule.java         |  32 +++--
 .../sql/engine/sql/fun/IgniteSqlOperatorTable.java |   3 +
 .../internal/sql/engine/util/IgniteMethod.java     |   4 +
 .../ignite/internal/sql/engine/util/RexUtils.java  |  44 ++++++-
 .../ignite/internal/sql/engine/util/TypeUtils.java |  27 +++-
 .../sql/engine/exec/rel/AbstractExecutionTest.java |   1 -
 .../sql/engine/exec/rel/LimitExecutionTest.java    | 110 +++++++++++++++-
 .../sql/engine/planner/AbstractPlannerTest.java    |   5 +
 .../sql/engine/planner/LimitOffsetPlannerTest.java |  62 ++++++---
 .../internal/sql/engine/planner/PlannerTest.java   |  62 +++++++++
 32 files changed, 811 insertions(+), 414 deletions(-)

diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/util/BoundedPriorityQueue.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/util/BoundedPriorityQueue.java
new file mode 100644
index 0000000000..24618d06f9
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/util/BoundedPriorityQueue.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.util;
+
+import java.util.Comparator;
+import java.util.PriorityQueue;
+
+/**
+ * Bounded variant of {@link PriorityQueue}.
+ *
+ * @param <E> Type of the queue element.
+ */
+public class BoundedPriorityQueue<E> extends PriorityQueue<E> {
+    private static final long serialVersionUID = 0L;
+
+    /** Queue max capacity. */
+    private final int maxCap;
+
+    /** Comparator. */
+    private final Comparator<? super E> cmp;
+
+    /**
+     * Creates a bounded priority queue with the specified maximum size. At 
most {@code maxCap} elements would be kept in the queue.
+     *
+     * @param maxCap Maximum size of the queue.
+     * @param cmp Comparator that orders the elements.
+     */
+    public BoundedPriorityQueue(int maxCap, Comparator<? super E> cmp) {
+        super(maxCap, cmp);
+
+        if (cmp == null) {
+            throw new NullPointerException("comparator should not be null");
+        }
+
+        this.maxCap = maxCap;
+        this.cmp = cmp;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean offer(E e) {
+        if (size() >= maxCap) {
+            E head = peek();
+
+            if (cmp.compare(e, head) <= 0) {
+                return false;
+            }
+
+            poll();
+        }
+
+        return super.offer(e);
+    }
+}
+
diff --git 
a/modules/jdbc/src/integrationTest/java/org/apache/ignite/jdbc/ItJdbcConnectionSelfTest.java
 
b/modules/jdbc/src/integrationTest/java/org/apache/ignite/jdbc/ItJdbcConnectionSelfTest.java
index adc421f57c..af0229984a 100644
--- 
a/modules/jdbc/src/integrationTest/java/org/apache/ignite/jdbc/ItJdbcConnectionSelfTest.java
+++ 
b/modules/jdbc/src/integrationTest/java/org/apache/ignite/jdbc/ItJdbcConnectionSelfTest.java
@@ -28,14 +28,12 @@ import static java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT;
 import static java.sql.ResultSet.TYPE_FORWARD_ONLY;
 import static java.sql.Statement.NO_GENERATED_KEYS;
 import static java.sql.Statement.RETURN_GENERATED_KEYS;
-import static 
org.apache.ignite.internal.jdbc.proto.SqlStateCode.TRANSACTION_STATE_EXCEPTION;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
 
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
@@ -513,7 +511,7 @@ public class ItJdbcConnectionSelfTest extends 
AbstractJdbcSelfTest {
     }
 
     @Test
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-15087";)
+    @Disabled("https://issues.apache.org/jira/browse/IGNITE-15248";)
     public void testGetSetAutoCommit() throws Exception {
         try (Connection conn = DriverManager.getConnection(URL)) {
             boolean ac0 = conn.getAutoCommit();
@@ -574,43 +572,6 @@ public class ItJdbcConnectionSelfTest extends 
AbstractJdbcSelfTest {
         }
     }
 
-    @Test
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-15087";)
-    public void testBeginFailsWhenMvccIsDisabled() throws Exception {
-        try (Connection conn = DriverManager.getConnection(URL)) {
-            conn.createStatement().execute("BEGIN");
-
-            fail("Exception is expected");
-        } catch (SQLException e) {
-            assertEquals(TRANSACTION_STATE_EXCEPTION, e.getSQLState());
-        }
-    }
-
-    @Test
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-15087";)
-    public void testCommitIgnoredWhenMvccIsDisabled() throws Exception {
-        try (Connection conn = DriverManager.getConnection(URL)) {
-            conn.setAutoCommit(false);
-            conn.createStatement().execute("COMMIT");
-
-            conn.commit();
-        }
-        // assert no exception
-    }
-
-    @Test
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-15087";)
-    public void testRollbackIgnoredWhenMvccIsDisabled() throws Exception {
-        try (Connection conn = DriverManager.getConnection(URL)) {
-            conn.setAutoCommit(false);
-
-            conn.createStatement().execute("ROLLBACK");
-
-            conn.rollback();
-        }
-        // assert no exception
-    }
-
     /**
      * Test get metadata.
      *
@@ -793,104 +754,6 @@ public class ItJdbcConnectionSelfTest extends 
AbstractJdbcSelfTest {
         }
     }
 
-    @Test
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-15087";)
-    public void testSetSavepoint() throws Exception {
-        try (Connection conn = DriverManager.getConnection(URL)) {
-            assertFalse(conn.getMetaData().supportsSavepoints());
-
-            // Disallowed in auto-commit mode
-            assertThrows(
-                    SQLException.class,
-                    () -> conn.setSavepoint(),
-                    "Savepoint cannot be set in auto-commit mode"
-            );
-
-            conn.close();
-
-            checkConnectionClosed(() -> conn.setSavepoint());
-        }
-    }
-
-    @Test
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-15087";)
-    public void testSetSavepointName() throws Exception {
-        try (Connection conn = DriverManager.getConnection(URL)) {
-            assertFalse(conn.getMetaData().supportsSavepoints());
-
-            // Invalid arg
-            assertThrows(
-                    SQLException.class,
-                    () -> conn.setSavepoint(null),
-                    "Savepoint name cannot be null"
-            );
-
-            final String name = "savepoint";
-
-            // Disallowed in auto-commit mode
-            assertThrows(
-                    SQLException.class,
-                    () -> conn.setSavepoint(name),
-                    "Savepoint cannot be set in auto-commit mode"
-            );
-
-            conn.close();
-
-            checkConnectionClosed(() -> conn.setSavepoint(name));
-        }
-    }
-
-    @Test
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-15087";)
-    public void testRollbackSavePoint() throws Exception {
-        try (Connection conn = DriverManager.getConnection(URL)) {
-            assertFalse(conn.getMetaData().supportsSavepoints());
-
-            // Invalid arg
-            assertThrows(
-                    SQLException.class,
-                    () -> conn.rollback(null),
-                    "Invalid savepoint"
-            );
-
-            final Savepoint savepoint = getFakeSavepoint();
-
-            // Disallowed in auto-commit mode
-            assertThrows(
-                    SQLException.class,
-                    () -> conn.rollback(savepoint),
-                    "Auto-commit mode"
-            );
-
-            conn.close();
-
-            checkConnectionClosed(() -> conn.rollback(savepoint));
-        }
-    }
-
-    @Test
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-15087";)
-    public void testReleaseSavepoint() throws Exception {
-        try (Connection conn = DriverManager.getConnection(URL)) {
-            assertFalse(conn.getMetaData().supportsSavepoints());
-
-            // Invalid arg
-            assertThrows(
-                    SQLException.class,
-                    () -> conn.releaseSavepoint(null),
-                    "Savepoint cannot be null"
-            );
-
-            final Savepoint savepoint = getFakeSavepoint();
-
-            checkNotSupported(() -> conn.releaseSavepoint(savepoint));
-
-            conn.close();
-
-            checkConnectionClosed(() -> conn.releaseSavepoint(savepoint));
-        }
-    }
-
     @Test
     public void testCreateClob() throws Exception {
         try (Connection conn = DriverManager.getConnection(URL)) {
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAggregatesTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAggregatesTest.java
index e28ca50ff2..5facfad006 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAggregatesTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAggregatesTest.java
@@ -330,6 +330,23 @@ public class ItAggregatesTest extends 
AbstractBasicIntegrationTest {
         }
     }
 
+    @Test
+    public void testEverySomeAggregate() throws Exception {
+        sql("CREATE TABLE t(c0 INT PRIMARY KEY, c1 INT, c2 INT)");
+        sql("INSERT INTO t VALUES (1, null, 0)");
+        sql("INSERT INTO t VALUES (2, 0, null)");
+        sql("INSERT INTO t VALUES (3, null, null)");
+        sql("INSERT INTO t VALUES (4, 0, 1)");
+        sql("INSERT INTO t VALUES (5, 1, 1)");
+        sql("INSERT INTO t VALUES (6, 1, 2)");
+        sql("INSERT INTO t VALUES (7, 2, 2)");
+
+        assertQuery("SELECT EVERY(c1 < c2) FROM t").returns(false).check();
+        assertQuery("SELECT SOME(c1 < c2) FROM t").returns(true).check();
+        assertQuery("SELECT EVERY(c1 <= c2) FROM t").returns(true).check();
+        assertQuery("SELECT SOME(c1 > c2) FROM t").returns(false).check();
+    }
+
     @Test
     public void distinctAggregateWithoutAggregateFunction() {
         var sql = "select distinct name from person";
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java
index 064e991806..3da5dca2a0 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java
@@ -19,9 +19,13 @@ package org.apache.ignite.internal.sql.engine;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 import org.apache.calcite.runtime.CalciteContextException;
@@ -210,6 +214,131 @@ public class ItDataTypesTest extends 
AbstractBasicIntegrationTest {
                 .returns("2021-11-07 01:30:00").check();
     }
 
+    /** Test Binary type. */
+    @Test
+    public void testBinarySql() {
+        sql("CREATE TABLE tbl(b BINARY(3) PRIMARY KEY, v VARBINARY)");
+        byte[] val = {1, 2, 3};
+
+        // From parameters to internal, from internal to store, from store to 
internal and from internal to user.
+        sql("INSERT INTO tbl VALUES (?, ?)", val, val);
+
+        List<List<Object>> res = sql("SELECT b, v FROM tbl");
+
+        assertEquals(1, res.size());
+        assertEquals(2, res.get(0).size());
+        assertTrue(Objects.deepEquals(val, res.get(0).get(0)));
+        assertTrue(Objects.deepEquals(val, res.get(0).get(1)));
+
+        sql("DELETE FROM tbl");
+
+        // From literal to internal, from internal to store, from store to 
internal and from internal to user.
+        sql("INSERT INTO tbl VALUES (x'1A2B3C', x'AABBCC')");
+
+        res = sql("SELECT b, v FROM tbl");
+
+        assertEquals(1, res.size());
+        assertEquals(2, res.get(0).size());
+        assertTrue(Objects.deepEquals(new byte[]{0x1A, 0x2B, 0x3C}, 
res.get(0).get(0)));
+        assertTrue(Objects.deepEquals(new byte[]{(byte) 0xAA, (byte) 0xBB, 
(byte) 0xCC}, res.get(0).get(1)));
+    }
+
+    /** Test Aggregation functions for Binary type. */
+    @Test
+    public void testBinaryAggregation() {
+        sql("CREATE TABLE tbl(p int PRIMARY KEY,b varbinary)");
+        sql("INSERT INTO tbl VALUES (1, NULL)");
+        sql("INSERT INTO tbl VALUES (2, x'010203')");
+        sql("INSERT INTO tbl VALUES (3, x'040506')");
+        List<List<Object>> res = sql("SELECT MIN(b), MAX(b) FROM tbl");
+
+        assertEquals(1, res.size());
+        assertEquals(2, res.get(0).size());
+        assertTrue(Objects.deepEquals(new byte[]{1, 2, 3}, res.get(0).get(0)));
+        assertTrue(Objects.deepEquals(new byte[]{4, 5, 6}, res.get(0).get(1)));
+
+        sql("INSERT INTO tbl VALUES (4, x'01'),(5, x'FF'), (6, 
x'99aabbccddeeff00')");
+        res = sql("SELECT MIN(b), MAX(b) FROM tbl");
+
+        assertTrue(Objects.deepEquals(new byte[]{1}, res.get(0).get(0)));
+        assertTrue(Objects.deepEquals(new byte[]{-1}, res.get(0).get(1)));
+
+        sql("INSERT INTO tbl VALUES (7, x'FFFF')");
+        res = sql("SELECT MAX(b) FROM tbl");
+
+        assertTrue(Objects.deepEquals(new byte[]{-1, -1}, res.get(0).get(0)));
+    }
+
+    /** Test concatenation for Binary type. */
+    @Test
+    public void testBinaryConcat() {
+        sql("CREATE TABLE tbl(p int PRIMARY KEY, b varbinary)");
+        sql("INSERT INTO tbl VALUES (1, x'010203')");
+        List<List<Object>> res = sql("SELECT b || x'040506' FROM tbl");
+
+        assertEquals(1, res.size());
+        assertEquals(1, res.get(0).size());
+        assertTrue(Objects.deepEquals(new byte[]{1, 2, 3, 4, 5, 6}, 
res.get(0).get(0)));
+    }
+
+    /** Test decimal scale for dynamic parameters. */
+    @Test
+    public void testDecimalScale() {
+        sql("CREATE TABLE t (id INT PRIMARY KEY, val1 DECIMAL(5, 3), val2 
DECIMAL(3), val3 DECIMAL)");
+
+        // Check literals scale.
+        sql("INSERT INTO t values (0, 0, 0, 0)");
+        sql("INSERT INTO t values (1.1, 1.1, 1.1, 1.1)");
+        sql("INSERT INTO t values (2.123, 2.123, 2.123, 2.123)");
+        sql("INSERT INTO t values (3.123456, 3.123456, 3.123456, 3.123456)");
+
+        // Check dynamic parameters scale.
+        List<Number> params = List.of(4, 5L, 6f, 7.25f, 8d, 9.03125d, new 
BigDecimal("10"),
+                new BigDecimal("11.1"), new BigDecimal("12.123456"));
+
+        for (Object val : params) {
+            sql("INSERT INTO t values (?, ?, ?, ?)", val, val, val, val);
+        }
+
+        assertQuery("SELECT * FROM t")
+                .returns(0, new BigDecimal("0.000"), new BigDecimal("0"), new 
BigDecimal("0"))
+                .returns(1, new BigDecimal("1.100"), new BigDecimal("1"), new 
BigDecimal("1"))
+                .returns(2, new BigDecimal("2.123"), new BigDecimal("2"), new 
BigDecimal("2"))
+                .returns(3, new BigDecimal("3.123"), new BigDecimal("3"), new 
BigDecimal("3"))
+                .returns(4, new BigDecimal("4.000"), new BigDecimal("4"), new 
BigDecimal("4"))
+                .returns(5, new BigDecimal("5.000"), new BigDecimal("5"), new 
BigDecimal("5"))
+                .returns(6, new BigDecimal("6.000"), new BigDecimal("6"), new 
BigDecimal("6"))
+                .returns(7, new BigDecimal("7.250"), new BigDecimal("7"), new 
BigDecimal("7"))
+                .returns(8, new BigDecimal("8.000"), new BigDecimal("8"), new 
BigDecimal("8"))
+                .returns(9, new BigDecimal("9.031"), new BigDecimal("9"), new 
BigDecimal("9"))
+                .returns(10, new BigDecimal("10.000"), new BigDecimal("10"), 
new BigDecimal("10"))
+                .returns(11, new BigDecimal("11.100"), new BigDecimal("11"), 
new BigDecimal("11"))
+                .returns(12, new BigDecimal("12.123"), new BigDecimal("12"), 
new BigDecimal("12"))
+                .check();
+    }
+
+    /** Tests conversion between numeric types. */
+    @Test
+    public void testNumericConversion() {
+        sql("CREATE TABLE t (v1 TINYINT PRIMARY KEY, v2 SMALLINT, v3 INT, v4 
BIGINT, v5 DECIMAL, v6 FLOAT, v7 DOUBLE)");
+
+        List<Number> params = List.of((byte) 1, (short) 2, 3, 4L, 
BigDecimal.valueOf(5), 6f, 7d);
+
+        for (Object val : params) {
+            sql("INSERT INTO t values (?, ?, ?, ?, ?, ?, ?)", val, val, val, 
val, val, val, val);
+        }
+
+        assertQuery("SELECT * FROM t")
+                .returns((byte) 1, (short) 1, 1, 1L, BigDecimal.valueOf(1), 
1f, 1d)
+                .returns((byte) 2, (short) 2, 2, 2L, BigDecimal.valueOf(2), 
2f, 2d)
+                .returns((byte) 3, (short) 3, 3, 3L, BigDecimal.valueOf(3), 
3f, 3d)
+                .returns((byte) 4, (short) 4, 4, 4L, BigDecimal.valueOf(4), 
4f, 4d)
+                .returns((byte) 5, (short) 5, 5, 5L, BigDecimal.valueOf(5), 
5f, 5d)
+                .returns((byte) 6, (short) 6, 6, 6L, BigDecimal.valueOf(6), 
6f, 6d)
+                .returns((byte) 7, (short) 7, 7, 7L, BigDecimal.valueOf(7), 
7f, 7d)
+                .check();
+    }
+
     private LocalDate sqlDate(String str) {
         return LocalDate.parse(str);
     }
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDynamicParameterTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDynamicParameterTest.java
index f951ead249..fdc18de602 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDynamicParameterTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDynamicParameterTest.java
@@ -60,7 +60,7 @@ public class ItDynamicParameterTest extends 
AbstractBasicIntegrationTest {
 
     @ParameterizedTest
     @EnumSource(value = ColumnType.class,
-            //    https://issues.apache.org/jira/browse/IGNITE-18258
+            //    https://issues.apache.org/jira/browse/IGNITE-18789
             //    https://issues.apache.org/jira/browse/IGNITE-18414
             //    https://issues.apache.org/jira/browse/IGNITE-18415
             //    https://issues.apache.org/jira/browse/IGNITE-18345
@@ -78,7 +78,10 @@ public class ItDynamicParameterTest extends 
AbstractBasicIntegrationTest {
     public void testDynamicParameters() {
         assertQuery("SELECT COALESCE(null, 
?)").withParams(13).returns(13).check();
         assertQuery("SELECT 
LOWER(?)").withParams("ASD").returns("asd").check();
+        assertQuery("SELECT POWER(?, ?)").withParams(2, 3).returns(8d).check();
+        assertQuery("SELECT SQRT(?)").withParams(4d).returns(2d).check();
         assertQuery("SELECT ?").withParams("asd").returns("asd").check();
+        assertQuery("SELECT ? % ?").withParams(11, 
10).returns(BigDecimal.valueOf(1)).check();
         assertQuery("SELECT ? + ?, LOWER(?) ").withParams(2, 2, 
"TeSt").returns(4, "test").check();
         assertQuery("SELECT LOWER(?), ? + ? ").withParams("TeSt", 2, 
2).returns("test", 4).check();
 
@@ -88,17 +91,7 @@ public class ItDynamicParameterTest extends 
AbstractBasicIntegrationTest {
 
         assertQuery("SELECT id FROM person WHERE name LIKE ? ORDER BY id LIMIT 
?").withParams("I%", 1).returns(0).check();
         assertQuery("SELECT id FROM person WHERE name LIKE ? ORDER BY id LIMIT 
? OFFSET ?").withParams("I%", 1, 1).returns(2).check();
-    }
-
-    // After fix the mute reason need to merge the test with above 
testDynamicParameters
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-18258";)
-    @Test
-    public void testDynamicParameters2() {
-        assertQuery("SELECT POWER(?, ?)").withParams(2, 3).returns(8).check();
-        assertQuery("SELECT SQRT(?)").withParams(4d).returns(2d).check();
-        assertQuery("SELECT ? % ?").withParams(11, 
10).returns(BigDecimal.valueOf(1)).check();
-
-        assertQuery("SELECT id from person where salary<? and 
id>?").withParams(15, 1).returns(2).check();
+        assertQuery("SELECT id from person WHERE salary<? and 
id<?").withParams(15, 3).returns(0).check();
     }
 
     // After fix the mute reason need to merge the test with above 
testDynamicParameters
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
index 8ed83d4b16..63ec7ccd81 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
@@ -855,6 +855,31 @@ public class ItSecondaryIndexTest extends 
AbstractBasicIntegrationTest {
                 .check();
     }
 
+    /**
+     * Test index search bounds on complex index expression.
+     */
+    @Test
+    public void testComplexIndexExpression() {
+        assertQuery("SELECT id FROM Developer WHERE depId BETWEEN ? - 1 AND ? 
+ 1")
+                .withParams(20, 20)
+                .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
+                .returns(20)
+                .returns(21)
+                .returns(22)
+                .check();
+
+        assertQuery("SELECT id FROM Birthday WHERE name = 
SUBSTRING(?::VARCHAR, 1, 4)")
+                .withParams("BachBach")
+                .matches(containsIndexScan("PUBLIC", "BIRTHDAY", 
NAME_DATE_IDX))
+                .returns(3)
+                .check();
+
+        assertQuery("SELECT id FROM Birthday WHERE name = SUBSTRING(name, 1, 
4)")
+                .matches(containsTableScan("PUBLIC", "BIRTHDAY"))
+                .returns(3)
+                .check();
+    }
+
     @Test
     @Disabled("https://issues.apache.org/jira/browse/IGNITE-18468";)
     public void testNullCondition1() {
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSqlOperatorsTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSqlOperatorsTest.java
index 73f2f51c4c..043961c3d6 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSqlOperatorsTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSqlOperatorsTest.java
@@ -98,6 +98,8 @@ public class ItSqlOperatorsTest extends 
AbstractBasicIntegrationTest {
         assertExpression("MAX(val)").returns(1).check();
         assertExpression("ANY_VALUE(val)").returns(1).check();
         assertExpression("COUNT(*) FILTER(WHERE val <> 
1)").returns(0L).check();
+        assertExpression("EVERY(val = 1)").returns(true).check();
+        assertExpression("SOME(val = 1)").returns(true).check();
     }
 
     @Test
diff --git 
a/modules/runner/src/integrationTest/sql/types/blob/test_blob.test_ignore 
b/modules/runner/src/integrationTest/sql/types/blob/test_blob.test
similarity index 96%
rename from 
modules/runner/src/integrationTest/sql/types/blob/test_blob.test_ignore
rename to modules/runner/src/integrationTest/sql/types/blob/test_blob.test
index 2e49350af9..ea38858017 100644
--- a/modules/runner/src/integrationTest/sql/types/blob/test_blob.test_ignore
+++ b/modules/runner/src/integrationTest/sql/types/blob/test_blob.test
@@ -1,7 +1,6 @@
 # name: test/sql/types/blob/test_blob.test
 # description: BLOB tests
 # group: [blob]
-# Ignored: https://issues.apache.org/jira/browse/IGNITE-18373
 
 statement ok
 PRAGMA enable_verification
diff --git 
a/modules/runner/src/integrationTest/sql/types/blob/test_blob.test_ignore_old 
b/modules/runner/src/integrationTest/sql/types/blob/test_blob.test_ignore_old
deleted file mode 100644
index f0fca68199..0000000000
--- 
a/modules/runner/src/integrationTest/sql/types/blob/test_blob.test_ignore_old
+++ /dev/null
@@ -1,106 +0,0 @@
-# name: test/sql/types/blob/test_blob.test
-# description: BLOB tests
-# group: [blob]
-# Ignore https://issues.apache.org/jira/browse/IGNITE-15123
-
-statement ok
-PRAGMA enable_verification
-
-statement ok
-CREATE TABLE blobs (b varbinary);
-
-# Insert valid hex strings
-statement ok
-INSERT INTO blobs VALUES(x'aaffaa'), (x'AAFFAAAAFFAA'), (x'AAFFAAAAFFAAAAFFAA')
-
-query T rowsort
-SELECT * FROM blobs
-----
-aaffaa
-aaffaaaaffaa
-aaffaaaaffaaaaffaa
-
-# Insert valid hex strings, lower case
-statement ok
-DELETE FROM blobs
-
-statement ok
-INSERT INTO blobs VALUES(x'aaffaa'), (x'aaffaaaaffaa'), (x'aaffaaaaffaaaaffaa')
-
-query T rowsort
-SELECT * FROM blobs
-----
-aaffaa
-aaffaaaaffaa
-aaffaaaaffaaaaffaa
-
-# Insert valid hex strings with number and letters
-statement ok
-DELETE FROM blobs
-
-statement ok
-INSERT INTO blobs VALUES(x'aa1199'), (x'aa1199aa1199'), (x'aa1199aa1199aa1199')
-
-query T rowsort
-SELECT * FROM blobs
-----
-aa1199
-aa1199aa1199
-aa1199aa1199aa1199
-
-# Insert invalid hex strings (invalid hex chars: G, H, I)
-statement error
-INSERT INTO blobs VALUES(x'GAFFAA')
-
-# Insert invalid hex strings (odd # of chars)
-statement error
-INSERT INTO blobs VALUES(x'A')
-
-statement error
-INSERT INTO blobs VALUES(x'AAA')
-
-statement ok
-DELETE FROM blobs
-
-# Implicit cast
-statement ok
-INSERT INTO blobs VALUES('blablabla')
-
-# BINARY with “non-printable” octets
-statement ok
-INSERT INTO blobs VALUES('abc �'::VARBINARY)
-
-query T
-SELECT b::varchar FROM blobs ORDER BY b
-----
-abc �
-blablabla
-
-# BINARY null and empty values
-query T
-SELECT ''::VARBINARY
-----
-(empty)
-
-query T
-SELECT NULL::VARBINARY
-----
-NULL
-
-statement ok
-CREATE TABLE blob_empty (b binary);
-
-statement ok
-INSERT INTO blob_empty VALUES(''), (''::VARBINARY)
-
-statement ok
-INSERT INTO blob_empty VALUES(NULL), (NULL::VARBINARY)
-
-query T rowsort
-SELECT * FROM blob_empty
-----
-NULL
-NULL
-(empty)
-(empty)
-
diff --git 
a/modules/runner/src/integrationTest/sql/types/blob/test_blob_function.test_ignore
 b/modules/runner/src/integrationTest/sql/types/blob/test_blob_function.test
similarity index 95%
rename from 
modules/runner/src/integrationTest/sql/types/blob/test_blob_function.test_ignore
rename to 
modules/runner/src/integrationTest/sql/types/blob/test_blob_function.test
index 4a31af7431..80381607d6 100644
--- 
a/modules/runner/src/integrationTest/sql/types/blob/test_blob_function.test_ignore
+++ b/modules/runner/src/integrationTest/sql/types/blob/test_blob_function.test
@@ -1,7 +1,6 @@
 # name: test/sql/types/blob/test_blob_function.test
 # description: BLOB with Functions
 # group: [blob]
-# Ignored: https://issues.apache.org/jira/browse/IGNITE-18373
 
 statement ok
 PRAGMA enable_verification
diff --git 
a/modules/runner/src/integrationTest/sql/types/blob/test_blob_operator.test_ignore
 b/modules/runner/src/integrationTest/sql/types/blob/test_blob_operator.test
similarity index 93%
rename from 
modules/runner/src/integrationTest/sql/types/blob/test_blob_operator.test_ignore
rename to 
modules/runner/src/integrationTest/sql/types/blob/test_blob_operator.test
index ec790415ac..3572d8e54a 100644
--- 
a/modules/runner/src/integrationTest/sql/types/blob/test_blob_operator.test_ignore
+++ b/modules/runner/src/integrationTest/sql/types/blob/test_blob_operator.test
@@ -1,8 +1,6 @@
 # name: test/sql/types/blob/test_blob_operator.test
 # description: Test BLOBs with various SQL operators
 # group: [blob]
-# Ignore https://issues.apache.org/jira/browse/IGNITE-15123
-# Ignored: https://issues.apache.org/jira/browse/IGNITE-18393
 
 statement ok
 PRAGMA enable_verification
@@ -33,10 +31,10 @@ SELECT COUNT(*), COUNT(b), MIN(b), MAX(b) FROM blobs
 query TI
 SELECT * FROM blobs ORDER BY b
 ----
-NULL   0
 00776861746973676f696e676f6e   1
 68656c6c6f     0
 fffefb 1
+NULL   0
 
 # GROUP BY
 statement ok
@@ -54,10 +52,10 @@ INSERT INTO blobs VALUES (x'FFFEFB', 19)
 query II
 SELECT b, SUM(g) FROM blobs GROUP BY b ORDER BY b
 ----
-NULL   0
 00776861746973676f696e676f6e   10
 68656c6c6f     3
 fffefb 20
+NULL   0
 
 # JOIN
 statement ok
diff --git 
a/modules/runner/src/integrationTest/sql/types/blob/test_blob_operator.test_ignore_old
 
b/modules/runner/src/integrationTest/sql/types/blob/test_blob_operator.test_ignore_old
deleted file mode 100644
index 1fc938f9dd..0000000000
--- 
a/modules/runner/src/integrationTest/sql/types/blob/test_blob_operator.test_ignore_old
+++ /dev/null
@@ -1,65 +0,0 @@
-# name: test/sql/types/blob/test_blob_operator.test
-# description: Test BLOBs with various SQL operators
-# group: [blob]
-# Ignore https://issues.apache.org/jira/browse/IGNITE-15123
-
-statement ok
-PRAGMA enable_verification
-
-statement ok
-CREATE TABLE blobs (b varbinary, g INTEGER);
-
-# strings: hello -> \x68656C6C6F, r -> \x72
-statement ok
-INSERT INTO blobs VALUES ('hello', 0), (x'00' || 'whatisgoingon'::varbinary, 
1), (NULL, 0), (x'FFFEFB', 1)
-
-# simple aggregates only
-query IITT
-SELECT COUNT(*), COUNT(b), MIN(b), MAX(b) FROM blobs
-----
-4      3       00776861746973676f696e676f6e    fffefb
-
-# ORDER BY
-query TI
-SELECT * FROM blobs ORDER BY b
-----
-NULL   0
-00776861746973676f696e676f6e   1
-68656c6c6f     0
-fffefb 1
-
-# GROUP BY
-statement ok
-INSERT INTO blobs VALUES ('hello', 3), (x'00' || 'whatisgoingon'::varbinary, 
9), (NULL, 0), (x'FFFEFB', 19)
-
-query II
-SELECT b, SUM(g) FROM blobs GROUP BY b ORDER BY b
-----
-NULL   0
-00776861746973676f696e676f6e   10
-68656c6c6f     3
-fffefb 20
-
-# JOIN
-statement ok
-CREATE TABLE blobs2 (b VARBINARY, g INTEGER);
-
-statement ok
-INSERT INTO blobs2 VALUES ('hello', 0), (x'00' || 'whatisgoingon'::varbinary, 
100), (NULL, 0), (x'FFFEFB', 200)
-
-# group by blobs.b, explicit JOIN
-query TR
-SELECT L.b, SUM(L.g) FROM blobs as L JOIN blobs2 AS R ON L.b=R.b GROUP BY L.b 
ORDER BY L.b
-----
-00776861746973676f696e676f6e   10.000000
-68656c6c6f     3.000000
-fffefb 20.000000
-
-# group by blobs2.b, implicit JOIN
-query TR
-SELECT R.b, SUM(R.g) FROM blobs as L, blobs2 AS R WHERE L.b=R.b GROUP BY R.b 
ORDER BY R.b
-----
-00776861746973676f696e676f6e   200.000000
-68656c6c6f     0.000000
-fffefb 400.000000
-
diff --git 
a/modules/runner/src/integrationTest/sql/types/blob/test_blob_string.test_ignore
 b/modules/runner/src/integrationTest/sql/types/blob/test_blob_string.test
similarity index 94%
rename from 
modules/runner/src/integrationTest/sql/types/blob/test_blob_string.test_ignore
rename to 
modules/runner/src/integrationTest/sql/types/blob/test_blob_string.test
index a9e741b89d..a4866ab117 100644
--- 
a/modules/runner/src/integrationTest/sql/types/blob/test_blob_string.test_ignore
+++ b/modules/runner/src/integrationTest/sql/types/blob/test_blob_string.test
@@ -1,7 +1,6 @@
 # name: test/sql/types/blob/test_blob_string.test
 # description: Insert BLOB values from normal strings
 # group: [blob]
-# Ignored: https://issues.apache.org/jira/browse/IGNITE-18373
 
 statement ok
 PRAGMA enable_verification
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionContext.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionContext.java
index cd56280d5b..72270990b2 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionContext.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionContext.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.sql.engine.exec;
 
 import static org.apache.ignite.lang.ErrorGroups.Common.UNEXPECTED_ERR;
 
+import java.lang.reflect.Type;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -250,6 +251,13 @@ public class ExecutionContext<RowT> extends 
AbstractQueryContext implements Data
         return params.get(name);
     }
 
+    /** Gets dynamic paremeters by name. */
+    public Object getParameter(String name, Type storageType) {
+        assert name.startsWith("?") : name;
+
+        return TypeUtils.toInternal(this, params.get(name), storageType);
+    }
+
     /**
      * Gets correlated value.
      *
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/LogicalRelImplementor.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/LogicalRelImplementor.java
index 63ae7944e7..f07d992f4f 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/LogicalRelImplementor.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/LogicalRelImplementor.java
@@ -453,7 +453,11 @@ public class LogicalRelImplementor<RowT> implements 
IgniteRelVisitor<Node<RowT>>
     public Node<RowT> visit(IgniteSort rel) {
         RelCollation collation = rel.getCollation();
 
-        SortNode<RowT> node = new SortNode<>(ctx, 
expressionFactory.comparator(collation));
+        Supplier<Integer> offset = (rel.offset == null) ? null : 
expressionFactory.execute(rel.offset);
+        Supplier<Integer> fetch = (rel.fetch == null) ? null : 
expressionFactory.execute(rel.fetch);
+
+        SortNode<RowT> node = new SortNode<>(ctx, 
expressionFactory.comparator(collation), offset,
+                fetch);
 
         Node<RowT> input = visit(rel.getInput());
 
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
index c78bf071a9..a55c8cc822 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
@@ -73,6 +73,7 @@ import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.ControlFlowException;
 import org.apache.calcite.util.Pair;
 import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
+import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
 import org.apache.ignite.internal.sql.engine.type.UuidFunctions;
 import org.apache.ignite.internal.sql.engine.type.UuidType;
 import org.apache.ignite.internal.sql.engine.util.IgniteMethod;
@@ -1261,10 +1262,14 @@ public class RexToLixTranslator implements 
RexVisitor<RexToLixTranslator.Result>
 
         final Type storageType = currentStorageType != null
                 ? currentStorageType : 
typeFactory.getJavaClass(dynamicParam.getType());
-        final Expression valueExpression = ConverterUtils.convert(
-                Expressions.call(root, BuiltInMethod.DATA_CONTEXT_GET.method,
-                        Expressions.constant("?" + dynamicParam.getIndex())),
-                storageType);
+        final Type paramType = ((IgniteTypeFactory) 
typeFactory).getResultClass(dynamicParam.getType());
+
+        final Expression ctxGet = Expressions.call(root, 
IgniteMethod.CONTEXT_GET_PARAMETER_VALUE.method(),
+                Expressions.constant("?" + dynamicParam.getIndex()), 
Expressions.constant(paramType));
+
+        final Expression valueExpression = 
SqlTypeUtil.isDecimal(dynamicParam.getType())
+                ? ConverterUtils.convertToDecimal(ctxGet, 
dynamicParam.getType())
+                : ConverterUtils.convert(ctxGet, storageType);
         final ParameterExpression valueVariable =
                 Expressions.parameter(valueExpression.getType(), 
list.newName("value_dynamic_param"));
         list.add(Expressions.declare(Modifier.FINAL, valueVariable, 
valueExpression));
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/agg/Accumulators.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/agg/Accumulators.java
index f6b875cfbc..2149ab3dbc 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/agg/Accumulators.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/agg/Accumulators.java
@@ -22,6 +22,7 @@ import static org.apache.calcite.sql.type.SqlTypeName.BIGINT;
 import static org.apache.calcite.sql.type.SqlTypeName.DECIMAL;
 import static org.apache.calcite.sql.type.SqlTypeName.DOUBLE;
 import static org.apache.calcite.sql.type.SqlTypeName.INTEGER;
+import static org.apache.calcite.sql.type.SqlTypeName.VARBINARY;
 import static org.apache.calcite.sql.type.SqlTypeName.VARCHAR;
 import static org.apache.ignite.internal.util.ArrayUtils.nullOrEmpty;
 
@@ -32,11 +33,13 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.function.Supplier;
+import org.apache.calcite.avatica.util.ByteString;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
 import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
+import org.apache.ignite.internal.util.ArrayUtils;
 
 /**
  * Accumulators.
@@ -80,8 +83,10 @@ public class Accumulators {
             case "$SUM0":
                 return sumEmptyIsZeroFactory(call);
             case "MIN":
+            case "EVERY":
                 return minMaxFactory(true, call);
             case "MAX":
+            case "SOME":
                 return minMaxFactory(false, call);
             case "SINGLE_VALUE":
                 return SingleVal.FACTORY;
@@ -164,6 +169,9 @@ public class Accumulators {
             case CHAR:
             case VARCHAR:
                 return min ? VarCharMinMax.MIN_FACTORY : 
VarCharMinMax.MAX_FACTORY;
+            case BINARY:
+            case VARBINARY:
+                return min ? VarBinaryMinMax.MIN_FACTORY : 
VarBinaryMinMax.MAX_FACTORY;
             default:
                 if (type instanceof IgniteCustomType) {
                     return MinMaxAccumulator.newAccumulator(min, typeFactory, 
type);
@@ -790,6 +798,78 @@ public class Accumulators {
         }
     }
 
+    private static class VarBinaryMinMax implements Accumulator {
+
+        public static final Supplier<Accumulator> MIN_FACTORY = () -> new 
VarBinaryMinMax(true);
+
+
+        public static final Supplier<Accumulator> MAX_FACTORY = () -> new 
VarBinaryMinMax(false);
+
+
+        private final boolean min;
+
+
+        private ByteString val;
+
+
+        private boolean empty = true;
+
+
+        private VarBinaryMinMax(boolean min) {
+            this.min = min;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void add(Object... args) {
+            ByteString in = (ByteString) args[0];
+
+            if (in == null) {
+                return;
+            }
+
+            val = empty ? in : min
+                    ? (val.compareTo(in) < 0 ? val : in)
+                    : (val.compareTo(in) < 0 ? in : val);
+
+            empty = false;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void apply(Accumulator other) {
+            VarBinaryMinMax other0 = (VarBinaryMinMax) other;
+
+            if (other0.empty) {
+                return;
+            }
+
+            val = empty ? other0.val : min
+                    ? (val.compareTo(other0.val) < 0 ? val : other0.val)
+                    : (val.compareTo(other0.val) < 0 ? other0.val : val);
+
+            empty = false;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public Object end() {
+            return empty ? null : val;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public List<RelDataType> argumentTypes(IgniteTypeFactory typeFactory) {
+            return 
ArrayUtils.asList(typeFactory.createTypeWithNullability(typeFactory.createSqlType(VARBINARY),
 true));
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public RelDataType returnType(IgniteTypeFactory typeFactory) {
+            return 
typeFactory.createTypeWithNullability(typeFactory.createSqlType(VARBINARY), 
true);
+        }
+    }
+
     private static class DistinctAccumulator implements Accumulator {
         private final Accumulator acc;
 
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/SortNode.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/SortNode.java
index 079661662b..cf7ab16fe8 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/SortNode.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/SortNode.java
@@ -19,9 +19,14 @@ package org.apache.ignite.internal.sql.engine.exec.rel;
 
 import static org.apache.ignite.internal.util.CollectionUtils.nullOrEmpty;
 
+import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.List;
 import java.util.PriorityQueue;
+import java.util.function.Supplier;
 import org.apache.ignite.internal.sql.engine.exec.ExecutionContext;
+import org.apache.ignite.internal.util.BoundedPriorityQueue;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Sort node.
@@ -38,16 +43,45 @@ public class SortNode<RowT> extends AbstractNode<RowT> 
implements SingleNode<Row
     /** Rows buffer. */
     private final PriorityQueue<RowT> rows;
 
+    /** SQL select limit. Negative if disabled. */
+    private final int limit;
+
+    /** Reverse-ordered rows in case of limited sort. */
+    private List<RowT> reversed;
+
     /**
      * Constructor.
      *
-     * @param ctx  Execution context.
+     * @param ctx Execution context.
      * @param comp Rows comparator.
+     * @param offset Offset.
+     * @param fetch Limit.
      */
-    public SortNode(ExecutionContext<RowT> ctx, Comparator<RowT> comp) {
+    public SortNode(ExecutionContext<RowT> ctx,
+            Comparator<RowT> comp,
+            @Nullable Supplier<Integer> offset,
+            @Nullable Supplier<Integer> fetch) {
         super(ctx);
+        assert fetch == null || fetch.get() >= 0;
+        assert offset == null || offset.get() >= 0;
 
-        rows = comp == null ? new PriorityQueue<>() : new 
PriorityQueue<>(comp);
+        limit = fetch == null ? -1 : fetch.get() + (offset == null ? 0 : 
offset.get());
+
+        if (limit < 1) {
+            rows = new PriorityQueue<>(comp);
+        } else {
+            rows = new BoundedPriorityQueue<>(limit, comp == null ? 
(Comparator<RowT>) Comparator.reverseOrder() : comp.reversed());
+        }
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param ctx Execution context.
+     * @param comp Rows comparator.
+     */
+    public SortNode(ExecutionContext<RowT> ctx, Comparator<RowT> comp) {
+        this(ctx, comp, null, null);
     }
 
     /** {@inheritDoc} */
@@ -56,6 +90,9 @@ public class SortNode<RowT> extends AbstractNode<RowT> 
implements SingleNode<Row
         requested = 0;
         waiting = 0;
         rows.clear();
+        if (reversed != null) {
+            reversed.clear();
+        }
     }
 
     /** {@inheritDoc} */
@@ -91,6 +128,7 @@ public class SortNode<RowT> extends AbstractNode<RowT> 
implements SingleNode<Row
     public void push(RowT row) throws Exception {
         assert downstream() != null;
         assert waiting > 0;
+        assert reversed == null || reversed.isEmpty();
 
         checkState();
 
@@ -127,12 +165,32 @@ public class SortNode<RowT> extends AbstractNode<RowT> 
implements SingleNode<Row
 
         inLoop = true;
         try {
-            while (requested > 0 && !rows.isEmpty()) {
+            // Prepare final order (reversed).
+            if (limit > 0 && !rows.isEmpty()) {
+                if (reversed == null) {
+                    reversed = new ArrayList<>(rows.size());
+                }
+
+                while (!rows.isEmpty()) {
+                    reversed.add(rows.poll());
+
+                    if (++processed >= inBufSize) {
+                        // Allow the others to do their job.
+                        context().execute(this::flush, this::onError);
+
+                        return;
+                    }
+                }
+
+                processed = 0;
+            }
+
+            while (requested > 0 && !(reversed == null ? rows.isEmpty() : 
reversed.isEmpty())) {
                 checkState();
 
                 requested--;
 
-                downstream().push(rows.poll());
+                downstream().push(reversed == null ? rows.poll() : 
reversed.remove(reversed.size() - 1));
 
                 if (++processed >= inBufSize && requested > 0) {
                     // allow others to do their job
@@ -142,7 +200,7 @@ public class SortNode<RowT> extends AbstractNode<RowT> 
implements SingleNode<Row
                 }
             }
 
-            if (rows.isEmpty()) {
+            if (reversed == null ? rows.isEmpty() : reversed.isEmpty()) {
                 if (requested > 0) {
                     downstream().end();
                 }
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/metadata/IgniteMdRowCount.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/metadata/IgniteMdRowCount.java
index 2a9b551657..e130a4f18f 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/metadata/IgniteMdRowCount.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/metadata/IgniteMdRowCount.java
@@ -25,6 +25,7 @@ import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.JoinInfo;
 import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.core.Minus;
+import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.metadata.ReflectiveRelMetadataProvider;
 import org.apache.calcite.rel.metadata.RelMdRowCount;
 import org.apache.calcite.rel.metadata.RelMdUtil;
@@ -56,6 +57,12 @@ public class IgniteMdRowCount extends RelMdRowCount {
         return rel.estimateRowCount(mq);
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public Double getRowCount(Sort rel, RelMetadataQuery mq) {
+        return rel.estimateRowCount(mq);
+    }
+
     /**
      * RowCount of Spool equals to estimated row count of its child by 
default, but IndexSpool has internal filter that
      * could filter out some rows, hence we need to estimate it differently.
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/metadata/cost/IgniteCost.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/metadata/cost/IgniteCost.java
index 0533e44aa5..904836793f 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/metadata/cost/IgniteCost.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/metadata/cost/IgniteCost.java
@@ -42,6 +42,12 @@ public class IgniteCost implements RelOptCost {
     /** Cost of a lookup at the hash. */
     public static final double HASH_LOOKUP_COST = 10;
 
+    /** In case the fetch value is a DYNAMIC_PARAM. */
+    public static final double FETCH_IS_PARAM_FACTOR = 0.01;
+
+    /** In case the offset value is a DYNAMIC_PARAM. */
+    public static final double OFFSET_IS_PARAM_FACTOR = 0.5;
+
     /**
      * With broadcast distribution each row will be sent to the each 
distination node, thus the total bytes amount will
      * be multiplies of the destination nodes count. Right now it's just a 
const.
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteLimit.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteLimit.java
index 2861de2f16..f6b4d4af5b 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteLimit.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteLimit.java
@@ -17,6 +17,10 @@
 
 package org.apache.ignite.internal.sql.engine.rel;
 
+import static 
org.apache.ignite.internal.sql.engine.metadata.cost.IgniteCost.FETCH_IS_PARAM_FACTOR;
+import static 
org.apache.ignite.internal.sql.engine.metadata.cost.IgniteCost.OFFSET_IS_PARAM_FACTOR;
+import static 
org.apache.ignite.internal.sql.engine.util.RexUtils.doubleFromRex;
+
 import java.util.List;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptCost;
@@ -28,10 +32,8 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.SingleRel;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
-import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexShuttle;
-import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.util.Pair;
 import org.apache.ignite.internal.sql.engine.metadata.cost.IgniteCost;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
@@ -39,12 +41,6 @@ import 
org.apache.ignite.internal.sql.engine.trait.TraitUtils;
 
 /** Relational expression that applies a limit and/or offset to its input. */
 public class IgniteLimit extends SingleRel implements IgniteRel {
-    /** In case the fetch value is a DYNAMIC_PARAM. */
-    private static final double FETCH_IS_PARAM_FACTOR = 0.01;
-
-    /** In case the offset value is a DYNAMIC_PARAM. */
-    private static final double OFFSET_IS_PARAM_FACTOR = 0.5;
-
     /** Offset. */
     private final RexNode offset;
 
@@ -180,26 +176,6 @@ public class IgniteLimit extends SingleRel implements 
IgniteRel {
         return Math.max(0, Math.min(lim, inputRowCount - off));
     }
 
-    /**
-     * DoubleFromRex.
-     * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859
-     *
-     * @return Integer value of the literal expression.
-     */
-    private double doubleFromRex(RexNode n, double def) {
-        try {
-            if (n.isA(SqlKind.LITERAL)) {
-                return ((RexLiteral) n).getValueAs(Integer.class);
-            } else {
-                return def;
-            }
-        } catch (Exception e) {
-            assert false : "Unable to extract value: " + e.getMessage();
-
-            return def;
-        }
-    }
-
     /**
      * Get offset.
      */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSort.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSort.java
index e88bd27f44..6664df0709 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSort.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSort.java
@@ -17,7 +17,10 @@
 
 package org.apache.ignite.internal.sql.engine.rel;
 
+import static 
org.apache.ignite.internal.sql.engine.metadata.cost.IgniteCost.FETCH_IS_PARAM_FACTOR;
+import static 
org.apache.ignite.internal.sql.engine.metadata.cost.IgniteCost.OFFSET_IS_PARAM_FACTOR;
 import static 
org.apache.ignite.internal.sql.engine.trait.TraitUtils.changeTraits;
+import static 
org.apache.ignite.internal.sql.engine.util.RexUtils.doubleFromRex;
 
 import java.util.List;
 import org.apache.calcite.plan.RelOptCluster;
@@ -45,9 +48,30 @@ public class IgniteSort extends Sort implements IgniteRel {
     /**
      * Constructor.
      *
-     * @param cluster   Cluster.
-     * @param traits    Trait set.
-     * @param child     Input node.
+     * @param cluster Cluster.
+     * @param traits Trait set.
+     * @param child Input node.
+     * @param collation Collation.
+     * @param offset Offset.
+     * @param fetch Limit.
+     */
+    public IgniteSort(
+            RelOptCluster cluster,
+            RelTraitSet traits,
+            RelNode child,
+            RelCollation collation,
+            RexNode offset,
+            RexNode fetch
+    ) {
+        super(cluster, traits, child, collation, offset, fetch);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param cluster Cluster.
+     * @param traits Trait set.
+     * @param child Input node.
      * @param collation Collation.
      */
     public IgniteSort(
@@ -55,7 +79,7 @@ public class IgniteSort extends Sort implements IgniteRel {
             RelTraitSet traits,
             RelNode child,
             RelCollation collation) {
-        super(cluster, traits, child, collation);
+        this(cluster, traits, child, collation, null, null);
     }
 
     /**
@@ -75,9 +99,7 @@ public class IgniteSort extends Sort implements IgniteRel {
             RexNode offset,
             RexNode fetch
     ) {
-        assert offset == null && fetch == null;
-
-        return new IgniteSort(getCluster(), traitSet, newInput, newCollation);
+        return new IgniteSort(getCluster(), traitSet, newInput, 
traitSet.getCollation(), offset, fetch);
     }
 
     /** {@inheritDoc} */
@@ -99,9 +121,14 @@ public class IgniteSort extends Sort implements IgniteRel {
             return null;
         }
 
-        RelCollation collation = TraitUtils.collation(required);
+        RelCollation requiredCollation = TraitUtils.collation(required);
+        RelCollation relCollation = traitSet.getCollation();
 
-        return Pair.of(required.replace(collation), 
List.of(required.replace(RelCollations.EMPTY)));
+        if (!requiredCollation.satisfies(relCollation)) {
+            return null;
+        }
+
+        return Pair.of(required, 
List.of(required.replace(RelCollations.EMPTY)));
     }
 
     /** {@inheritDoc} */
@@ -116,17 +143,26 @@ public class IgniteSort extends Sort implements IgniteRel 
{
         return Pair.of(childTraits.replace(collation()), List.of(childTraits));
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public double estimateRowCount(RelMetadataQuery mq) {
+        return memRows(mq.getRowCount(getInput()));
+    }
+
     /** {@inheritDoc} */
     @Override
     public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery 
mq) {
-        double rows = mq.getRowCount(getInput());
+        double inputRows = mq.getRowCount(getInput());
+
+        double memRows = memRows(inputRows);
 
-        double cpuCost = rows * IgniteCost.ROW_PASS_THROUGH_COST + 
Util.nLogN(rows) * IgniteCost.ROW_COMPARISON_COST;
-        double memory = rows * getRowType().getFieldCount() * 
IgniteCost.AVERAGE_FIELD_SIZE;
+        double cpuCost = inputRows * IgniteCost.ROW_PASS_THROUGH_COST + 
Util.nLogM(inputRows, memRows)
+                * IgniteCost.ROW_COMPARISON_COST;
+        double memory = memRows * getRowType().getFieldCount() * 
IgniteCost.AVERAGE_FIELD_SIZE;
 
         IgniteCostFactory costFactory = (IgniteCostFactory) 
planner.getCostFactory();
 
-        RelOptCost cost = costFactory.makeCost(rows, cpuCost, 0, memory, 0);
+        RelOptCost cost = costFactory.makeCost(inputRows, cpuCost, 0, memory, 
0);
 
         // Distributed sorting is more preferable than sorting on the single 
node.
         if (TraitUtils.distributionEnabled(this) && 
TraitUtils.distribution(traitSet).satisfies(IgniteDistributions.single())) {
@@ -139,6 +175,16 @@ public class IgniteSort extends Sort implements IgniteRel {
     /** {@inheritDoc} */
     @Override
     public IgniteRel clone(RelOptCluster cluster, List<IgniteRel> inputs) {
-        return new IgniteSort(cluster, getTraitSet(), sole(inputs), collation);
+        return new IgniteSort(cluster, getTraitSet(), sole(inputs), collation, 
offset, fetch);
+    }
+
+    /** Rows number to keep in memory and sort. */
+    private double memRows(double inputRows) {
+        double fetch = this.fetch != null ? doubleFromRex(this.fetch, 
inputRows * FETCH_IS_PARAM_FACTOR)
+                : inputRows;
+        double offset = this.offset != null ? doubleFromRex(this.offset, 
inputRows * OFFSET_IS_PARAM_FACTOR)
+                : 0;
+
+        return Math.min(inputRows, fetch + offset);
     }
 }
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/SortConverterRule.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/SortConverterRule.java
index b914f61232..37644d7535 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/SortConverterRule.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/SortConverterRule.java
@@ -17,11 +17,13 @@
 
 package org.apache.ignite.internal.sql.engine.rule;
 
+import java.util.Map;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelRule;
 import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.logical.LogicalSort;
@@ -68,15 +70,27 @@ public class SortConverterRule extends 
RelRule<SortConverterRule.Config> {
                     .replace(sort.getCollation())
                     .replace(IgniteDistributions.single());
 
-            call.transformTo(
-                    new IgniteLimit(
-                            cluster,
-                            traits,
-                            convert(sort.getInput(), traits),
-                            sort.offset,
-                            sort.fetch
-                    )
-            );
+            if (sort.collation == RelCollations.EMPTY || sort.fetch == null) {
+                call.transformTo(new IgniteLimit(cluster, traits, 
convert(sort.getInput(), traits), sort.offset,
+                        sort.fetch));
+            } else {
+                RelNode igniteSort = new IgniteSort(
+                        cluster,
+                        
cluster.traitSetOf(IgniteConvention.INSTANCE).replace(sort.getCollation()),
+                        convert(sort.getInput(), 
cluster.traitSetOf(IgniteConvention.INSTANCE)),
+                        sort.getCollation(),
+                        sort.offset,
+                        sort.fetch
+                );
+
+                call.transformTo(
+                        new IgniteLimit(cluster, traits, convert(igniteSort, 
traits), sort.offset, sort.fetch),
+                        Map.of(
+                                new IgniteLimit(cluster, traits, 
convert(sort.getInput(), traits), sort.offset, sort.fetch),
+                                sort
+                        )
+                );
+            }
         } else {
             RelTraitSet outTraits = 
cluster.traitSetOf(IgniteConvention.INSTANCE).replace(sort.getCollation());
             RelTraitSet inTraits = 
cluster.traitSetOf(IgniteConvention.INSTANCE);
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/fun/IgniteSqlOperatorTable.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/fun/IgniteSqlOperatorTable.java
index 12f451faad..59d39cd5bd 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/fun/IgniteSqlOperatorTable.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/fun/IgniteSqlOperatorTable.java
@@ -148,6 +148,9 @@ public class IgniteSqlOperatorTable extends 
ReflectiveSqlOperatorTable {
         register(SqlStdOperatorTable.SINGLE_VALUE);
         register(SqlStdOperatorTable.FILTER);
 
+        register(SqlStdOperatorTable.EVERY);
+        register(SqlStdOperatorTable.SOME);
+
         // IS ... operator.
         register(SqlStdOperatorTable.IS_NULL);
         register(SqlStdOperatorTable.IS_NOT_NULL);
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMethod.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMethod.java
index 9bee587c82..043449d3ee 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMethod.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMethod.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.sql.engine.util;
 
 import java.lang.reflect.Method;
+import java.lang.reflect.Type;
 import java.util.Objects;
 import org.apache.calcite.DataContext;
 import org.apache.calcite.avatica.util.ByteString;
@@ -55,6 +56,9 @@ public enum IgniteMethod {
     /** See {@link ExecutionContext#nullBound()}. */
     CONTEXT_NULL_BOUND(ExecutionContext.class, "nullBound"),
 
+    /** See {@link ExecutionContext#getParameter(String, Type)}. */
+    CONTEXT_GET_PARAMETER_VALUE(ExecutionContext.class, "getParameter", 
String.class, Type.class),
+
     /** See {@link SingleScalar#execute(ExecutionContext, Object, Object)}. */
     SCALAR_EXECUTE(SingleScalar.class, "execute", ExecutionContext.class, 
Object.class, Object.class),
 
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
index 579ef1ad02..4af607fa83 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
@@ -744,7 +744,8 @@ public class RexUtils {
     private static boolean idxOpSupports(RexNode op) {
         return op instanceof RexLiteral
                 || op instanceof RexDynamicParam
-                || op instanceof RexFieldAccess;
+                || op instanceof RexFieldAccess
+                || !containsRef(op);
     }
 
     /**
@@ -905,6 +906,25 @@ public class RexUtils {
         return cors;
     }
 
+    /**
+     * Double value of the literal expression.
+     *
+     * @return Double value of the literal expression.
+     */
+    public static double doubleFromRex(RexNode n, double def) {
+        try {
+            if (n.isA(SqlKind.LITERAL)) {
+                return ((RexLiteral) n).getValueAs(Integer.class);
+            } else {
+                return def;
+            }
+        } catch (Exception e) {
+            assert false : "Unable to extract value: " + e.getMessage();
+
+            return def;
+        }
+    }
+
     /**
      * NotNullKeys.
      * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859
@@ -925,6 +945,28 @@ public class RexUtils {
         return keys;
     }
 
+    private static boolean containsRef(RexNode node) {
+        RexVisitor<Void> v = new RexVisitorImpl<>(true) {
+            @Override
+            public Void visitInputRef(RexInputRef inputRef) {
+                throw Util.FoundOne.NULL;
+            }
+
+            @Override
+            public Void visitLocalRef(RexLocalRef locRef) {
+                throw Util.FoundOne.NULL;
+            }
+        };
+
+        try {
+            node.accept(v);
+
+            return false;
+        } catch (Util.FoundOne e) {
+            return true;
+        }
+    }
+
     /** Visitor for replacing scan local refs to input refs. */
     private static class LocalRefReplacer extends RexShuttle {
         private static final RexShuttle INSTANCE = new LocalRefReplacer();
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/TypeUtils.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/TypeUtils.java
index 5095e77570..0fe3988738 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/TypeUtils.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/TypeUtils.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.sql.engine.util;
 import static org.apache.ignite.internal.sql.engine.util.Commons.transform;
 
 import java.lang.reflect.Type;
+import java.math.BigDecimal;
 import java.time.Duration;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
@@ -42,6 +43,7 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeFactoryImpl;
 import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.runtime.SqlFunctions;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.ignite.internal.schema.DecimalNativeType;
@@ -53,6 +55,7 @@ import 
org.apache.ignite.internal.sql.engine.exec.ExecutionContext;
 import org.apache.ignite.internal.sql.engine.exec.RowHandler;
 import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
 import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
+import org.apache.ignite.internal.sql.engine.type.UuidFunctions;
 import org.apache.ignite.internal.sql.engine.type.UuidType;
 import org.apache.ignite.sql.ColumnType;
 import org.jetbrains.annotations.NotNull;
@@ -265,9 +268,27 @@ public class TypeUtils {
             return (int) ((Period) val).toTotalMonths();
         } else if (storageType == byte[].class) {
             return new ByteString((byte[]) val);
+        } else if (val instanceof Number && storageType != val.getClass()) {
+            // For dynamic parameters we don't know exact parameter type in 
compile time. To avoid casting errors in
+            // runtime we should convert parameter value to expected type.
+            Number num = (Number) val;
+
+            return Byte.class.equals(storageType) || 
byte.class.equals(storageType) ? SqlFunctions.toByte(num) :
+                    Short.class.equals(storageType) || 
short.class.equals(storageType) ? SqlFunctions.toShort(num) :
+                            Integer.class.equals(storageType) || 
int.class.equals(storageType) ? SqlFunctions.toInt(num) :
+                                    Long.class.equals(storageType) || 
long.class.equals(storageType) ? SqlFunctions.toLong(num) :
+                                            Float.class.equals(storageType) || 
float.class.equals(storageType) ? SqlFunctions.toFloat(num) :
+                                                    
Double.class.equals(storageType) || double.class.equals(storageType)
+                                                            ? 
SqlFunctions.toDouble(num) :
+                                                            
BigDecimal.class.equals(storageType) ? SqlFunctions.toBigDecimal(num) : num;
         } else if (storageType == UUID.class) {
-            assert val instanceof UUID : storageTypeMismatch(val, UUID.class);
-            return val;
+            //ToDo: This a quick fix of the issue 
https://issues.apache.org/jira/browse/IGNITE-18831 and should be reworked.
+            if (val instanceof String) {
+                return UuidFunctions.cast(val);
+            } else {
+                assert val instanceof UUID : storageTypeMismatch(val, 
UUID.class);
+                return val;
+            }
         } else {
             // IgniteCustomType: Add storageTypeMismatch assertion for your 
type.
             return val;
@@ -424,7 +445,7 @@ public class TypeUtils {
 
                 var varlen = (VarlenNativeType) nativeType;
 
-                return factory.createSqlType(SqlTypeName.BINARY, 
varlen.length());
+                return factory.createSqlType(SqlTypeName.VARBINARY, 
varlen.length());
             }
             case BITMASK:
                 // TODO IGNITE-18431.
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/AbstractExecutionTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/AbstractExecutionTest.java
index 44e4462eaf..724c580ae8 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/AbstractExecutionTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/AbstractExecutionTest.java
@@ -61,7 +61,6 @@ public class AbstractExecutionTest extends IgniteAbstractTest 
{
     public static final Object[][] EMPTY = new Object[0][];
 
     private Throwable lastE;
-    private List<UUID> nodes;
 
     private QueryTaskExecutorImpl taskExecutor;
 
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/LimitExecutionTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/LimitExecutionTest.java
index 061550601b..08de8e9400 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/LimitExecutionTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/LimitExecutionTest.java
@@ -17,13 +17,17 @@
 
 package org.apache.ignite.internal.sql.engine.exec.rel;
 
+import static 
org.apache.ignite.internal.sql.engine.util.Commons.IN_BUFFER_SIZE;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import java.util.Collections;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 import org.apache.ignite.internal.sql.engine.exec.ExecutionContext;
-import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -33,7 +37,7 @@ public class LimitExecutionTest extends AbstractExecutionTest 
{
     /** Tests correct results fetched with Limit node. */
     @Test
     public void testLimit() {
-        int bufSize = Commons.IN_BUFFER_SIZE;
+        int bufSize = IN_BUFFER_SIZE;
 
         checkLimit(0, 1);
         checkLimit(1, 0);
@@ -51,6 +55,58 @@ public class LimitExecutionTest extends 
AbstractExecutionTest {
         checkLimit(2000, 3000);
     }
 
+    /** Tests Sort node can limit its output when fetch param is set. */
+    @Test
+    public void testSortLimit() throws Exception {
+        int bufSize = IN_BUFFER_SIZE;
+
+        checkLimitSort(0, 1);
+        checkLimitSort(1, 0);
+        checkLimitSort(1, 1);
+        checkLimitSort(0, bufSize);
+        checkLimitSort(bufSize, 0);
+        checkLimitSort(bufSize, bufSize);
+        checkLimitSort(bufSize - 1, 1);
+        checkLimitSort(2000, 0);
+        checkLimitSort(0, 3000);
+        checkLimitSort(2000, 3000);
+    }
+
+    /**
+     * Check limit sort.
+     *
+     * @param offset Rows offset.
+     * @param fetch Fetch rows count (zero means unlimited).
+     */
+    private void checkLimitSort(int offset, int fetch) {
+        assert offset >= 0;
+        assert fetch >= 0;
+
+        ExecutionContext<Object[]> ctx = executionContext();
+
+        RootNode<Object[]> rootNode = new RootNode<>(ctx);
+
+        SortNode<Object[]> sortNode = new SortNode<>(ctx, 
LimitExecutionTest::compareArrays, () -> offset,
+                fetch == 0 ? null : () -> fetch);
+
+        List<Object[]> data = IntStream.range(0, IN_BUFFER_SIZE + fetch + 
offset).boxed()
+                .map(i -> new Object[] {i}).collect(Collectors.toList());
+        Collections.shuffle(data);
+
+        ScanNode<Object[]> srcNode = new ScanNode<>(ctx, data);
+
+        rootNode.register(sortNode);
+
+        sortNode.register(srcNode);
+
+        for (int i = 0; i < offset + fetch; i++) {
+            assertTrue(rootNode.hasNext());
+            assertEquals(i, rootNode.next()[0]);
+        }
+
+        assertEquals(fetch == 0, rootNode.hasNext());
+    }
+
     /**
      * Check correct result size fetched.
      *
@@ -82,6 +138,53 @@ public class LimitExecutionTest extends 
AbstractExecutionTest {
         }
     }
 
+    /**
+     * Check the passed value to belong to array type.
+     *
+     * @param val Value to check.
+     * @return {@code True} if not null and array.
+     */
+    public static boolean isArray(Object val) {
+        return val != null && val.getClass().isArray();
+    }
+
+    /**
+     * Compare arrays.
+     *
+     * @param a1 Value 1.
+     * @param a2 Value 2.
+     * @return a negative integer, zero, or a positive integer as the first 
argument is less than, equal to, or greater than the second.
+     */
+    public static int compareArrays(Object[] a1, Object[] a2) {
+        if (a1 == a2) {
+            return 0;
+        }
+
+        int l = Math.min(a1.length, a2.length);
+
+        for (int i = 0; i < l; i++) {
+            if (a1[i] == null || a2[i] == null) {
+                if (a1[i] != null || a2[i] != null) {
+                    return a1[i] != null ? 1 : -1;
+                }
+
+                continue;
+            }
+
+            if (isArray(a1[i]) && isArray(a2[i])) {
+                int res = compareArrays((Object[]) a1[i], (Object[]) a2[i]);
+
+                if (res != 0) {
+                    return res;
+                }
+            }
+
+            return ((Comparable) a1[i]).compareTo(a2[i]);
+        }
+
+        return Integer.compare(a1.length, a2.length);
+    }
+
     private static class SourceNode extends AbstractNode<Object[]> {
         AtomicInteger requested = new AtomicInteger();
 
@@ -90,7 +193,8 @@ public class LimitExecutionTest extends 
AbstractExecutionTest {
         }
 
         /** {@inheritDoc} */
-        @Override protected void rewindInternal() {
+        @Override
+        protected void rewindInternal() {
             // No-op.
         }
 
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractPlannerTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractPlannerTest.java
index 103821bc48..6490f9574e 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractPlannerTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractPlannerTest.java
@@ -106,6 +106,7 @@ import 
org.apache.ignite.internal.sql.engine.prepare.MappingQueryContext;
 import org.apache.ignite.internal.sql.engine.prepare.PlannerHelper;
 import org.apache.ignite.internal.sql.engine.prepare.PlanningContext;
 import org.apache.ignite.internal.sql.engine.prepare.Splitter;
+import org.apache.ignite.internal.sql.engine.prepare.bounds.ExactBounds;
 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.IgniteIndexScan;
@@ -1324,6 +1325,10 @@ public abstract class AbstractPlannerTest extends 
IgniteAbstractTest {
         }
     }
 
+    Predicate<SearchBounds> exact(Object val) {
+        return b -> b instanceof ExactBounds && matchValue(val, ((ExactBounds) 
b).bound());
+    }
+
     void assertBounds(String sql, List<Object> params, IgniteSchema schema, 
Predicate<SearchBounds>... predicates) throws Exception {
         assertPlan(sql, schema, 
nodeOrAnyChild(isInstanceOf(IgniteIndexScan.class)
                 .and(scan -> matchBounds(scan.searchBounds(), predicates))), 
params);
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/LimitOffsetPlannerTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/LimitOffsetPlannerTest.java
index e5f219cb68..ee052b2fed 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/LimitOffsetPlannerTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/LimitOffsetPlannerTest.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.internal.sql.engine.planner;
 
+import static 
org.apache.ignite.internal.sql.engine.util.RexUtils.doubleFromRex;
+
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.util.ImmutableIntList;
@@ -24,6 +26,7 @@ import 
org.apache.ignite.internal.sql.engine.rel.IgniteExchange;
 import org.apache.ignite.internal.sql.engine.rel.IgniteIndexScan;
 import org.apache.ignite.internal.sql.engine.rel.IgniteLimit;
 import org.apache.ignite.internal.sql.engine.rel.IgniteSort;
+import org.apache.ignite.internal.sql.engine.rel.IgniteTableScan;
 import org.apache.ignite.internal.sql.engine.rel.IgniteUnionAll;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
@@ -83,44 +86,67 @@ public class LimitOffsetPlannerTest extends 
AbstractPlannerTest {
         IgniteSchema publicSchema = 
createSchemaWithTable(IgniteDistributions.random());
 
         // Simple case, Limit can't be pushed down under Exchange or Sort. 
Sort before Exchange is more preferable.
-        assertPlan("SELECT * FROM TEST ORDER BY ID LIMIT 10 OFFSET 10", 
publicSchema,
+        assertPlan("SELECT * FROM TEST ORDER BY ID LIMIT 5 OFFSET 10", 
publicSchema,
                 isInstanceOf(IgniteLimit.class)
                         .and(input(isInstanceOf(IgniteExchange.class)
-                                .and(input(isInstanceOf(IgniteSort.class))))));
+                                .and(input(isInstanceOf(IgniteSort.class)
+                                        .and(s -> doubleFromRex(s.fetch, -1) 
== 5.0)
+                                        .and(s -> doubleFromRex(s.offset, -1) 
== 10.0))))));
 
-        // Simple case without ordering.
-        assertPlan("SELECT * FROM TEST OFFSET 10 ROWS FETCH FIRST 10 ROWS 
ONLY", publicSchema,
+        // Same simple case but witout offset.
+        assertPlan("SELECT * FROM TEST ORDER BY ID LIMIT 5", publicSchema,
                 isInstanceOf(IgniteLimit.class)
-                    .and(input(isInstanceOf(IgniteExchange.class)))
-                    
.and(hasChildThat(isInstanceOf(IgniteSort.class)).negate()));
+                        .and(input(isInstanceOf(IgniteExchange.class)
+                                .and(input(isInstanceOf(IgniteSort.class)
+                                        .and(s -> doubleFromRex(s.fetch, -1) 
== 5.0)
+                                        .and(s -> s.offset == null))))));
+
+        // No special liited sort required if LIMIT is not set.
+        assertPlan("SELECT * FROM TEST ORDER BY ID OFFSET 10", publicSchema,
+                isInstanceOf(IgniteLimit.class)
+                        .and(input(isInstanceOf(IgniteExchange.class)
+                                .and(input(isInstanceOf(IgniteSort.class)
+                                        .and(s -> s.fetch == null)
+                                        .and(s -> s.offset == null))))));
 
+        // Simple case without ordering.
+        assertPlan("SELECT * FROM TEST OFFSET 10 ROWS FETCH FIRST 5 ROWS 
ONLY", publicSchema,
+                isInstanceOf(IgniteLimit.class)
+                        .and(s -> doubleFromRex(s.fetch(), -1) == 5)
+                        .and(s -> doubleFromRex(s.offset(), -1) == 10)
+                        .and(input(isInstanceOf(IgniteExchange.class)))
+                        
.and(hasChildThat(isInstanceOf(IgniteSort.class)).negate()));
         // Check that Sort node is not eliminated by aggregation and Exchange 
node is not eliminated by distribution
         // required by parent nodes.
         assertPlan("SELECT * FROM TEST UNION (SELECT * FROM TEST ORDER BY ID 
LIMIT 10)", publicSchema,
                 nodeOrAnyChild(isInstanceOf(IgniteUnionAll.class)
-                    .and(hasChildThat(isInstanceOf(IgniteLimit.class)
-                        .and(input(isInstanceOf(IgniteExchange.class)
-                            .and(input(isInstanceOf(IgniteSort.class)))))))));
+                        .and(hasChildThat(isInstanceOf(IgniteLimit.class)
+                                .and(input(isInstanceOf(IgniteExchange.class)
+                                        
.and(input(isInstanceOf(IgniteSort.class)
+                                                .and(s -> 
doubleFromRex(s.fetch, -1) == 10.0)))))))));
 
         // Check that internal Sort node is not eliminated by external Sort 
node with different collation.
         assertPlan("SELECT * FROM (SELECT * FROM TEST ORDER BY ID LIMIT 10) 
ORDER BY VAL", publicSchema,
                 nodeOrAnyChild(isInstanceOf(IgniteSort.class)
                     .and(hasChildThat(isInstanceOf(IgniteLimit.class)
                         .and(input(isInstanceOf(IgniteExchange.class)
-                            .and(input(isInstanceOf(IgniteSort.class)))))))));
+                                .and(input(isInstanceOf(IgniteSort.class)
+                                        .and(s -> doubleFromRex(s.fetch, -1) 
== 10.0)))))))));
 
         // Check that extended collation is passed through the Limit node if 
it satisfies the Limit collation.
         assertPlan("SELECT * FROM (SELECT * FROM TEST ORDER BY ID LIMIT 10) 
ORDER BY ID, VAL", publicSchema,
                 isInstanceOf(IgniteLimit.class)
                     .and(input(isInstanceOf(IgniteExchange.class)
                         .and(input(isInstanceOf(IgniteSort.class)
-                            .and(s -> 
s.collation().getKeys().equals(ImmutableIntList.of(0, 1))))))));
+                                
.and(input(isInstanceOf(IgniteTableScan.class)))
+                                .and(s -> 
s.collation().getKeys().equals(ImmutableIntList.of(0, 1))))))));
 
         // Check that external Sort node is not required if external collation 
is subset of internal collation.
         assertPlan("SELECT * FROM (SELECT * FROM TEST ORDER BY ID, VAL LIMIT 
10) ORDER BY ID", publicSchema,
                 isInstanceOf(IgniteLimit.class)
                     .and(input(isInstanceOf(IgniteExchange.class)
-                        .and(input(isInstanceOf(IgniteSort.class))))));
+                            .and(input(isInstanceOf(IgniteSort.class)
+                                    .and(s -> doubleFromRex(s.fetch, -1) == 
10.0))))));
 
         // Check double limit when external collation is a subset of internal 
collation.
         assertPlan("SELECT * FROM (SELECT * FROM TEST ORDER BY ID, VAL LIMIT 
10) ORDER BY ID LIMIT 5 OFFSET 3",
@@ -128,15 +154,19 @@ public class LimitOffsetPlannerTest extends 
AbstractPlannerTest {
                 isInstanceOf(IgniteLimit.class)
                     .and(input(isInstanceOf(IgniteLimit.class)
                         .and(input(isInstanceOf(IgniteExchange.class)
-                            .and(input(isInstanceOf(IgniteSort.class))))))));
+                                .and(input(isInstanceOf(IgniteSort.class)
+                                        .and(s -> doubleFromRex(s.fetch, -1) 
== 10.0)
+                                        .and(s -> s.offset == null))))))));
 
         // Check limit/exchange/sort rel order in subquery.
         assertPlan("SELECT NULLIF((SELECT id FROM test ORDER BY id LIMIT 1 
OFFSET 1), id) FROM test",
                 publicSchema,
                 hasChildThat(isInstanceOf(IgniteLimit.class)
-                    .and(input(isInstanceOf(IgniteExchange.class)
-                        .and(e -> e.distribution() == 
IgniteDistributions.single())
-                        .and(input(isInstanceOf(IgniteSort.class)))))));
+                        .and(input(isInstanceOf(IgniteExchange.class)
+                                .and(e -> e.distribution() == 
IgniteDistributions.single())
+                                .and(input(isInstanceOf(IgniteSort.class)
+                                        .and(s -> doubleFromRex(s.offset, -1) 
== 1)
+                                        .and(s -> doubleFromRex(s.fetch, -1) 
== 1)))))));
 
         publicSchema = createSchemaWithTable(IgniteDistributions.random(), 0);
 
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PlannerTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PlannerTest.java
index 6aa5cb3f4c..2a6ab9f3d1 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PlannerTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PlannerTest.java
@@ -493,6 +493,59 @@ public class PlannerTest extends AbstractPlannerTest {
         );
     }
 
+    /** Tests complex bounds expressions. */
+    @Test
+    public void testBoundsComplex() throws Exception {
+        IgniteTypeFactory typeFactory = new 
IgniteTypeFactory(IgniteTypeSystem.INSTANCE);
+
+        TestTable tbl = new TestTable(
+                new RelDataTypeFactory.Builder(typeFactory)
+                        .add("C1", typeFactory.createJavaType(Integer.class))
+                        .add("C2", typeFactory.createJavaType(Integer.class))
+                        .add("C3", typeFactory.createJavaType(Integer.class))
+                        .add("C4", typeFactory.createJavaType(Integer.class))
+                        .build(), "TEST") {
+            @Override
+            public ColocationGroup colocationGroup(MappingQueryContext ctx) {
+                return ColocationGroup.forNodes(select(NODES, 0));
+            }
+
+            @Override
+            public IgniteDistribution distribution() {
+                return IgniteDistributions.hash(List.of(0));
+            }
+        };
+
+        tbl.addIndex("C1C2C3", 0, 1, 2);
+
+        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
+
+        publicSchema.addTable(tbl);
+
+        assertBounds("SELECT * FROM TEST WHERE C1 = ? + 10", List.of(10), 
publicSchema,
+                exact("+(?0, 10)")
+        );
+
+        assertBounds("SELECT * FROM TEST WHERE C1 = 1 AND C2 > 
SUBSTRING(?::VARCHAR, 1, 2) || '3'", List.of("10"), publicSchema,
+                exact(1),
+                range("||(SUBSTRING(?0, 1, 2), _UTF-8'3')", "$NULL_BOUND()", 
false, false)
+        );
+
+        assertBounds("SELECT * FROM TEST WHERE C1 = 1 AND C2 > 
SUBSTRING(C3::VARCHAR, 1, 2) || '3'", List.of(), publicSchema,
+                exact(1),
+                empty()
+        );
+
+        assertBounds("SELECT (SELECT C1 FROM TEST t2 WHERE t2.C1 = t1.C1 + 
t1.C3 * ?) FROM TEST t1", List.of(10), publicSchema,
+                exact("+($cor0.C1, *($cor0.C3, ?0))")
+        );
+
+        assertPlan("SELECT * FROM TEST WHERE C1 = ? + C3", publicSchema, 
nodeOrAnyChild(isTableScan("TEST")), List.of(10));
+
+        assertPlan("SELECT (SELECT C1 FROM TEST t2 WHERE t2.C1 < t1.C1 + 
t2.C1) FROM TEST t1", publicSchema,
+                nodeOrAnyChild(isIndexScan("TEST", "C1C2C3")).negate());
+    }
+
     /** String representation of LEAST or GREATEST operator converted to CASE. 
*/
     private String leastOrGreatest(boolean least, String val0, String val1, 
String type) {
         return "CASE(OR(IS NULL(" + val0 + "), IS NULL(" + val1 + ")), null:" 
+ type + ", " + (least ? '<' : '>')
@@ -961,6 +1014,15 @@ public class PlannerTest extends AbstractPlannerTest {
         assertPlan(sql, Collections.singleton(publicSchema), hintCheck, 
hintStrategies, List.of());
     }
 
+    @Test
+    public void testMinusDateSerialization() throws Exception {
+        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
+
+        IgniteRel phys = physicalPlan("SELECT (DATE '2021-03-01' - DATE 
'2021-01-01') MONTHS", publicSchema);
+
+        checkSplitAndSerialization(phys, publicSchema);
+    }
+
     /**
      * IntermediateMapping.
      * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859


Reply via email to