You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by zs...@apache.org on 2022/02/01 16:13:44 UTC

[ignite-3] branch main updated: IGNITE-16328 Sql Adopt IGNITE-15992, IGNITE-16138 - Fixes #565.

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

zstan 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 3ad271c  IGNITE-16328 Sql Adopt IGNITE-15992, IGNITE-16138 - Fixes #565.
3ad271c is described below

commit 3ad271cc58225703ef408db319582f350453e06d
Author: zstan <st...@gmail.com>
AuthorDate: Tue Feb 1 19:12:57 2022 +0300

    IGNITE-16328 Sql Adopt IGNITE-15992, IGNITE-16138 - Fixes #565.
    
    Correlated queries with ORDER and LIMIT can't be planned.
    AssertionError: Input not sorted for some ORDER BY containing requests.
    
    Signed-off-by: zstan <st...@gmail.com>
---
 .../internal/sql/engine/ItSortAggregateTest.java   | 34 +++++++++++++
 .../internal/sql/engine/util/QueryChecker.java     | 18 +++----
 .../ignite/internal/sql/engine/exec/rel/Inbox.java | 55 ++++++++++++++--------
 .../sql/engine/exec/rel/SortAggregateNode.java     |  6 +--
 .../sql/engine/prepare/ddl/CreateIndexCommand.java |  2 +-
 .../internal/sql/engine/rel/IgniteIndexScan.java   | 10 ++--
 .../internal/sql/engine/rel/IgniteLimit.java       |  8 +++-
 .../internal/sql/engine/rel/IgniteTableScan.java   | 12 ++---
 .../engine/rel/agg/IgniteSortAggregateBase.java    | 16 +++++--
 .../engine/rel/logical/IgniteLogicalTableScan.java |  6 +--
 .../engine/planner/SortAggregatePlannerTest.java   | 41 ++++++++++++++++
 11 files changed, 154 insertions(+), 54 deletions(-)

diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSortAggregateTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSortAggregateTest.java
index 233ad60..4ac7024 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSortAggregateTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSortAggregateTest.java
@@ -60,12 +60,29 @@ public class ItSortAggregateTest extends AbstractBasicIntegrationTest {
                 )
                 .build();
 
+        TableDefinition schTbl2 = SchemaBuilders.tableBuilder("PUBLIC", "TEST_ONE_COL_IDX")
+                .columns(
+                        SchemaBuilders.column("PK", ColumnType.INT32).build(),
+                        SchemaBuilders.column("COL0", ColumnType.INT32).asNullable(true).build()
+                )
+                .withPrimaryKey("PK")
+                .withIndex(
+                        SchemaBuilders.sortedIndex("IDX")
+                                .addIndexColumn("COL0").desc().done()
+                                .build()
+                )
+                .build();
+
         Table table = CLUSTER_NODES.get(0).tables().createTable(schTbl1.canonicalName(), tblCh ->
                 SchemaConfigurationConverter.convert(schTbl1, tblCh)
                         .changeReplicas(2)
                         .changePartitions(10)
         );
 
+        Table tblOneColIdx = CLUSTER_NODES.get(0).tables().createTable(schTbl2.canonicalName(), tblCh ->
+                SchemaConfigurationConverter.convert(schTbl2, tblCh)
+        );
+
         RecordView<Tuple> view = table.recordView();
         for (int i = 0; i < ROWS; i++) {
             view.insert(
@@ -78,6 +95,16 @@ public class ItSortAggregateTest extends AbstractBasicIntegrationTest {
                             .set("VAL1", 2)
             );
         }
+
+        RecordView<Tuple> view1 = tblOneColIdx.recordView();
+        for (int i = 0; i < ROWS; i++) {
+            view1.insert(
+                    null,
+                    Tuple.create()
+                            .set("PK", i)
+                            .set("COL0", i)
+            );
+        }
     }
 
     @Test
@@ -98,4 +125,11 @@ public class ItSortAggregateTest extends AbstractBasicIntegrationTest {
             assertEquals(s0 * 2, (int) s1);
         });
     }
+
+    @Test
+    public void correctCollationsOnMapReduceSortAgg() {
+        List<List<?>> cursors = sql("SELECT PK FROM TEST_ONE_COL_IDX WHERE col0 IN (SELECT col0 FROM TEST_ONE_COL_IDX)");
+
+        assertEquals(ROWS, cursors.size());
+    }
 }
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/util/QueryChecker.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/util/QueryChecker.java
index 54c5cf6..cbf0650 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/util/QueryChecker.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/util/QueryChecker.java
@@ -95,14 +95,14 @@ public abstract class QueryChecker {
      */
     public static Matcher<String> notContainsProject(String schema, String tblName) {
         return CoreMatchers.not(containsSubPlan("Scan(table=[[" + schema + ", "
-                + tblName + "]], " + "requiredColunms="));
+                + tblName + "]], " + "requiredColumns="));
     }
 
     /**
      * {@link #containsProject(String, String, int...)} reverter.
      */
-    public static Matcher<String> notContainsProject(String schema, String tblName, int... requiredColunms) {
-        return CoreMatchers.not(containsProject(schema, tblName, requiredColunms));
+    public static Matcher<String> notContainsProject(String schema, String tblName, int... requiredColumns) {
+        return CoreMatchers.not(containsProject(schema, tblName, requiredColumns));
     }
 
     /**
@@ -110,13 +110,13 @@ public abstract class QueryChecker {
      *
      * @param schema          Schema name.
      * @param tblName         Table name.
-     * @param requiredColunms columns in projection.
+     * @param requiredColumns columns in projection.
      * @return Matcher.
      */
-    public static Matcher<String> containsProject(String schema, String tblName, int... requiredColunms) {
+    public static Matcher<String> containsProject(String schema, String tblName, int... requiredColumns) {
         Matcher<String> res = matches(".*Ignite(Table|Index)Scan\\(table=\\[\\[" + schema + ", "
                 + tblName + "\\]\\], " + ".*requiredColumns=\\[\\{"
-                + Arrays.toString(requiredColunms)
+                + Arrays.toString(requiredColumns)
                         .replaceAll("\\[", "")
                         .replaceAll("]", "") + "\\}\\].*");
         return res;
@@ -127,13 +127,13 @@ public abstract class QueryChecker {
      *
      * @param schema          Schema name.
      * @param tblName         Table name.
-     * @param requiredColunms columns in projection.
+     * @param requiredColumns columns in projection.
      * @return Matcher.
      */
-    public static Matcher<String> containsOneProject(String schema, String tblName, int... requiredColunms) {
+    public static Matcher<String> containsOneProject(String schema, String tblName, int... requiredColumns) {
         return matchesOnce(".*Ignite(Table|Index)Scan\\(table=\\[\\[" + schema + ", "
                 + tblName + "\\]\\], " + ".*requiredColumns=\\[\\{"
-                + Arrays.toString(requiredColunms)
+                + Arrays.toString(requiredColumns)
                         .replaceAll("\\[", "")
                         .replaceAll("]", "") + "\\}\\].*");
     }
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/Inbox.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/Inbox.java
index 1ff72d8..27d1434 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/Inbox.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/Inbox.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.internal.sql.engine.exec.rel;
 
+import static org.apache.calcite.util.Util.unexpected;
+
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -204,29 +206,43 @@ public class Inbox<RowT> extends AbstractNode<RowT> implements Mailbox<RowT>, Si
         }
     }
 
-    private void pushOrdered() throws Exception {
-        PriorityQueue<Pair<RowT, Buffer>> heap =
-                new PriorityQueue<>(Math.max(buffers.size(), 1), Map.Entry.comparingByKey(comp));
-
-        Iterator<Buffer> it = buffers.iterator();
-
+    /** Checks that all corresponding buffers are in ready state. */
+    private boolean checkAllBuffsReady(Iterator<Buffer> it) {
         while (it.hasNext()) {
             Buffer buf = it.next();
 
-            switch (buf.check()) {
-                case END:
-                    it.remove();
+            State state = buf.check();
 
-                    break;
+            switch (state) {
                 case READY:
-                    heap.offer(Pair.of(buf.peek(), buf));
-
+                    break;
+                case END:
+                    it.remove();
                     break;
                 case WAITING:
-
-                    return;
+                    return false;
                 default:
-                    break;
+                    throw unexpected(state);
+            }
+        }
+        return true;
+    }
+
+    private void pushOrdered() throws Exception {
+        if (!checkAllBuffsReady(buffers.iterator())) {
+            return;
+        }
+
+        PriorityQueue<Pair<RowT, Buffer>> heap =
+                new PriorityQueue<>(Math.max(buffers.size(), 1), Map.Entry.comparingByKey(comp));
+
+        for (Buffer buf : buffers) {
+            State state = buf.check();
+
+            if (state == State.READY) {
+                heap.offer(Pair.of(buf.peek(), buf));
+            } else {
+                throw new AssertionError("Unexpected buffer state: " + state);
             }
         }
 
@@ -240,20 +256,19 @@ public class Inbox<RowT> extends AbstractNode<RowT> implements Mailbox<RowT>, Si
                 requested--;
                 downstream().push(buf.remove());
 
-                switch (buf.check()) {
+                State state = buf.check();
+
+                switch (state) {
                     case END:
                         buffers.remove(buf);
-
                         break;
                     case READY:
                         heap.offer(Pair.of(buf.peek(), buf));
-
                         break;
                     case WAITING:
-
                         return;
                     default:
-                        break;
+                        throw unexpected(state);
                 }
             }
         } finally {
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/SortAggregateNode.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/SortAggregateNode.java
index 81899d8..593845f 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/SortAggregateNode.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/SortAggregateNode.java
@@ -226,16 +226,12 @@ public class SortAggregateNode<RowT> extends AbstractNode<RowT> implements Singl
     private class Group {
         private final List<AccumulatorWrapper<RowT>> accumWrps;
 
-        private final RowHandler<RowT> handler;
-
         private final Object[] grpKeys;
 
         private Group(Object[] grpKeys) {
             this.grpKeys = grpKeys;
 
             accumWrps = hasAccumulators() ? accFactory.get() : Collections.emptyList();
-
-            handler = context().rowHandler();
         }
 
         private void add(RowT row) {
@@ -261,6 +257,8 @@ public class SortAggregateNode<RowT> extends AbstractNode<RowT> implements Singl
         }
 
         private void addOnReducer(RowT row) {
+            RowHandler<RowT> handler = context().rowHandler();
+
             List<Accumulator> accums = hasAccumulators()
                     ? (List<Accumulator>) handler.get(handler.columnCount(row) - 1, row) : Collections.emptyList();
 
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/CreateIndexCommand.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/CreateIndexCommand.java
index 1e60c08..3cb6e0b 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/CreateIndexCommand.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/CreateIndexCommand.java
@@ -39,7 +39,7 @@ public class CreateIndexCommand implements DdlCommand {
     /** Quietly ignore this command if index already exists. */
     private boolean ifIdxNotExists;
 
-    /** Colunms covered with ordering. */
+    /** Columns covered with ordering. */
     List<Pair<String, Boolean>> cols;
 
     /** Return idx name. */
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteIndexScan.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteIndexScan.java
index e07d53d..26c41cf 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteIndexScan.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteIndexScan.java
@@ -31,7 +31,7 @@ import org.apache.ignite.internal.sql.engine.util.IndexConditions;
 import org.jetbrains.annotations.Nullable;
 
 /**
- * Relational operator that returns the contents of a table.
+ * Relational operator that returns the contents of a table using an index.
  */
 public class IgniteIndexScan extends AbstractIndexScan implements SourceAwareIgniteRel {
     private final long sourceId;
@@ -53,7 +53,7 @@ public class IgniteIndexScan extends AbstractIndexScan implements SourceAwareIgn
     }
 
     /**
-     * Creates a TableScan.
+     * Creates a IndexScan.
      *
      * @param cluster Cluster that this relational expression belongs to
      * @param traits  Traits of this relational expression
@@ -69,7 +69,7 @@ public class IgniteIndexScan extends AbstractIndexScan implements SourceAwareIgn
     }
 
     /**
-     * Creates a TableScan.
+     * Creates a IndexScan.
      *
      * @param cluster      Cluster that this relational expression belongs to
      * @param traits       Traits of this relational expression
@@ -93,7 +93,7 @@ public class IgniteIndexScan extends AbstractIndexScan implements SourceAwareIgn
     }
 
     /**
-     * Creates a TableScan.
+     * Creates a IndexScan.
      *
      * @param cluster      Cluster that this relational expression belongs to
      * @param traits       Traits of this relational expression
@@ -101,7 +101,7 @@ public class IgniteIndexScan extends AbstractIndexScan implements SourceAwareIgn
      * @param idxName      Index name.
      * @param proj         Projects.
      * @param cond         Filters.
-     * @param requiredCols Participating colunms.
+     * @param requiredCols Participating columns.
      */
     private IgniteIndexScan(
             long sourceId,
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 f683460..6b0074b 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
@@ -22,6 +22,7 @@ import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelInput;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
@@ -120,7 +121,12 @@ public class IgniteLimit extends SingleRel implements InternalIgniteRel {
             return null;
         }
 
-        if (!TraitUtils.collation(required).satisfies(TraitUtils.collation(traitSet))) {
+        RelCollation requiredCollation = TraitUtils.collation(required);
+        RelCollation relCollation = TraitUtils.collation(traitSet);
+
+        if (relCollation.satisfies(requiredCollation)) {
+            required = required.replace(relCollation);
+        } else if (!requiredCollation.satisfies(relCollation)) {
             return null;
         }
 
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableScan.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableScan.java
index 25aca95..50eced2 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableScan.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableScan.java
@@ -74,7 +74,7 @@ public class IgniteTableScan extends ProjectableFilterableTableScan implements S
      * @param tbl             Table definition.
      * @param proj            Projects.
      * @param cond            Filters.
-     * @param requiredColunms Participating colunms.
+     * @param requiredColumns Participating columns.
      */
     public IgniteTableScan(
             RelOptCluster cluster,
@@ -82,9 +82,9 @@ public class IgniteTableScan extends ProjectableFilterableTableScan implements S
             RelOptTable tbl,
             @Nullable List<RexNode> proj,
             @Nullable RexNode cond,
-            @Nullable ImmutableBitSet requiredColunms
+            @Nullable ImmutableBitSet requiredColumns
     ) {
-        this(-1L, cluster, traits, tbl, proj, cond, requiredColunms);
+        this(-1L, cluster, traits, tbl, proj, cond, requiredColumns);
     }
 
     /**
@@ -95,7 +95,7 @@ public class IgniteTableScan extends ProjectableFilterableTableScan implements S
      * @param tbl             Table definition.
      * @param proj            Projects.
      * @param cond            Filters.
-     * @param requiredColunms Participating colunms.
+     * @param requiredColumns Participating columns.
      */
     public IgniteTableScan(
             long sourceId,
@@ -104,9 +104,9 @@ public class IgniteTableScan extends ProjectableFilterableTableScan implements S
             RelOptTable tbl,
             @Nullable List<RexNode> proj,
             @Nullable RexNode cond,
-            @Nullable ImmutableBitSet requiredColunms
+            @Nullable ImmutableBitSet requiredColumns
     ) {
-        super(cluster, traits, List.of(), tbl, proj, cond, requiredColunms);
+        super(cluster, traits, List.of(), tbl, proj, cond, requiredColumns);
         this.sourceId = sourceId;
     }
 
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/agg/IgniteSortAggregateBase.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/agg/IgniteSortAggregateBase.java
index cc54ce4..772cf61 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/agg/IgniteSortAggregateBase.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/agg/IgniteSortAggregateBase.java
@@ -19,11 +19,14 @@ package org.apache.ignite.internal.sql.engine.rel.agg;
 
 import static org.apache.ignite.internal.sql.engine.util.Commons.maxPrefix;
 
+import com.google.common.collect.ImmutableList;
 import it.unimi.dsi.fastutil.ints.IntList;
 import java.util.List;
+import java.util.stream.Collectors;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Pair;
@@ -60,14 +63,17 @@ interface IgniteSortAggregateBase extends TraitsAwareIgniteRel {
     ) {
         RelCollation inputCollation = TraitUtils.collation(inputTraits.get(0));
 
-        IntList newCollation = maxPrefix(inputCollation.getKeys(), getGroupSet().asSet());
+        IntList newCollationColls = maxPrefix(inputCollation.getKeys(), getGroupSet().asSet());
 
-        if (newCollation.size() < getGroupSet().cardinality()) {
-            return List.of();
+        if (newCollationColls.size() < getGroupSet().cardinality()) {
+            return ImmutableList.of();
         }
 
-        return List.of(Pair.of(
-                nodeTraits.replace(RelCollations.of(ImmutableIntList.copyOf(newCollation))),
+        List<RelFieldCollation> suitableCollations = inputCollation.getFieldCollations()
+                .stream().filter(k -> newCollationColls.contains(k.getFieldIndex())).collect(Collectors.toList());
+
+        return ImmutableList.of(Pair.of(
+                nodeTraits.replace(RelCollations.of(suitableCollations)),
                 inputTraits
         ));
     }
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalTableScan.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalTableScan.java
index 4606ca6..aaaabbd 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalTableScan.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalTableScan.java
@@ -51,7 +51,7 @@ public class IgniteLogicalTableScan extends ProjectableFilterableTableScan {
      * @param tbl             Table definition.
      * @param proj            Projects.
      * @param cond            Filters.
-     * @param requiredColunms Participating colunms.
+     * @param requiredColumns Participating columns.
      */
     private IgniteLogicalTableScan(
             RelOptCluster cluster,
@@ -59,8 +59,8 @@ public class IgniteLogicalTableScan extends ProjectableFilterableTableScan {
             RelOptTable tbl,
             @Nullable List<RexNode> proj,
             @Nullable RexNode cond,
-            @Nullable ImmutableBitSet requiredColunms
+            @Nullable ImmutableBitSet requiredColumns
     ) {
-        super(cluster, traits, List.of(), tbl, proj, cond, requiredColunms);
+        super(cluster, traits, List.of(), tbl, proj, cond, requiredColumns);
     }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SortAggregatePlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SortAggregatePlannerTest.java
index d109275..db065e9 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SortAggregatePlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SortAggregatePlannerTest.java
@@ -26,8 +26,11 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.util.ImmutableIntList;
+import org.apache.ignite.internal.sql.engine.rel.IgniteCorrelatedNestedLoopJoin;
+import org.apache.ignite.internal.sql.engine.rel.IgniteLimit;
 import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
 import org.apache.ignite.internal.sql.engine.rel.IgniteSort;
 import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceSortAggregate;
@@ -70,6 +73,32 @@ public class SortAggregatePlannerTest extends AbstractAggregatePlannerTest {
         assertThat(ex.getMessage(), startsWith("There are not enough rules to produce a node with desired properties"));
     }
 
+    /** Checks if already sorted input exist and involved [Map|Reduce]SortAggregate. */
+    @Test
+    public void testNoSortAppendingWithCorrectCollation() throws Exception {
+        RelFieldCollation coll = new RelFieldCollation(1, RelFieldCollation.Direction.DESCENDING);
+
+        TestTable tbl = createAffinityTable().addIndex(RelCollations.of(coll), "val0Idx");
+
+        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
+
+        publicSchema.addTable("TEST", tbl);
+
+        String sql = "SELECT ID FROM test WHERE VAL0 IN (SELECT VAL0 FROM test)";
+
+        IgniteRel phys = physicalPlan(
+                sql,
+                publicSchema,
+                "HashSingleAggregateConverterRule", "HashMapReduceAggregateConverterRule",
+                "LogicalTableScanConverterRule"
+        );
+
+        assertNull(
+                findFirstNode(phys, byClass(IgniteSort.class)),
+                "Invalid plan\n" + RelOptUtil.toString(phys)
+        );
+    }
+
     /**
      * CollationPermuteSingle.
      * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859
@@ -165,4 +194,16 @@ public class SortAggregatePlannerTest extends AbstractAggregatePlannerTest {
                 "Invalid plan\n" + RelOptUtil.toString(phys)
         );
     }
+
+    @Test
+    public void testEmptyCollationPasshThroughLimit() throws Exception {
+        IgniteSchema publicSchema = createSchema(
+                createTable("TEST", IgniteDistributions.single(), "A", Integer.class));
+
+        assertPlan("SELECT (SELECT test.a FROM test t ORDER BY 1 LIMIT 1) FROM test", publicSchema,
+                hasChildThat(isInstanceOf(IgniteCorrelatedNestedLoopJoin.class)
+                        .and(input(1, hasChildThat(isInstanceOf(IgniteLimit.class)
+                                .and(input(isInstanceOf(IgniteSort.class)))))))
+        );
+    }
 }