You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by am...@apache.org on 2023/08/02 08:42:22 UTC

[ignite-3] branch main updated: IGNITE-18875 Sql. Drop AbstractPlannerTest.TestTable (#2372)

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 1507d0552c IGNITE-18875 Sql. Drop AbstractPlannerTest.TestTable (#2372)
1507d0552c is described below

commit 1507d0552c51f2ef57be484ffe2305d3abf88669
Author: Andrew V. Mashenkov <AM...@users.noreply.github.com>
AuthorDate: Wed Aug 2 11:42:15 2023 +0300

    IGNITE-18875 Sql. Drop AbstractPlannerTest.TestTable (#2372)
---
 .../exec/ExecutionDependencyResolverSelfTest.java  | 129 ++--
 .../sql/engine/exec/ExecutionServiceImplTest.java  |   1 -
 .../sql/engine/framework/TestBuilders.java         |  14 +-
 .../internal/sql/engine/framework/TestIndex.java   |   1 +
 .../sql/engine/framework/TestStatistic.java        |  78 +++
 .../internal/sql/engine/framework/TestTable.java   |  52 +-
 .../planner/AbstractAggregatePlannerTest.java      |  91 +--
 .../sql/engine/planner/AbstractPlannerTest.java    | 359 ++--------
 .../sql/engine/planner/AggregatePlannerTest.java   |  12 +-
 .../planner/ColocatedSortAggregatePlannerTest.java |  12 +-
 .../CorrelatedNestedLoopJoinPlannerTest.java       |  91 +--
 .../planner/CorrelatedSubqueryPlannerTest.java     |  35 +-
 .../sql/engine/planner/DmlPlannerTest.java         |   5 +-
 .../sql/engine/planner/HashIndexPlannerTest.java   |  97 +--
 .../engine/planner/HashIndexSpoolPlannerTest.java  | 121 +---
 .../sql/engine/planner/ImplicitCastsTest.java      |  54 +-
 .../planner/IndexSearchBoundsPlannerTest.java      | 118 ++--
 .../engine/planner/JoinColocationPlannerTest.java  | 107 ++-
 .../sql/engine/planner/JoinCommutePlannerTest.java |  36 +-
 .../engine/planner/JoinWithUsingPlannerTest.java   |  46 +-
 .../sql/engine/planner/LimitOffsetPlannerTest.java |  42 +-
 .../planner/MapReduceSortAggregatePlannerTest.java |  12 +-
 .../sql/engine/planner/MergeJoinPlannerTest.java   | 754 +++++++++-----------
 .../internal/sql/engine/planner/PlannerTest.java   | 757 ++++++---------------
 .../sql/engine/planner/PlannerTimeoutTest.java     |  54 +-
 .../planner/ProjectFilterScanMergePlannerTest.java |  42 +-
 .../sql/engine/planner/SetOpPlannerTest.java       |  51 +-
 .../planner/SortedIndexSpoolPlannerTest.java       | 100 ++-
 .../engine/planner/TableFunctionPlannerTest.java   |  33 +-
 .../sql/engine/planner/TableSpoolPlannerTest.java  |  39 +-
 .../sql/engine/planner/UnionPlannerTest.java       |  54 +-
 .../sql/engine/prepare/TypeCoercionTest.java       | 164 ++++-
 32 files changed, 1422 insertions(+), 2139 deletions(-)

diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ExecutionDependencyResolverSelfTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ExecutionDependencyResolverSelfTest.java
index e93cb0b8d3..5a05bb9225 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ExecutionDependencyResolverSelfTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ExecutionDependencyResolverSelfTest.java
@@ -32,16 +32,16 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionException;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.sql.type.SqlTypeName;
+import java.util.function.UnaryOperator;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
+import org.apache.ignite.internal.sql.engine.framework.TestTable;
 import org.apache.ignite.internal.sql.engine.metadata.ColocationGroup;
 import org.apache.ignite.internal.sql.engine.planner.AbstractPlannerTest;
 import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
-import org.apache.ignite.internal.sql.engine.schema.IgniteIndex;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
 import org.apache.ignite.internal.sql.engine.schema.IgniteTable;
 import org.apache.ignite.internal.sql.engine.schema.TableDescriptor;
@@ -49,6 +49,7 @@ import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
 import org.apache.ignite.internal.utils.PrimaryReplica;
 import org.apache.ignite.network.ClusterNode;
 import org.apache.ignite.network.NetworkAddress;
+import org.jetbrains.annotations.Nullable;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
@@ -81,16 +82,17 @@ public class ExecutionDependencyResolverSelfTest extends AbstractPlannerTest {
      */
     @Test
     public void testTableScan() {
-        Tester tester = new Tester();
+        TestTable testTable1 = createTestTable("TEST1");
+        TestTable testTable2 = createTestTable("TEST2");
 
-        RelDataType tableType = new RelDataTypeFactory.Builder(TYPE_FACTORY)
-                .add("ID", SqlTypeName.INTEGER)
-                .build();
+        int t1Id = testTable1.id();
+        int t2Id = testTable2.id();
+        TableDescriptor td1 = testTable1.descriptor();
+        TableDescriptor td2 = testTable2.descriptor();
 
-        int t1Id = tester.addTable("TEST1", tableType);
-        tester.setDependencies(t1Id, table1, update1);
+        Tester tester = new Tester(createSchema(testTable1, testTable2));
 
-        int t2Id = tester.addTable("TEST2", tableType);
+        tester.setDependencies(t1Id, table1, update1);
         tester.setDependencies(t2Id, table2, update2);
 
         CompletableFuture<ResolvedDependencies> f = tester.resolveDependencies("SELECT * FROM test1 JOIN test2 ON test1.id = test2.id");
@@ -99,9 +101,6 @@ public class ExecutionDependencyResolverSelfTest extends AbstractPlannerTest {
         tester.checkDependencies(deps, t1Id);
         tester.checkDependencies(deps, t2Id);
 
-        TableDescriptor td1 = tester.tableDescriptor("TEST1");
-        TableDescriptor td2 = tester.tableDescriptor("TEST2");
-
         verify(registry, times(1)).getTable(eq(t1Id), same(td1));
         verify(registry, times(1)).getTable(eq(t2Id), same(td2));
     }
@@ -111,21 +110,17 @@ public class ExecutionDependencyResolverSelfTest extends AbstractPlannerTest {
      */
     @Test
     public void testIndexScan() {
-        Tester tester = new Tester();
+        TestTable table = createTestTable("TEST1", addHashIndex("ID"));
 
-        RelDataType tableType = new RelDataTypeFactory.Builder(TYPE_FACTORY)
-                .add("ID", SqlTypeName.INTEGER)
-                .build();
+        int t1Id = table.id();
+        TableDescriptor td1 = table.descriptor();
 
-        int t1Id = tester.addTable("TEST1", tableType);
+        Tester tester = new Tester(createSchema(table));
         tester.setDependencies(t1Id, table1, update1);
-        tester.addIndex("TEST1", new IgniteIndex(TestHashIndex.create(List.of("ID"), "ID_IDX")));
 
         CompletableFuture<ResolvedDependencies> f = tester.resolveDependencies("SELECT * FROM test1 WHERE id=1");
         tester.checkDependencies(f.join(), t1Id);
 
-        TableDescriptor td1 = tester.tableDescriptor("TEST1");
-
         verify(registry, times(1)).getTable(eq(t1Id), same(td1));
     }
 
@@ -134,17 +129,17 @@ public class ExecutionDependencyResolverSelfTest extends AbstractPlannerTest {
      */
     @Test
     public void testModify() {
-        RelDataType tableType = new RelDataTypeFactory.Builder(TYPE_FACTORY)
-                .add("ID", SqlTypeName.INTEGER)
-                .add("VAL", SqlTypeName.INTEGER)
-                .build();
+        TestTable testTable1 = createTestTable("TEST1");
+        TestTable testTable2 = createTestTable("TEST2");
 
-        Tester tester = new Tester();
+        int t1Id = testTable1.id();
+        int t2Id = testTable2.id();
+        TableDescriptor td1 = testTable1.descriptor();
+        TableDescriptor td2 = testTable2.descriptor();
 
-        int t1Id = tester.addTable("TEST1", tableType);
-        tester.setDependencies(t1Id, table1, update1);
+        Tester tester = new Tester(createSchema(testTable1, testTable2));
 
-        int t2Id = tester.addTable("TEST2", tableType);
+        tester.setDependencies(t1Id, table1, update1);
         tester.setDependencies(t2Id, table2, update2);
 
         CompletableFuture<ResolvedDependencies> f = tester.resolveDependencies(
@@ -154,9 +149,6 @@ public class ExecutionDependencyResolverSelfTest extends AbstractPlannerTest {
         tester.checkDependencies(deps, t1Id);
         tester.checkDependencies(deps, t2Id);
 
-        TableDescriptor td1 = tester.tableDescriptor("TEST1");
-        TableDescriptor td2 = tester.tableDescriptor("TEST2");
-
         verify(registry, times(1)).getTable(eq(t1Id), same(td1));
         verify(registry, times(1)).getTable(eq(t2Id), same(td2));
     }
@@ -166,14 +158,12 @@ public class ExecutionDependencyResolverSelfTest extends AbstractPlannerTest {
      */
     @Test
     public void testCached() {
-        Tester tester = new Tester();
+        TestTable table = createTestTable("TEST1");
+
+        int t1Id = table.id();
 
-        RelDataType tableType = new RelDataTypeFactory.Builder(TYPE_FACTORY)
-                .add("ID", SqlTypeName.INTEGER)
-                .build();
+        Tester tester = new Tester(createSchema(table));
 
-        String tableName = "TEST1";
-        int t1Id = tester.addTable(tableName, tableType);
         tester.setDependencies(t1Id, table1, update1);
 
         CompletableFuture<ResolvedDependencies> f = tester.resolveDependencies("SELECT (SELECT id FROM test1) FROM test1");
@@ -189,13 +179,11 @@ public class ExecutionDependencyResolverSelfTest extends AbstractPlannerTest {
      */
     @Test
     public void testResolutionErrorIsReturned() {
-        Tester tester = new Tester();
+        TestTable table = createTestTable("TEST1");
 
-        RelDataType tableType = new RelDataTypeFactory.Builder(TYPE_FACTORY)
-                .add("ID", SqlTypeName.INTEGER)
-                .build();
+        int t1Id = table.id();
 
-        int t1Id = tester.addTable("TEST1", tableType);
+        Tester tester = new Tester(createSchema(table));
 
         RuntimeException err = new RuntimeException("Broken");
         tester.setError(t1Id, err);
@@ -208,13 +196,12 @@ public class ExecutionDependencyResolverSelfTest extends AbstractPlannerTest {
     /** Fetch colocation group succeeds. */
     @Test
     public void testFetchColocationGroup() {
-        Tester tester = new Tester();
+        TestTable table = createTestTable("TEST1");
+
+        int t1Id = table.id();
 
-        RelDataType tableType = new RelDataTypeFactory.Builder(TYPE_FACTORY)
-                .add("ID", SqlTypeName.INTEGER)
-                .build();
+        Tester tester = new Tester(createSchema(table));
 
-        int t1Id = tester.addTable("TEST1", tableType);
         ColocationGroup g1 = ColocationGroup.forNodes(List.of("n1"));
 
         tester.setColocationGroup(t1Id, CompletableFuture.completedFuture(g1));
@@ -229,13 +216,11 @@ public class ExecutionDependencyResolverSelfTest extends AbstractPlannerTest {
     /** Fetch colocation group propagates an error. */
     @Test
     public void testFetchColocationGroupErrorIsReturned() {
-        Tester tester = new Tester();
+        TestTable table = createTestTable("TEST1");
 
-        RelDataType tableType = new RelDataTypeFactory.Builder(TYPE_FACTORY)
-                .add("ID", SqlTypeName.INTEGER)
-                .build();
+        int t1Id = table.id();
 
-        int t1Id = tester.addTable("TEST1", tableType);
+        Tester tester = new Tester(createSchema(table));
 
         ClusterNode node1 = new ClusterNode("1", "node1", new NetworkAddress("host", 1234));
 
@@ -254,23 +239,14 @@ public class ExecutionDependencyResolverSelfTest extends AbstractPlannerTest {
 
     private class Tester {
 
-        final IgniteSchema igniteSchema = new IgniteSchema("PUBLIC");
+        final IgniteSchema igniteSchema;
 
         final Map<Integer, TestExecutableTable> deps = new HashMap<>();
 
         final Map<Integer, CompletableFuture<ColocationGroup>> colocationGroups = new HashMap<>();
 
-        int addTable(String name, RelDataType rowType) {
-            IgniteTable table = createTable(igniteSchema, name, rowType, IgniteDistributions.single());
-            igniteSchema.addTable(table);
-
-            return table.id();
-        }
-
-        void addIndex(String tableName, IgniteIndex index) {
-            IgniteTable table = (IgniteTable) igniteSchema.getTable(tableName);
-            Objects.requireNonNull(table, "No table");
-            table.addIndex(index);
+        Tester(IgniteSchema schema) {
+            igniteSchema = schema;
         }
 
         void setDependencies(int tableId, ScannableTable table, UpdatableTable updates) {
@@ -321,6 +297,7 @@ public class ExecutionDependencyResolverSelfTest extends AbstractPlannerTest {
             IgniteTable table = (IgniteTable) igniteSchema.getTable(tableName);
             return table.descriptor();
         }
+
     }
 
     private static final class TestExecutableTable implements ExecutableTable {
@@ -352,4 +329,22 @@ public class ExecutionDependencyResolverSelfTest extends AbstractPlannerTest {
             return colocationGroup;
         }
     }
+
+    private static TestTable createTestTable(String tableName) {
+        return createTestTable(tableName, null);
+    }
+
+    private static TestTable createTestTable(String tableName, @Nullable UnaryOperator<TableBuilder> changer) {
+        TableBuilder testTable = TestBuilders.table()
+                .name(tableName)
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("VAL", NativeTypes.STRING)
+                .distribution(IgniteDistributions.single());
+
+        if (changer != null) {
+            changer.apply(testTable);
+        }
+
+        return testTable.build();
+    }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImplTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImplTest.java
index e57170b284..e94dac023d 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImplTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImplTest.java
@@ -879,7 +879,6 @@ public class ExecutionServiceImplTest {
         return new TestTable(
                 new TableDescriptorImpl(columns, distr),
                 name,
-                ColocationGroup.forNodes(nodeNames),
                 size
         ) {
 
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestBuilders.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestBuilders.java
index db75948eac..2d0e283046 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestBuilders.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestBuilders.java
@@ -433,7 +433,6 @@ public class TestBuilders {
             TestTable testTable = new TestTable(
                     new TableDescriptorImpl(columns, distribution),
                     Objects.requireNonNull(name),
-                    Map.of(),
                     size
             );
 
@@ -524,7 +523,7 @@ public class TestBuilders {
                 throw new IllegalArgumentException("Index must contain at least one column");
             }
 
-            if (collations.size() == columns.size()) {
+            if (collations.size() != columns.size()) {
                 throw new IllegalArgumentException("Collation must be specified for each of columns.");
             }
 
@@ -673,8 +672,14 @@ public class TestBuilders {
         /** {@inheritDoc} */
         @Override
         public ChildT addColumn(String name, NativeType type) {
+            return addColumn(name, type, true);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public ChildT addColumn(String name, NativeType type, boolean nullable) {
             columns.add(new ColumnDescriptorImpl(
-                    name, false, true, columns.size(), columns.size(), type, DefaultValueStrategy.DEFAULT_NULL, null
+                    name, false, nullable, columns.size(), columns.size(), type, DefaultValueStrategy.DEFAULT_NULL, null
             ));
 
             return self();
@@ -778,6 +783,9 @@ public class TestBuilders {
         /** Adds a column to the table. */
         ChildT addColumn(String name, NativeType type);
 
+        /** Adds a column with given nullability to the table. */
+        ChildT addColumn(String name, NativeType type, boolean nullable);
+
         /** Adds a column with the given default value to the table. */
         ChildT addColumn(String name, NativeType type, @Nullable Object defaultValue);
 
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestIndex.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestIndex.java
index f9da45677b..dd8449e6bb 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestIndex.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestIndex.java
@@ -66,6 +66,7 @@ public class TestIndex extends IgniteIndex {
     }
 
     /** Returns an id of the index. */
+    @Override
     public int id() {
         return id;
     }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestStatistic.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestStatistic.java
new file mode 100644
index 0000000000..4518786c21
--- /dev/null
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestStatistic.java
@@ -0,0 +1,78 @@
+/*
+ * 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.sql.engine.framework;
+
+import java.util.Collections;
+import java.util.List;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelDistribution;
+import org.apache.calcite.rel.RelReferentialConstraint;
+import org.apache.calcite.schema.Statistic;
+import org.apache.calcite.util.ImmutableBitSet;
+
+/**
+ * A test statistic that implements all the necessary for the optimizer methods to be used to prepare a query.
+ */
+public class TestStatistic implements Statistic {
+    private final double rowCnt;
+
+    /**
+     * Constructor.
+     *
+     * @param rowCnt Table row count.
+     */
+    public TestStatistic(double rowCnt) {
+        this.rowCnt = rowCnt;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Double getRowCount() {
+        return rowCnt;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isKey(ImmutableBitSet cols) {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public List<ImmutableBitSet> getKeys() {
+        throw new AssertionError();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public List<RelReferentialConstraint> getReferentialConstraints() {
+        throw new AssertionError();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public List<RelCollation> getCollations() {
+        return Collections.emptyList();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public RelDistribution getDistribution() {
+        throw new AssertionError();
+    }
+}
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestTable.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestTable.java
index ec46c53ae6..db7c1ff202 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestTable.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestTable.java
@@ -27,9 +27,6 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.calcite.config.CalciteConnectionConfig;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptTable;
-import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelDistribution;
-import org.apache.calcite.rel.RelReferentialConstraint;
 import org.apache.calcite.rel.hint.RelHint;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -39,7 +36,6 @@ import org.apache.calcite.schema.Statistic;
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.util.ImmutableBitSet;
-import org.apache.ignite.internal.sql.engine.metadata.ColocationGroup;
 import org.apache.ignite.internal.sql.engine.rel.logical.IgniteLogicalIndexScan;
 import org.apache.ignite.internal.sql.engine.rel.logical.IgniteLogicalTableScan;
 import org.apache.ignite.internal.sql.engine.schema.IgniteIndex;
@@ -50,9 +46,8 @@ import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
 import org.jetbrains.annotations.Nullable;
 
 /**
- * A test table that implements all the necessary for the optimizer methods to be used
- * to prepare a query, as well as provides access to the data to use this table in
- * execution-related scenarios.
+ * A test table that implements all the necessary for the optimizer methods to be used to prepare a query, as well as provides access to the
+ * data to use this table in execution-related scenarios.
  */
 public class TestTable implements IgniteTable {
     private static final String DATA_PROVIDER_NOT_CONFIGURED_MESSAGE_TEMPLATE =
@@ -65,7 +60,6 @@ public class TestTable implements IgniteTable {
 
     private final String name;
     private final double rowCnt;
-    private final ColocationGroup colocationGroup;
     private final TableDescriptor descriptor;
     private final Map<String, DataProvider<?>> dataProviders;
 
@@ -74,13 +68,11 @@ public class TestTable implements IgniteTable {
     public TestTable(
             TableDescriptor descriptor,
             String name,
-            ColocationGroup colocationGroup,
             double rowCnt
     ) {
         this.descriptor = descriptor;
         this.name = name;
         this.rowCnt = rowCnt;
-        this.colocationGroup = colocationGroup;
 
         dataProviders = Collections.emptyMap();
     }
@@ -96,8 +88,6 @@ public class TestTable implements IgniteTable {
         this.name = name;
         this.rowCnt = rowCnt;
         this.dataProviders = dataProviders;
-
-        this.colocationGroup = ColocationGroup.forNodes(List.copyOf(dataProviders.keySet()));
     }
 
     /**
@@ -163,43 +153,7 @@ public class TestTable implements IgniteTable {
     /** {@inheritDoc} */
     @Override
     public Statistic getStatistic() {
-        return new Statistic() {
-            /** {@inheritDoc} */
-            @Override
-            public Double getRowCount() {
-                return rowCnt;
-            }
-
-            /** {@inheritDoc} */
-            @Override
-            public boolean isKey(ImmutableBitSet cols) {
-                return false;
-            }
-
-            /** {@inheritDoc} */
-            @Override
-            public List<ImmutableBitSet> getKeys() {
-                throw new AssertionError();
-            }
-
-            /** {@inheritDoc} */
-            @Override
-            public List<RelReferentialConstraint> getReferentialConstraints() {
-                throw new AssertionError();
-            }
-
-            /** {@inheritDoc} */
-            @Override
-            public List<RelCollation> getCollations() {
-                return Collections.emptyList();
-            }
-
-            /** {@inheritDoc} */
-            @Override
-            public RelDistribution getDistribution() {
-                throw new AssertionError();
-            }
-        };
+        return new TestStatistic(rowCnt);
     }
 
     /** {@inheritDoc} */
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractAggregatePlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractAggregatePlannerTest.java
index fbff6b9e03..98d098e329 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractAggregatePlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractAggregatePlannerTest.java
@@ -25,23 +25,18 @@ import java.util.Collections;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Objects;
-import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.function.Predicate;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollations;
-import org.apache.calcite.rel.RelFieldCollation;
+import java.util.function.UnaryOperator;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.ignite.internal.schema.NativeTypes;
-import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 import org.apache.ignite.internal.sql.engine.rel.IgniteAggregate;
 import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceAggregateBase;
-import org.apache.ignite.internal.sql.engine.schema.IgniteIndex;
+import org.apache.ignite.internal.sql.engine.schema.IgniteIndex.Collation;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
-import org.apache.ignite.internal.sql.engine.trait.TraitUtils;
 import org.hamcrest.Matchers;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
@@ -253,7 +248,7 @@ public abstract class AbstractAggregatePlannerTest extends AbstractPlannerTest {
          *
          * <p>Distribution single
          */
-        CASE_9("SELECT AVG(val0) FROM test GROUP BY grp0", schema(single(), index("grp0_grp1", 3, 4))),
+        CASE_9("SELECT AVG(val0) FROM test GROUP BY grp0", schema(single(), addSortIndex("grp0", "grp1"))),
         /**
          * Query: SELECT AVG(val0) FROM test GROUP BY grp0.
          *
@@ -261,31 +256,31 @@ public abstract class AbstractAggregatePlannerTest extends AbstractPlannerTest {
          *
          * <p>Distribution hash(0)
          */
-        CASE_9A("SELECT AVG(val0) FROM test GROUP BY grp0", schema(hash(), index("grp0_grp1", 3, 4))),
+        CASE_9A("SELECT AVG(val0) FROM test GROUP BY grp0", schema(hash(), addSortIndex("grp0", "grp1"))),
         /**
          * Query: SELECT AVG(val0) FROM test GROUP BY grp0, grp1.
          *
          * <p>Distribution single
          */
-        CASE_10("SELECT AVG(val0) FROM test GROUP BY grp0, grp1", schema(single(), index("grp0_grp1", 3, 4))),
+        CASE_10("SELECT AVG(val0) FROM test GROUP BY grp0, grp1", schema(single(), addSortIndex("grp0", "grp1"))),
         /**
          * Query: SELECT AVG(val0) FROM test GROUP BY grp0, grp1.
          *
          * <p>Distribution hash(0)
          */
-        CASE_10A("SELECT AVG(val0) FROM test GROUP BY grp0, grp1", schema(hash(), index("grp0_grp1", 3, 4))),
+        CASE_10A("SELECT AVG(val0) FROM test GROUP BY grp0, grp1", schema(hash(), addSortIndex("grp0", "grp1"))),
         /**
          * Query: SELECT AVG(val0) FROM test GROUP BY grp1, grp0.
          *
          * <p>Distribution single
          */
-        CASE_11("SELECT AVG(val0) FROM test GROUP BY grp1, grp0", schema(single(), index("grp0_grp1", 3, 4))),
+        CASE_11("SELECT AVG(val0) FROM test GROUP BY grp1, grp0", schema(single(), addSortIndex("grp0", "grp1"))),
         /**
          * Query: SELECT AVG(val0) FROM test GROUP BY grp1, grp0.
          *
          * <p>Distribution hash(0)
          */
-        CASE_11A("SELECT AVG(val0) FROM test GROUP BY grp1, grp0", schema(hash(), index("grp0_grp1", 3, 4))),
+        CASE_11A("SELECT AVG(val0) FROM test GROUP BY grp1, grp0", schema(hash(), addSortIndex("grp0", "grp1"))),
         /**
          * Query: SELECT DISTINCT val0, val1 FROM test.
          *
@@ -293,7 +288,7 @@ public abstract class AbstractAggregatePlannerTest extends AbstractPlannerTest {
          *
          * <p>Distribution single
          */
-        CASE_12("SELECT DISTINCT val0, val1 FROM test", schema(single(), index("val0", 1))),
+        CASE_12("SELECT DISTINCT val0, val1 FROM test", schema(single(), addSortIndex("val0"))),
         /**
          * Query: SELECT DISTINCT val0, val1 FROM test.
          *
@@ -301,7 +296,7 @@ public abstract class AbstractAggregatePlannerTest extends AbstractPlannerTest {
          *
          * <p>Distribution hash(0)
          */
-        CASE_12A("SELECT DISTINCT val0, val1 FROM test", schema(hash(), index("val0", 1))),
+        CASE_12A("SELECT DISTINCT val0, val1 FROM test", schema(hash(), addSortIndex("val0"))),
         /**
          * Query: SELECT DISTINCT grp0, grp1 FROM test.
          *
@@ -309,7 +304,7 @@ public abstract class AbstractAggregatePlannerTest extends AbstractPlannerTest {
          *
          * <p>Distribution single
          */
-        CASE_13("SELECT DISTINCT grp0, grp1 FROM test", schema(single(), index("grp0_grp1", 3, 4))),
+        CASE_13("SELECT DISTINCT grp0, grp1 FROM test", schema(single(), addSortIndex("grp0", "grp1"))),
         /**
          * Query: SELECT DISTINCT grp0, grp1 FROM test.
          *
@@ -317,7 +312,7 @@ public abstract class AbstractAggregatePlannerTest extends AbstractPlannerTest {
          *
          * <p>Distribution hash(0)
          */
-        CASE_13A("SELECT DISTINCT grp0, grp1 FROM test", schema(hash(), index("grp0_grp1", 3, 4))),
+        CASE_13A("SELECT DISTINCT grp0, grp1 FROM test", schema(hash(), addSortIndex("grp0", "grp1"))),
         /**
          * Query: SELECT val0 FROM test WHERE VAL1 = (SELECT AVG(val1) FROM test).
          *
@@ -451,7 +446,7 @@ public abstract class AbstractAggregatePlannerTest extends AbstractPlannerTest {
          * <p>Distribution single
          */
         CASE_21("SELECT /*+ EXPAND_DISTINCT_AGG */ SUM(DISTINCT val0), AVG(DISTINCT val1) FROM test GROUP BY grp0",
-                schema(single(), index("idx_val0", 3, 1), index("idx_val1", 3, 2))),
+                schema(single(), addSortIndex("grp0", "val0"), addSortIndex("grp0", "val1"))),
         /**
          * Query: SELECT /*+ EXPAND_DISTINCT_AGG *&#47; SUM(DISTINCT val0), AVG(DISTINCT val1) FROM test GROUP BY grp0.
          *
@@ -460,7 +455,7 @@ public abstract class AbstractAggregatePlannerTest extends AbstractPlannerTest {
          * <p>Distribution hash(0)
          */
         CASE_21A("SELECT /*+ EXPAND_DISTINCT_AGG */ SUM(DISTINCT val0), AVG(DISTINCT val1) FROM test GROUP BY grp0",
-                schema(hash(), index("idx_val0", 3, 1), index("idx_val1", 3, 2))),
+                schema(hash(), addSortIndex("grp0", "val0"), addSortIndex("grp0", "val1"))),
 
         ;
 
@@ -516,47 +511,38 @@ public abstract class AbstractAggregatePlannerTest extends AbstractPlannerTest {
 
     @SafeVarargs
     private static IgniteSchema schema(IgniteDistribution distribution,
-            Consumer<org.apache.ignite.internal.sql.engine.framework.TestTable>... indices) {
-        org.apache.ignite.internal.sql.engine.framework.TestTable table = TestBuilders.table()
-                .name("TEST")
+            UnaryOperator<TableBuilder>... indices) {
+
+        Function<TableBuilder, TableBuilder> testTable = defaultTestTable(distribution);
+
+        for (UnaryOperator<TableBuilder> index : indices) {
+            testTable = testTable.andThen(index);
+        }
+
+        return createSchemaFrom(testTable);
+    }
+
+    private static UnaryOperator<TableBuilder> defaultTestTable(IgniteDistribution distribution) {
+        return t -> t.name("TEST")
                 .addColumn("ID", NativeTypes.INT32)
                 .addColumn("VAL0", NativeTypes.INT32)
                 .addColumn("VAL1", NativeTypes.INT32)
                 .addColumn("GRP0", NativeTypes.INT32)
                 .addColumn("GRP1", NativeTypes.INT32)
                 .size(DEFAULT_TBL_SIZE)
-                .distribution(distribution)
-                .build();
-
-        for (Consumer<org.apache.ignite.internal.sql.engine.framework.TestTable> index : indices) {
-            index.accept(table);
-        }
-
-        IgniteSchema schema = new IgniteSchema("PUBLIC");
-        schema.addTable(table);
-
-        return schema;
+                .distribution(distribution);
     }
 
     private static IgniteDistribution hash() {
         return someAffinity();
     }
 
-    private static Consumer<org.apache.ignite.internal.sql.engine.framework.TestTable> index(String name, int... cols) {
-        RelCollation collation = TraitUtils.createCollation(IntStream.of(cols).boxed().collect(Collectors.toList()));
-
-        return tbl -> tbl.addIndex(createIndex(tbl, name, collation));
-    }
-
-    private static Consumer<org.apache.ignite.internal.sql.engine.framework.TestTable> indexByVal0Desc() {
-        RelFieldCollation coll = new RelFieldCollation(1, RelFieldCollation.Direction.DESCENDING);
-
-        return tbl -> tbl.addIndex(createIndex(tbl, "val0", RelCollations.of(coll)));
-    }
-
-    private static IgniteIndex createIndex(org.apache.ignite.internal.sql.engine.framework.TestTable tbl, String name,
-            RelCollation collation) {
-        return new IgniteIndex(TestSortedIndex.create(collation, name, tbl));
+    private static UnaryOperator<TableBuilder> indexByVal0Desc() {
+        return tableBuilder -> tableBuilder
+                .sortedIndex()
+                .name("idx_val0")
+                .addColumn("VAL0", Collation.DESC_NULLS_FIRST)
+                .end();
     }
 
     <T extends RelNode> Predicate<T> hasAggregate() {
@@ -583,9 +569,4 @@ public abstract class AbstractAggregatePlannerTest extends AbstractPlannerTest {
 
         return aggregateNode.or(reduceNode);
     }
-
-    /** Returns predicate returning {@code true} for any input. */
-    static <T> Predicate<T> alwaysTrue() {
-        return anything -> true;
-    }
 }
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 c8da086c5f..a8c6aee0b9 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
@@ -35,10 +35,8 @@ import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
@@ -46,11 +44,11 @@ import java.util.concurrent.Flow.Publisher;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
+import java.util.function.UnaryOperator;
 import java.util.stream.Collectors;
-import org.apache.calcite.config.CalciteConnectionConfig;
-import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptListener;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptTable;
@@ -61,23 +59,15 @@ import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelDistribution;
 import org.apache.calcite.rel.RelFieldCollation.NullDirection;
 import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.RelReferentialConstraint;
 import org.apache.calcite.rel.RelVisitor;
 import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.hint.HintStrategyTable;
-import org.apache.calcite.rel.hint.RelHint;
 import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeField;
-import org.apache.calcite.rel.type.RelDataTypeImpl;
-import org.apache.calcite.rel.type.RelProtoDataType;
 import org.apache.calcite.rex.RexCall;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.schema.ColumnStrategy;
-import org.apache.calcite.schema.Schema;
 import org.apache.calcite.schema.SchemaPlus;
-import org.apache.calcite.schema.Statistic;
-import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlExplainLevel;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlNode;
@@ -97,6 +87,10 @@ import org.apache.ignite.internal.schema.BinaryTuple;
 import org.apache.ignite.internal.schema.BinaryTuplePrefix;
 import org.apache.ignite.internal.schema.NativeType;
 import org.apache.ignite.internal.sql.engine.externalize.RelJsonReader;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.HashIndexBuilder;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.SortedIndexBuilder;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 import org.apache.ignite.internal.sql.engine.prepare.Cloner;
 import org.apache.ignite.internal.sql.engine.prepare.Fragment;
 import org.apache.ignite.internal.sql.engine.prepare.IgnitePlanner;
@@ -107,24 +101,20 @@ import org.apache.ignite.internal.sql.engine.prepare.bounds.SearchBounds;
 import org.apache.ignite.internal.sql.engine.rel.IgniteIndexScan;
 import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
 import org.apache.ignite.internal.sql.engine.rel.IgniteTableScan;
-import org.apache.ignite.internal.sql.engine.rel.logical.IgniteLogicalIndexScan;
-import org.apache.ignite.internal.sql.engine.rel.logical.IgniteLogicalTableScan;
 import org.apache.ignite.internal.sql.engine.schema.ColumnDescriptor;
 import org.apache.ignite.internal.sql.engine.schema.DefaultValueStrategy;
-import org.apache.ignite.internal.sql.engine.schema.IgniteIndex;
+import org.apache.ignite.internal.sql.engine.schema.IgniteIndex.Collation;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
 import org.apache.ignite.internal.sql.engine.schema.IgniteTable;
 import org.apache.ignite.internal.sql.engine.schema.TableDescriptor;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
-import org.apache.ignite.internal.sql.engine.trait.TraitUtils;
 import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
 import org.apache.ignite.internal.sql.engine.util.BaseQueryContext;
 import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.apache.ignite.internal.sql.engine.util.StatementChecker;
 import org.apache.ignite.internal.testframework.IgniteAbstractTest;
 import org.apache.ignite.internal.testframework.IgniteTestUtils;
-import org.apache.ignite.internal.util.ArrayUtils;
 import org.apache.ignite.internal.utils.PrimaryReplica;
 import org.apache.ignite.network.ClusterNode;
 import org.jetbrains.annotations.Nullable;
@@ -439,81 +429,6 @@ public abstract class AbstractPlannerTest extends IgniteAbstractTest {
         };
     }
 
-    protected static TestTable createTable(IgniteSchema schema, String name, RelDataType type, IgniteDistribution distr) {
-        TestTable table = createTable(name, type, DEFAULT_TBL_SIZE, distr);
-
-        schema.addTable(table);
-
-        return table;
-    }
-
-    /**
-     * Creates test table with given params and schema.
-     *
-     * @param schema Table schema.
-     * @param name   Name of the table.
-     * @param distr  Distribution of the table.
-     * @param fields List of the required fields. Every odd item should be a string representing a column name, every
-     *               even item should be a class representing column's type.
-     *               E.g. {@code createTable("MY_TABLE", distribution, "ID", Integer.class, "VAL", String.class)}.
-     * @return Instance of the {@link TestTable}.
-     */
-    protected static TestTable createTable(IgniteSchema schema, String name, IgniteDistribution distr, Object... fields) {
-        TestTable tbl = createTable(name, DEFAULT_TBL_SIZE, distr, fields);
-
-        schema.addTable(tbl);
-
-        return tbl;
-    }
-
-    /**
-     * Creates test table with given params.
-     *
-     * @param name   Name of the table.
-     * @param distr  Distribution of the table.
-     * @param fields List of the required fields. Every odd item should be a string representing a column name, every
-     *               even item should be a class representing column's type.
-     *               E.g. {@code createTable("MY_TABLE", distribution, "ID", Integer.class, "VAL", String.class)}.
-     * @return Instance of the {@link TestTable}.
-     */
-    protected static TestTable createTable(String name, IgniteDistribution distr, Object... fields) {
-        return createTable(name, DEFAULT_TBL_SIZE, distr, fields);
-    }
-
-    /**
-     * Creates test table with given params.
-     *
-     * @param name   Name of the table.
-     * @param size   Required size of the table.
-     * @param distr  Distribution of the table.
-     * @param fields List of the required fields. Every odd item should be a string representing a column name, every
-     *               even item should be a class representing column's type.
-     *               E.g. {@code createTable("MY_TABLE", 500, distribution, "ID", Integer.class, "VAL", String.class)}.
-     * @return Instance of the {@link TestTable}.
-     */
-    protected static TestTable createTable(String name, int size, IgniteDistribution distr, Object... fields) {
-        if (ArrayUtils.nullOrEmpty(fields) || fields.length % 2 != 0) {
-            throw new IllegalArgumentException("'fields' should be non-null array with even number of elements");
-        }
-
-        RelDataTypeFactory.Builder b = new RelDataTypeFactory.Builder(TYPE_FACTORY);
-
-        for (int i = 0; i < fields.length; i += 2) {
-            b.add((String) fields[i], TYPE_FACTORY.createJavaType((Class<?>) fields[i + 1]));
-        }
-
-        return createTable(name, b.build(), size, distr);
-    }
-
-    protected static TestTable createTable(String name, RelDataType type, int size, IgniteDistribution distr) {
-        return new TestTable(name, type, size) {
-            @Override
-            public IgniteDistribution distribution() {
-                return distr;
-            }
-        };
-    }
-
     protected <T extends RelNode> void assertPlan(
             String sql,
             IgniteSchema schema,
@@ -808,226 +723,6 @@ public abstract class AbstractPlannerTest extends IgniteAbstractTest {
         rel.getInputs().forEach(this::clearHints);
     }
 
-    /** Test table. */
-    public abstract static class TestTable implements IgniteTable {
-        private final String name;
-
-        private final RelProtoDataType protoType;
-
-        private final Map<String, IgniteIndex> indexes = new HashMap<>();
-
-        private final double rowCnt;
-
-        private final TableDescriptor desc;
-
-        private final int id = nextTableId();
-
-        /** Constructor. */
-        public TestTable(RelDataType type) {
-            this(type, 100.0);
-        }
-
-        /** Constructor. */
-        public TestTable(RelDataType type, String name) {
-            this(name, type, 100.0);
-        }
-
-        /** Constructor. */
-        public TestTable(RelDataType type, double rowCnt) {
-            this(UUID.randomUUID().toString(), type, rowCnt);
-        }
-
-        /** Constructor. */
-        public TestTable(String name, RelDataType type, double rowCnt) {
-            protoType = RelDataTypeImpl.proto(type);
-            this.rowCnt = rowCnt;
-            this.name = name;
-
-            desc = new TestTableDescriptor(this::distribution, type);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public int id() {
-            return id;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public int version() {
-            return 0;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public IgniteLogicalTableScan toRel(
-                RelOptCluster cluster,
-                RelOptTable relOptTbl,
-                List<RelHint> hints,
-                @Nullable List<RexNode> proj,
-                @Nullable RexNode cond,
-                @Nullable ImmutableBitSet requiredColumns
-        ) {
-            return IgniteLogicalTableScan.create(cluster, cluster.traitSet(), hints, relOptTbl, proj, cond, requiredColumns);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public IgniteLogicalIndexScan toRel(
-                RelOptCluster cluster,
-                RelOptTable relOptTbl,
-                String idxName,
-                @Nullable List<RexNode> proj,
-                @Nullable RexNode cond,
-                @Nullable ImmutableBitSet requiredColumns
-        ) {
-            return IgniteLogicalIndexScan.create(cluster, cluster.traitSet(), relOptTbl, idxName, proj, cond, requiredColumns);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public RelDataType getRowType(RelDataTypeFactory typeFactory, ImmutableBitSet bitSet) {
-            RelDataType rowType = protoType.apply(typeFactory);
-
-            if (bitSet != null) {
-                RelDataTypeFactory.Builder b = new RelDataTypeFactory.Builder(typeFactory);
-                for (int i = bitSet.nextSetBit(0); i != -1; i = bitSet.nextSetBit(i + 1)) {
-                    b.add(rowType.getFieldList().get(i));
-                }
-                rowType = b.build();
-            }
-
-            return rowType;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Statistic getStatistic() {
-            return new Statistic() {
-                /** {@inheritDoc} */
-                @Override
-                public Double getRowCount() {
-                    return rowCnt;
-                }
-
-                /** {@inheritDoc} */
-                @Override
-                public boolean isKey(ImmutableBitSet cols) {
-                    return false;
-                }
-
-                /** {@inheritDoc} */
-                @Override
-                public List<ImmutableBitSet> getKeys() {
-                    throw new AssertionError();
-                }
-
-                /** {@inheritDoc} */
-                @Override
-                public List<RelReferentialConstraint> getReferentialConstraints() {
-                    throw new AssertionError();
-                }
-
-                /** {@inheritDoc} */
-                @Override
-                public List<RelCollation> getCollations() {
-                    return Collections.emptyList();
-                }
-
-                /** {@inheritDoc} */
-                @Override
-                public RelDistribution getDistribution() {
-                    throw new AssertionError();
-                }
-            };
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Schema.TableType getJdbcTableType() {
-            throw new AssertionError();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public boolean isRolledUp(String col) {
-            return false;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public boolean rolledUpColumnValidInsideAgg(
-                String column,
-                SqlCall call,
-                SqlNode parent,
-                CalciteConnectionConfig config
-        ) {
-            throw new AssertionError();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public IgniteDistribution distribution() {
-            throw new AssertionError();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public TableDescriptor descriptor() {
-            return desc;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Map<String, IgniteIndex> indexes() {
-            return Collections.unmodifiableMap(indexes);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void addIndex(IgniteIndex idxTbl) {
-            indexes.put(idxTbl.name(), idxTbl);
-        }
-
-        /**
-         * AddIndex.
-         * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859
-         */
-        public TestTable addIndex(RelCollation collation, String name) {
-            indexes.put(name, new IgniteIndex(TestSortedIndex.create(collation, name, this)));
-
-            return this;
-        }
-
-        /**
-         * AddIndex.
-         * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859
-         */
-        public TestTable addIndex(String name, int... keys) {
-            addIndex(TraitUtils.createCollation(Arrays.stream(keys).boxed().collect(Collectors.toList())), name);
-
-            return this;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public IgniteIndex getIndex(String idxName) {
-            return indexes.get(idxName);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void removeIndex(String idxName) {
-            throw new AssertionError();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public String name() {
-            return name;
-        }
-    }
-
     /**
      * TestTableDescriptor.
      * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859
@@ -1425,4 +1120,44 @@ public abstract class AbstractPlannerTest extends IgniteAbstractTest {
             checkSplitAndSerialization(igniteRel, schema);
         }
     }
+
+    /** Creates schema using given table builders. */
+    protected static IgniteSchema createSchemaFrom(Function<TableBuilder, TableBuilder>... tables) {
+        return createSchema(Arrays.stream(tables).map(op -> op.apply(TestBuilders.table()).build()).toArray(IgniteTable[]::new));
+    }
+
+    /** Creates a function, which builds sorted index with given column names and with default collation. */
+    protected static UnaryOperator<TableBuilder> addSortIndex(String... columns) {
+        return tableBuilder -> {
+            SortedIndexBuilder indexBuilder = tableBuilder.sortedIndex();
+            StringBuilder nameBuilder = new StringBuilder("idx");
+
+            for (String colName : columns) {
+                indexBuilder.addColumn(colName.toUpperCase(), Collation.ASC_NULLS_LAST);
+                nameBuilder.append('_').append(colName);
+            }
+
+            return indexBuilder.name(nameBuilder.toString()).end();
+        };
+    }
+
+    /** Creates a function, which builds hash index with given column names. */
+    protected static UnaryOperator<TableBuilder> addHashIndex(String... columns) {
+        return tableBuilder -> {
+            HashIndexBuilder indexBuilder = tableBuilder.hashIndex();
+            StringBuilder nameBuilder = new StringBuilder("idx");
+
+            for (String colName : columns) {
+                indexBuilder.addColumn(colName.toUpperCase());
+                nameBuilder.append('_').append(colName);
+            }
+
+            return indexBuilder.name(nameBuilder.toString()).end();
+        };
+    }
+
+    /** Sets table size. */
+    static Function<TableBuilder, TableBuilder> setSize(int size) {
+        return t -> t.size(size);
+    }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AggregatePlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AggregatePlannerTest.java
index da5d8ef33f..cad99b2b40 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AggregatePlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AggregatePlannerTest.java
@@ -175,7 +175,7 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest {
                 nodeOrAnyChild(isInstanceOf(IgniteColocatedSortAggregate.class)
                         .and(not(hasAggregate()))
                         .and(hasGroups())
-                        .and(input(isIndexScan("TEST", "grp0_grp1")))
+                        .and(input(isIndexScan("TEST", "idx_grp0_grp1")))
                 ));
 
         assertPlan(TestCase.CASE_13A,
@@ -186,7 +186,7 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest {
                                 .and(input(isInstanceOf(IgniteMapSortAggregate.class)
                                         .and(not(hasAggregate()))
                                         .and(hasGroups())
-                                        .and(input(isIndexScan("TEST", "grp0_grp1")))
+                                        .and(input(isIndexScan("TEST", "idx_grp0_grp1")))
                                 ))
                         ))
                 ));
@@ -228,7 +228,7 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest {
         assertPlan(TestCase.CASE_16,
                 not(nodeOrAnyChild(isInstanceOf(IgniteSort.class)))
                         .and(nodeOrAnyChild(input(1, isInstanceOf(IgniteColocatedSortAggregate.class))
-                                .and(input(isIndexScan("TEST", "val0")))
+                                .and(input(isIndexScan("TEST", "idx_val0")))
                         )),
                 additionalRulesToDisable);
 
@@ -236,7 +236,7 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest {
                 nodeOrAnyChild(isInstanceOf(IgniteReduceSortAggregate.class)
                         .and(input(isInstanceOf(IgniteExchange.class)
                                 .and(input(isInstanceOf(IgniteMapSortAggregate.class)
-                                        .and(input(isIndexScan("TEST", "val0")))
+                                        .and(input(isIndexScan("TEST", "idx_val0")))
                                 ))
                         ))
                 ),
@@ -469,7 +469,7 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest {
         assertPlan(testCase,
                 nodeOrAnyChild(isInstanceOf(IgniteColocatedSortAggregate.class)
                         .and(hasAggregate())
-                        .and(input(isIndexScan("TEST", "grp0_grp1")))
+                        .and(input(isIndexScan("TEST", "idx_grp0_grp1")))
                 )
         );
     }
@@ -480,7 +480,7 @@ public class AggregatePlannerTest extends AbstractAggregatePlannerTest {
                         .and(input(isInstanceOf(IgniteExchange.class)
                                 .and(input(isInstanceOf(IgniteMapSortAggregate.class)
                                         .and(hasAggregate())
-                                        .and(input(isIndexScan("TEST", "grp0_grp1")))
+                                        .and(input(isIndexScan("TEST", "idx_grp0_grp1")))
                                 ))
                         ))
                 )
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ColocatedSortAggregatePlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ColocatedSortAggregatePlannerTest.java
index 289e38b2ba..8c92f35c18 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ColocatedSortAggregatePlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ColocatedSortAggregatePlannerTest.java
@@ -164,7 +164,7 @@ public class ColocatedSortAggregatePlannerTest extends AbstractAggregatePlannerT
                 nodeOrAnyChild(isInstanceOf(IgniteColocatedSortAggregate.class)
                         .and(not(hasAggregate()))
                         .and(hasGroups())
-                        .and(input(isIndexScan("TEST", "grp0_grp1")))
+                        .and(input(isIndexScan("TEST", "idx_grp0_grp1")))
                 ),
                 disableRules
         );
@@ -174,7 +174,7 @@ public class ColocatedSortAggregatePlannerTest extends AbstractAggregatePlannerT
                         .and(not(hasAggregate()))
                         .and(hasGroups())
                         .and(input(isInstanceOf(IgniteExchange.class)
-                                .and(input(isIndexScan("TEST", "grp0_grp1")))
+                                .and(input(isIndexScan("TEST", "idx_grp0_grp1")))
                         ))
                 ),
                 disableRules
@@ -209,7 +209,7 @@ public class ColocatedSortAggregatePlannerTest extends AbstractAggregatePlannerT
         assertPlan(TestCase.CASE_16,
                 not(nodeOrAnyChild(isInstanceOf(IgniteSort.class)))
                         .and(nodeOrAnyChild(input(1, isInstanceOf(IgniteColocatedSortAggregate.class))
-                                .and(input(isIndexScan("TEST", "val0")))
+                                .and(input(isIndexScan("TEST", "idx_val0")))
                         )),
                 ArrayUtils.concat(disableRules, additionalRulesToDisable)
         );
@@ -218,7 +218,7 @@ public class ColocatedSortAggregatePlannerTest extends AbstractAggregatePlannerT
                 not(nodeOrAnyChild(isInstanceOf(IgniteSort.class)))
                         .and(nodeOrAnyChild(input(1, isInstanceOf(IgniteColocatedSortAggregate.class)
                                         .and(input(isInstanceOf(IgniteExchange.class)
-                                                .and(input(isIndexScan("TEST", "val0")))
+                                                .and(input(isIndexScan("TEST", "idx_val0")))
                                         ))
                                 ))
                         ),
@@ -443,7 +443,7 @@ public class ColocatedSortAggregatePlannerTest extends AbstractAggregatePlannerT
         assertPlan(testCase,
                 nodeOrAnyChild(isInstanceOf(IgniteColocatedSortAggregate.class)
                         .and(hasAggregate())
-                        .and(input(isIndexScan("TEST", "grp0_grp1")))
+                        .and(input(isIndexScan("TEST", "idx_grp0_grp1")))
                 ),
                 disableRules
         );
@@ -454,7 +454,7 @@ public class ColocatedSortAggregatePlannerTest extends AbstractAggregatePlannerT
                 nodeOrAnyChild(isInstanceOf(IgniteColocatedSortAggregate.class)
                         .and(hasAggregate())
                         .and(input(isInstanceOf(IgniteExchange.class)
-                                .and(input(isIndexScan("TEST", "grp0_grp1")))
+                                .and(input(isIndexScan("TEST", "idx_grp0_grp1")))
                         ))
                 ),
                 disableRules
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CorrelatedNestedLoopJoinPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CorrelatedNestedLoopJoinPlannerTest.java
index 705952a164..bfbe4390e6 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CorrelatedNestedLoopJoinPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CorrelatedNestedLoopJoinPlannerTest.java
@@ -23,18 +23,18 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.List;
+import java.util.Objects;
+import java.util.function.UnaryOperator;
 import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rex.RexFieldAccess;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 import org.apache.ignite.internal.sql.engine.prepare.bounds.ExactBounds;
 import org.apache.ignite.internal.sql.engine.prepare.bounds.SearchBounds;
 import org.apache.ignite.internal.sql.engine.rel.IgniteIndexScan;
 import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
-import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
-import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -47,38 +47,9 @@ public class CorrelatedNestedLoopJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testValidIndexExpressions() throws Exception {
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        publicSchema.addTable(
-                new TestTable(
-                        new RelDataTypeFactory.Builder(f)
-                                .add("ID", f.createJavaType(Integer.class))
-                                .add("JID", f.createJavaType(Integer.class))
-                                .add("VAL", f.createJavaType(String.class))
-                                .build(), "T0") {
-
-                    @Override
-                    public IgniteDistribution distribution() {
-                        return IgniteDistributions.broadcast();
-                    }
-                }
-        );
-
-        publicSchema.addTable(
-                new TestTable(
-                        new RelDataTypeFactory.Builder(f)
-                                .add("ID", f.createJavaType(Integer.class))
-                                .add("JID", f.createJavaType(Integer.class))
-                                .add("VAL", f.createJavaType(String.class))
-                                .build(), "T1") {
-
-                    @Override
-                    public IgniteDistribution distribution() {
-                        return IgniteDistributions.broadcast();
-                    }
-                }
-                        .addIndex("t1_jid_idx", 1, 0)
+        IgniteSchema publicSchema = createSchemaFrom(
+                tableA("T0"),
+                tableA("T1").andThen(addSortIndex("JID", "ID"))
         );
 
         String sql = "select * "
@@ -112,51 +83,29 @@ public class CorrelatedNestedLoopJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInvalidIndexExpressions() throws Exception {
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        publicSchema.addTable(
-                new TestTable(
-                        new RelDataTypeFactory.Builder(f)
-                                .add("ID", f.createJavaType(Integer.class))
-                                .add("JID", f.createJavaType(Integer.class))
-                                .add("VAL", f.createJavaType(String.class))
-                                .build(), "T0") {
-
-                    @Override
-                    public IgniteDistribution distribution() {
-                        return IgniteDistributions.broadcast();
-                    }
-                }
-                        .addIndex("t0_jid_idx", 1, 0)
-        );
-
-        publicSchema.addTable(
-                new TestTable(
-                        new RelDataTypeFactory.Builder(f)
-                                .add("ID", f.createJavaType(Integer.class))
-                                .add("JID", f.createJavaType(Integer.class))
-                                .add("VAL", f.createJavaType(String.class))
-                                .build(), "T1") {
-
-                    @Override
-                    public IgniteDistribution distribution() {
-                        return IgniteDistributions.broadcast();
-                    }
-                }
-                        .addIndex("t1_jid_idx", 1, 0)
+        IgniteSchema publicSchema = createSchemaFrom(
+                tableA("T0").andThen(addHashIndex("JID", "ID")),
+                tableA("T1").andThen(addHashIndex("JID", "ID"))
         );
 
         String sql = "select * "
                 + "from t0 "
                 + "join t1 on t0.jid + 2 > t1.jid * 2";
 
-        IgniteRel phys = physicalPlan(
+        assertPlan(
                 sql,
                 publicSchema,
+                Objects::nonNull,
                 "MergeJoinConverter", "NestedLoopJoinConverter", "FilterSpoolMergeRule"
         );
+    }
 
-        assertNotNull(phys);
+    private static UnaryOperator<TableBuilder> tableA(String tableName) {
+        return tableBuilder -> tableBuilder
+                .name(tableName)
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("JID", NativeTypes.INT32)
+                .addColumn("VAL", NativeTypes.STRING)
+                .distribution(IgniteDistributions.broadcast());
     }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CorrelatedSubqueryPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CorrelatedSubqueryPlannerTest.java
index 0ed485c65f..c64726ad74 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CorrelatedSubqueryPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CorrelatedSubqueryPlannerTest.java
@@ -32,6 +32,10 @@ import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rex.RexCorrelVariable;
 import org.apache.calcite.rex.RexFieldAccess;
 import org.apache.calcite.sql.SqlNode;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
+import org.apache.ignite.internal.sql.engine.framework.TestTable;
 import org.apache.ignite.internal.sql.engine.prepare.IgnitePlanner;
 import org.apache.ignite.internal.sql.engine.prepare.PlannerPhase;
 import org.apache.ignite.internal.sql.engine.prepare.PlanningContext;
@@ -46,8 +50,7 @@ import org.junit.jupiter.api.Test;
 /** Tests to verify correlated subquery planning. */
 public class CorrelatedSubqueryPlannerTest extends AbstractPlannerTest {
     /**
-     * Test verifies the row type is consistent for correlation variable and
-     * node that actually puts this variable into a context.
+     * Test verifies the row type is consistent for correlation variable and node that actually puts this variable into a context.
      *
      * <p>In this particular test the row type of the left input of CNLJ node should
      * match the row type correlated variable in the filter was created with.
@@ -56,10 +59,7 @@ public class CorrelatedSubqueryPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void test() throws Exception {
-        IgniteSchema schema = createSchema(
-                createTable("T1", IgniteDistributions.single(), "A", Integer.class,
-                        "B", Integer.class, "C", Integer.class, "D", Integer.class, "E", Integer.class)
-        );
+        IgniteSchema schema = createSchema(createTestTable("A", "B", "C", "D", "E"));
 
         String sql = ""
                 + "SELECT (SELECT count(*) FROM t1 AS x WHERE x.b<t1.b)\n"
@@ -95,8 +95,7 @@ public class CorrelatedSubqueryPlannerTest extends AbstractPlannerTest {
     @Test
     public void testCorrelatesCollisionsLeftHand() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("T1", IgniteDistributions.single(), "A", Integer.class,
-                        "B", Integer.class, "C", Integer.class, "D", Integer.class)
+                createTestTable("A", "B", "C", "D")
         );
 
         String sql = "SELECT * FROM t1 as cor WHERE "
@@ -151,7 +150,7 @@ public class CorrelatedSubqueryPlannerTest extends AbstractPlannerTest {
     @Test
     public void testCorrelatesCollisionsRightHand() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("T1", IgniteDistributions.single(), "A", Integer.class)
+                createTestTable("A")
         );
 
         String sql = "SELECT (SELECT (SELECT (SELECT cor.a))) FROM t1 as cor";
@@ -183,8 +182,7 @@ public class CorrelatedSubqueryPlannerTest extends AbstractPlannerTest {
     @Test
     public void testCorrelatesCollisionsMixed() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("T1", IgniteDistributions.single(), "A", Integer.class,
-                        "B", Integer.class, "C", Integer.class)
+                createTestTable("A", "B", "C")
         );
 
         String sql = "SELECT * FROM t1 as cor WHERE "
@@ -237,5 +235,20 @@ public class CorrelatedSubqueryPlannerTest extends AbstractPlannerTest {
         // Convert sub-queries to correlates.
         return planner.transform(PlannerPhase.HEP_DECORRELATE, rel.getTraitSet(), rel);
     }
+
+    /** Creates test table with columns of given name and INT32 type. */
+    private static TestTable createTestTable(String... columns) {
+        assert columns.length > 0;
+
+        TableBuilder tableBuilder = TestBuilders.table()
+                .name("T1")
+                .distribution(IgniteDistributions.single());
+
+        for (String column : columns) {
+            tableBuilder.addColumn(column, NativeTypes.INT32);
+        }
+
+        return tableBuilder.build();
+    }
 }
 
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/DmlPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/DmlPlannerTest.java
index bd5a66e808..6a1409f4fa 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/DmlPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/DmlPlannerTest.java
@@ -22,6 +22,7 @@ import java.util.stream.Stream;
 import org.apache.calcite.sql.validate.SqlValidatorException;
 import org.apache.ignite.internal.schema.NativeTypes;
 import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestTable;
 import org.apache.ignite.internal.sql.engine.rel.IgniteExchange;
 import org.apache.ignite.internal.sql.engine.rel.IgniteTableModify;
 import org.apache.ignite.internal.sql.engine.rel.IgniteTableScan;
@@ -183,9 +184,7 @@ public class DmlPlannerTest extends AbstractPlannerTest {
     }
 
     // Class name is fully-qualified because AbstractPlannerTest defines a class with the same name.
-    private static org.apache.ignite.internal.sql.engine.framework.TestTable newTestTable(
-            String tableName, IgniteDistribution distribution) {
-
+    private static TestTable newTestTable(String tableName, IgniteDistribution distribution) {
         return TestBuilders.table()
                 .name(tableName)
                 .addColumn("C1", NativeTypes.INT32)
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/HashIndexPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/HashIndexPlannerTest.java
index c84fa99d77..e9356112f9 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/HashIndexPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/HashIndexPlannerTest.java
@@ -22,14 +22,16 @@ import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.notNullValue;
 import static org.hamcrest.Matchers.nullValue;
 
-import java.util.List;
+import java.util.function.UnaryOperator;
 import org.apache.calcite.plan.RelOptPlanner.CannotPlanException;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelNode;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 import org.apache.ignite.internal.sql.engine.rel.IgniteIndexScan;
 import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
 import org.apache.ignite.internal.sql.engine.rel.IgniteTableScan;
-import org.apache.ignite.internal.sql.engine.schema.IgniteIndex;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
 import org.apache.ignite.internal.testframework.IgniteTestUtils;
@@ -39,10 +41,10 @@ import org.junit.jupiter.api.Test;
  * Tests to verify hash index support.
  */
 public class HashIndexPlannerTest extends AbstractPlannerTest {
+    private static final String HASH_INDEX_NAME = "VAL_HASH_IDX";
+
     @Test
     public void hashIndexIsAppliedForEquiCondition() throws Exception {
-        var indexName = "VAL_HASH_IDX";
-
         IgniteSchema schema = makeCommonSchema();
 
         String sql = "SELECT id FROM test_tbl WHERE val = 10";
@@ -54,7 +56,7 @@ public class HashIndexPlannerTest extends AbstractPlannerTest {
         String invalidPlanMsg = "Invalid plan:\n" + RelOptUtil.toString(phys);
 
         assertThat(invalidPlanMsg, scan, notNullValue());
-        assertThat(invalidPlanMsg, scan.indexName(), equalTo(indexName));
+        assertThat(invalidPlanMsg, scan.indexName(), equalTo(HASH_INDEX_NAME));
     }
 
     @Test
@@ -103,45 +105,13 @@ public class HashIndexPlannerTest extends AbstractPlannerTest {
         assertThat("Invalid plan:\n" + RelOptUtil.toString(phys), idxScan, notNullValue());
     }
 
-    private IgniteSchema makeCommonSchema() {
-        var indexName = "VAL_HASH_IDX";
-
-        TestTable tbl = createTable(
-                "TEST_TBL",
-                someAffinity(),
-                "ID", Integer.class,
-                "VAL", Integer.class
-        );
-
-        tbl.addIndex(new IgniteIndex(TestHashIndex.create(List.of("VAL"), indexName)));
-
-        return createSchema(tbl);
-    }
-
     @Test
     public void hashIndexIsAppliedForComplexConditions() throws Exception {
-        var indexName = "VAL_HASH_IDX";
-
-        TestTable leftTable = createTable(
-                "LEFT_TBL",
-                IgniteDistributions.single(),
-                "ID", Integer.class,
-                "VAL0", Integer.class,
-                "VAL1", Integer.class
-        );
-
-        TestTable rightTable = createTable(
-                "RIGHT_TBL",
-                IgniteDistributions.single(),
-                "ID", Integer.class,
-                "VAL0", Integer.class,
-                "VAL1", Integer.class
+        IgniteSchema schema = createSchemaFrom(
+                tableB("LEFT_TBL"),
+                tableB("RIGHT_TBL").andThen(addHashIndex("VAL0", "VAL1"))
         );
 
-        rightTable.addIndex(new IgniteIndex(TestHashIndex.create(List.of("VAL0", "VAL1"), indexName)));
-
-        IgniteSchema schema = createSchema(leftTable, rightTable);
-
         String sql = "SELECT l.*, r.* FROM left_tbl l JOIN right_tbl r ON l.val0 = r.val0 AND l.val1 = r.val1";
 
         RelNode phys = physicalPlan(sql, schema, "MergeJoinConverter", "NestedLoopJoinConverter");
@@ -151,33 +121,16 @@ public class HashIndexPlannerTest extends AbstractPlannerTest {
         String invalidPlanMsg = "Invalid plan:\n" + RelOptUtil.toString(phys);
 
         assertThat(invalidPlanMsg, scan, notNullValue());
-        assertThat(invalidPlanMsg, scan.indexName(), equalTo(indexName));
+        assertThat(invalidPlanMsg, scan.indexName(), equalTo("idx_VAL0_VAL1"));
     }
 
     @Test
     public void hashIndexIsNotAppliedForPartialCoveredConditions() throws Exception {
-        var indexName = "VAL_HASH_IDX";
-
-        TestTable leftTable = createTable(
-                "LEFT_TBL",
-                IgniteDistributions.single(),
-                "ID", Integer.class,
-                "VAL0", Integer.class,
-                "VAL1", Integer.class
+        IgniteSchema schema = createSchemaFrom(
+                tableB("LEFT_TBL"),
+                tableB("RIGHT_TBL").andThen(addHashIndex("VAL0", "VAL1"))
         );
 
-        TestTable rightTable = createTable(
-                "RIGHT_TBL",
-                IgniteDistributions.single(),
-                "ID", Integer.class,
-                "VAL0", Integer.class,
-                "VAL1", Integer.class
-        );
-
-        rightTable.addIndex(new IgniteIndex(TestHashIndex.create(List.of("VAL0", "VAL1"), indexName)));
-
-        IgniteSchema schema = createSchema(leftTable, rightTable);
-
         String sql = "SELECT l.id FROM left_tbl l JOIN right_tbl r ON l.val0 = r.val0";
 
         RelNode phys = physicalPlan(sql, schema, "MergeJoinConverter", "NestedLoopJoinConverter");
@@ -188,4 +141,26 @@ public class HashIndexPlannerTest extends AbstractPlannerTest {
 
         assertThat(invalidPlanMsg, scan, nullValue());
     }
+
+    private static IgniteSchema makeCommonSchema() {
+        return createSchema(TestBuilders.table()
+                .name("TEST_TBL")
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("VAL", NativeTypes.INT32)
+                .distribution(someAffinity())
+                .hashIndex()
+                .name(HASH_INDEX_NAME)
+                .addColumn("VAL")
+                .end()
+                .build());
+    }
+
+    private static UnaryOperator<TableBuilder> tableB(String tableName) {
+        return tableBuilder -> tableBuilder
+                .name(tableName)
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("VAL0", NativeTypes.INT32)
+                .addColumn("VAL1", NativeTypes.INT32)
+                .distribution(IgniteDistributions.single());
+    }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/HashIndexSpoolPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/HashIndexSpoolPlannerTest.java
index 0724c2699f..3014b79154 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/HashIndexSpoolPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/HashIndexSpoolPlannerTest.java
@@ -23,17 +23,15 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.List;
+import java.util.function.UnaryOperator;
 import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rex.RexFieldAccess;
 import org.apache.calcite.rex.RexNode;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 import org.apache.ignite.internal.sql.engine.rel.IgniteHashIndexSpool;
 import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
-import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
-import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
-import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
@@ -44,27 +42,14 @@ import org.junit.jupiter.api.Test;
 @Disabled("https://issues.apache.org/jira/browse/IGNITE-18689")
 public class HashIndexSpoolPlannerTest extends AbstractPlannerTest {
     /**
-     * Check equi-join on not colocated fields. CorrelatedNestedLoopJoinTest is applicable for this case only with
-     * IndexSpool.
+     * Check equi-join on not colocated fields. CorrelatedNestedLoopJoinTest is applicable for this case only with IndexSpool.
      */
     @Test
     public void testSingleKey() throws Exception {
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        createTable(publicSchema, "T0", new RelDataTypeFactory.Builder(f)
-                .add("ID", f.createJavaType(Integer.class))
-                .add("JID", f.createJavaType(Integer.class))
-                .add("VAL", f.createJavaType(String.class))
-                .build(), IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID));
-
-        createTable(publicSchema, "T1",
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("JID", f.createJavaType(Integer.class))
-                        .add("VAL", f.createJavaType(String.class))
-                        .build(), IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID))
-                .addIndex("t1_jid_idx", 1, 0);
+        IgniteSchema publicSchema = createSchemaFrom(
+                tableA("T0"),
+                tableA("T1").andThen(addHashIndex("JID", "ID"))
+        );
 
         String sql = "select * "
                 + "from t0 "
@@ -92,40 +77,9 @@ public class HashIndexSpoolPlannerTest extends AbstractPlannerTest {
 
     @Test
     public void testMultipleKeys() throws Exception {
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        publicSchema.addTable(
-                new TestTable(
-                        new RelDataTypeFactory.Builder(f)
-                                .add("ID", f.createJavaType(Integer.class))
-                                .add("JID0", f.createJavaType(Integer.class))
-                                .add("JID1", f.createJavaType(Integer.class))
-                                .add("VAL", f.createJavaType(String.class))
-                                .build(), "T0") {
-
-                    @Override
-                    public IgniteDistribution distribution() {
-                        return IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID);
-                    }
-                }
-        );
-
-        publicSchema.addTable(
-                new TestTable(
-                        new RelDataTypeFactory.Builder(f)
-                                .add("ID", f.createJavaType(Integer.class))
-                                .add("JID0", f.createJavaType(Integer.class))
-                                .add("JID1", f.createJavaType(Integer.class))
-                                .add("VAL", f.createJavaType(String.class))
-                                .build(), "T1") {
-
-                    @Override
-                    public IgniteDistribution distribution() {
-                        return IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID);
-                    }
-                }
-                        .addIndex("t1_jid0_idx", 1, 0)
+        IgniteSchema publicSchema = createSchemaFrom(
+                tableB("T0"),
+                tableB("T1").andThen(addHashIndex("JID", "ID"))
         );
 
         String sql = "select * "
@@ -156,37 +110,9 @@ public class HashIndexSpoolPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testSourceWithoutCollation() throws Exception {
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        publicSchema.addTable(
-                new TestTable(
-                        new RelDataTypeFactory.Builder(f)
-                                .add("ID", f.createJavaType(Integer.class))
-                                .add("JID", f.createJavaType(Integer.class))
-                                .add("VAL", f.createJavaType(String.class))
-                                .build(), "T0") {
-
-                    @Override
-                    public IgniteDistribution distribution() {
-                        return IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID);
-                    }
-                }
-        );
-
-        publicSchema.addTable(
-                new TestTable(
-                        new RelDataTypeFactory.Builder(f)
-                                .add("ID", f.createJavaType(Integer.class))
-                                .add("JID", f.createJavaType(Integer.class))
-                                .add("VAL", f.createJavaType(String.class))
-                                .build(), "T1") {
-
-                    @Override
-                    public IgniteDistribution distribution() {
-                        return IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID);
-                    }
-                }
+        IgniteSchema publicSchema = createSchemaFrom(
+                tableA("T0"),
+                tableA("T1")
         );
 
         String sql = "select * "
@@ -210,4 +136,23 @@ public class HashIndexSpoolPlannerTest extends AbstractPlannerTest {
         assertTrue(searchRow.get(1) instanceof RexFieldAccess);
         assertNull(searchRow.get(2));
     }
+
+    private static UnaryOperator<TableBuilder> tableA(String tableName) {
+        return tableBuilder -> tableBuilder
+                .name(tableName)
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("JID", NativeTypes.INT32)
+                .addColumn("VAL", NativeTypes.STRING)
+                .distribution(someAffinity());
+    }
+
+    private static UnaryOperator<TableBuilder> tableB(String tableName) {
+        return tableBuilder -> tableBuilder
+                .name(tableName)
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("JID0", NativeTypes.INT32)
+                .addColumn("JID1", NativeTypes.INT32)
+                .addColumn("VAL", NativeTypes.STRING)
+                .distribution(someAffinity());
+    }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ImplicitCastsTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ImplicitCastsTest.java
index 8f4f1e213f..7442c50772 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ImplicitCastsTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ImplicitCastsTest.java
@@ -28,17 +28,19 @@ import java.util.UUID;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
-import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
+import org.apache.ignite.internal.sql.engine.framework.TestTable;
 import org.apache.ignite.internal.sql.engine.rel.IgniteIndexScan;
 import org.apache.ignite.internal.sql.engine.rel.IgniteMergeJoin;
 import org.apache.ignite.internal.sql.engine.rel.IgniteNestedLoopJoin;
@@ -47,6 +49,7 @@ import org.apache.ignite.internal.sql.engine.rel.IgniteTableScan;
 import org.apache.ignite.internal.sql.engine.schema.IgniteIndex.Type;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
+import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
 import org.apache.ignite.internal.sql.engine.util.NativeTypeValues;
 import org.apache.ignite.internal.sql.engine.util.StatementChecker;
 import org.jetbrains.annotations.Nullable;
@@ -61,13 +64,13 @@ import org.junit.jupiter.params.provider.MethodSource;
  */
 public class ImplicitCastsTest extends AbstractPlannerTest {
 
-    private static TestTable addTable(IgniteSchema igniteSchema, String tableName, String columnName, RelDataType columnType) {
-        RelDataType tableType = new RelDataTypeFactory.Builder(TYPE_FACTORY)
-                .add("ID", SqlTypeName.INTEGER)
-                .add(columnName, columnType)
+    private static TestTable tableWithColumn(String tableName, String columnName, RelDataType columnType) {
+        return TestBuilders.table()
+                .name(tableName)
+                .addColumn("ID", NativeTypes.INT32, false)
+                .addColumn(columnName, IgniteTypeFactory.relDataTypeToNative(columnType), false)
+                .distribution(IgniteDistributions.single())
                 .build();
-
-        return createTable(igniteSchema, tableName, tableType, IgniteDistributions.single());
     }
 
     private static String castedExpr(String idx, @Nullable RelDataType type) {
@@ -149,10 +152,10 @@ public class ImplicitCastsTest extends AbstractPlannerTest {
     @ParameterizedTest
     @MethodSource("joinColumnTypes")
     public void testMergeSort(RelDataType lhs, RelDataType rhs, ExpectedTypes expected) throws Exception {
-        IgniteSchema igniteSchema = new IgniteSchema("PUBLIC");
-
-        addTable(igniteSchema, "A1", "COL1", lhs);
-        addTable(igniteSchema, "B1", "COL1", rhs);
+        IgniteSchema igniteSchema = createSchema(
+                tableWithColumn("A1", "COL1", lhs),
+                tableWithColumn("B1", "COL1", rhs)
+        );
 
         String query = "select A1.*, B1.* from A1 join B1 on A1.col1 = B1.col1";
         assertPlan(query, igniteSchema, nodeOrAnyChild(isInstanceOf(IgniteMergeJoin.class)
@@ -165,10 +168,11 @@ public class ImplicitCastsTest extends AbstractPlannerTest {
     @ParameterizedTest
     @MethodSource("joinColumnTypes")
     public void testNestedLoop(RelDataType lhs, RelDataType rhs, ExpectedTypes expected) throws Exception {
-        IgniteSchema igniteSchema = new IgniteSchema("PUBLIC");
+        IgniteSchema igniteSchema = createSchema(
+                tableWithColumn("A1", "COL1", lhs),
+                tableWithColumn("B1", "COL1", rhs)
+        );
 
-        addTable(igniteSchema, "A1", "COL1", lhs);
-        addTable(igniteSchema, "B1", "COL1", rhs);
 
         String query = "select A1.*, B1.* from A1 join B1 on A1.col1 != B1.col1";
         assertPlan(query, igniteSchema, isInstanceOf(IgniteNestedLoopJoin.class).and(new NestedLoopWithFilter(expected)));
@@ -178,9 +182,9 @@ public class ImplicitCastsTest extends AbstractPlannerTest {
     @ParameterizedTest
     @MethodSource("filterTypes")
     public void testFilter(RelDataType lhs, RelDataType rhs, ExpectedTypes expected) throws Exception {
-        IgniteSchema igniteSchema = new IgniteSchema("PUBLIC");
-
-        addTable(igniteSchema, "A1", "COL1", lhs);
+        IgniteSchema igniteSchema = createSchema(
+                tableWithColumn("A1", "COL1", lhs)
+        );
 
         List<Object> params = NativeTypeValues.values(rhs, 1);
 
@@ -202,20 +206,26 @@ public class ImplicitCastsTest extends AbstractPlannerTest {
     @ParameterizedTest
     @MethodSource("filterTypesForIndex")
     public void testIndex(RelDataType lhs, RelDataType rhs, ExpectedTypes expected, Type indexType) throws Exception {
-        IgniteSchema igniteSchema = new IgniteSchema("PUBLIC");
+        UnaryOperator<TableBuilder> tableOp = tableBuilder -> tableBuilder
+                .name("A1")
+                .addColumn("ID", NativeTypes.INT32, false)
+                .addColumn("COL1", IgniteTypeFactory.relDataTypeToNative(lhs), false)
+                .distribution(IgniteDistributions.single());
 
-        TestTable table = addTable(igniteSchema, "A1", "COL1", lhs);
+        UnaryOperator<TableBuilder> indexOp;
         switch (indexType) {
             case SORTED:
-                table.addIndex(RelCollations.of(1), "COL1_IDX");
+                indexOp = addSortIndex("COL1");
                 break;
             case HASH:
-                table.addIndex("COL1_IDX", 1);
+                indexOp = addHashIndex("COL1");
                 break;
             default:
                 throw new IllegalArgumentException("Unexpected index type " + indexType);
         }
 
+        IgniteSchema igniteSchema = createSchemaFrom(tableOp.andThen(indexOp));
+
         List<Object> params = NativeTypeValues.values(rhs, 1);
 
         String query = format("SELECT * FROM A1 WHERE COL1 = ?", rhs);
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/IndexSearchBoundsPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/IndexSearchBoundsPlannerTest.java
index db5c1af179..b4d7ed7fe2 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/IndexSearchBoundsPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/IndexSearchBoundsPlannerTest.java
@@ -27,29 +27,26 @@ import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
 import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
 import java.util.stream.IntStream;
 import java.util.stream.Stream;
-import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.rel.type.RelDataTypeFactory.Builder;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.ignite.internal.index.ColumnCollation;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 import org.apache.ignite.internal.sql.engine.prepare.bounds.ExactBounds;
 import org.apache.ignite.internal.sql.engine.prepare.bounds.MultiBounds;
 import org.apache.ignite.internal.sql.engine.prepare.bounds.RangeBounds;
 import org.apache.ignite.internal.sql.engine.prepare.bounds.SearchBounds;
 import org.apache.ignite.internal.sql.engine.rel.IgniteIndexScan;
 import org.apache.ignite.internal.sql.engine.rel.IgniteUnionAll;
+import org.apache.ignite.internal.sql.engine.schema.IgniteIndex.Collation;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
-import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
-import org.apache.ignite.internal.sql.engine.trait.TraitUtils;
 import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.apache.ignite.internal.sql.engine.util.RexUtils;
 import org.jetbrains.annotations.Nullable;
 import org.junit.jupiter.api.BeforeAll;
@@ -67,8 +64,6 @@ public class IndexSearchBoundsPlannerTest extends AbstractPlannerTest {
 
     private IgniteSchema publicSchema;
 
-    private TestTable tbl;
-
     @BeforeAll
     public static void init() {
         IntStream.rangeClosed(0, 3).forEach(i -> NODES.add(UUID.randomUUID().toString()));
@@ -76,28 +71,7 @@ public class IndexSearchBoundsPlannerTest extends AbstractPlannerTest {
 
     @BeforeEach
     public void beforeEach() {
-        IgniteTypeFactory typeFactory = Commons.typeFactory();
-
-        tbl = new TestTable(
-                new RelDataTypeFactory.Builder(typeFactory)
-                        .add("C1", typeFactory.createTypeWithNullability(typeFactory.createSqlType(SqlTypeName.INTEGER), true))
-                        .add("C2", typeFactory.createTypeWithNullability(typeFactory.createSqlType(SqlTypeName.VARCHAR), true))
-                        .add("C3", typeFactory.createTypeWithNullability(typeFactory.createSqlType(SqlTypeName.INTEGER), true))
-                        .add("C4", typeFactory.createTypeWithNullability(typeFactory.createSqlType(SqlTypeName.INTEGER), true))
-                        .add("C5", typeFactory.createTypeWithNullability(typeFactory.createSqlType(SqlTypeName.TINYINT), true))
-                        .build(), "TEST") {
-
-            @Override
-            public IgniteDistribution distribution() {
-                return IgniteDistributions.single();
-            }
-        };
-
-        tbl.addIndex("C1C2C3", 0, 1, 2);
-
-        publicSchema = new IgniteSchema("PUBLIC");
-
-        publicSchema.addTable(tbl);
+        publicSchema = createSchemaFrom(tableA("TEST"));
     }
 
     /** Simple case on one field, without multi tuple SEARCH/SARG. */
@@ -200,11 +174,18 @@ public class IndexSearchBoundsPlannerTest extends AbstractPlannerTest {
     /** Tests bounds with DESC ordering. */
     @Test
     public void testBoundsDescOrdering() throws Exception {
-        tbl.addIndex(RelCollations.of(TraitUtils.createFieldCollation(3, ColumnCollation.DESC_NULLS_LAST),
-                TraitUtils.createFieldCollation(2, ColumnCollation.ASC_NULLS_FIRST)), "C4");
-
-        tbl.addIndex(RelCollations.of(TraitUtils.createFieldCollation(3, ColumnCollation.ASC_NULLS_FIRST),
-                TraitUtils.createFieldCollation(2, ColumnCollation.ASC_NULLS_FIRST)), "C4IDX");
+        publicSchema = createSchemaFrom(tableA("TEST")
+                .andThen(t -> t.sortedIndex()
+                        .name("C4")
+                        .addColumn("C4", Collation.DESC_NULLS_LAST)
+                        .addColumn("C3", Collation.ASC_NULLS_FIRST)
+                        .end())
+                .andThen(t -> t.sortedIndex()
+                        .name("C4_IDX")
+                        .addColumn("C4", Collation.ASC_NULLS_FIRST)
+                        .addColumn("C3", Collation.ASC_NULLS_FIRST)
+                        .end())
+        );
 
         assertBounds("SELECT * FROM TEST WHERE C4 > 1",
                 range(null, 1, true, false));
@@ -404,6 +385,14 @@ public class IndexSearchBoundsPlannerTest extends AbstractPlannerTest {
     /** Tests bounds merge. */
     @Test
     public void testBoundsMerge() throws Exception {
+        IgniteSchema publicSchema = createSchemaFrom(tableA("TEST")
+                .andThen(t -> t.sortedIndex()
+                        .name("C4")
+                        .addColumn("C4", Collation.DESC_NULLS_LAST)
+                        .addColumn("C3", Collation.ASC_NULLS_FIRST)
+                        .end()
+                ));
+
         assertBounds("SELECT * FROM TEST WHERE C1 > ? AND C1 >= 1", List.of(10), publicSchema,
                 range("$GREATEST2(?0, 1)", "$NULL_BOUND()", true, false)
         );
@@ -424,9 +413,6 @@ public class IndexSearchBoundsPlannerTest extends AbstractPlannerTest {
                 range("?0", "$NULL_BOUND()", true, false)
         );
 
-        tbl.addIndex(RelCollations.of(TraitUtils.createFieldCollation(3, ColumnCollation.DESC_NULLS_LAST),
-                TraitUtils.createFieldCollation(2, ColumnCollation.ASC_NULLS_FIRST)), "C4");
-
         assertBounds("SELECT * FROM TEST WHERE C4 > ? AND C4 >= 1 AND C4 < ? AND C4 < ?", List.of(10, 10, 10), publicSchema,
                 range("$LEAST2(?1, ?2)", "$GREATEST2(?0, 1)", false, true)
         );
@@ -465,10 +451,10 @@ public class IndexSearchBoundsPlannerTest extends AbstractPlannerTest {
     @ParameterizedTest
     @MethodSource("boundsTypeLimits")
     public void testBoundsTypeLimits(RelDataType type, Object value, Predicate<SearchBounds> bounds) throws Exception {
-        TestTable table = createTableWithIndex("TEST2", "C2", type);
-        publicSchema.addTable(table);
+        IgniteSchema schema = createSchemaFrom(
+                tableB("TEST2", "C2", type).andThen(addSortIndex("C2")));
 
-        assertBounds("SELECT * FROM test2 WHERE C2 = " + value, List.of(), publicSchema, bounds);
+        assertBounds("SELECT * FROM test2 WHERE C2 = " + value, List.of(), schema, bounds);
     }
 
     private static Stream<Arguments> boundsTypeLimits() {
@@ -508,10 +494,10 @@ public class IndexSearchBoundsPlannerTest extends AbstractPlannerTest {
                 Arguments.arguments(decimal3Type, "(-1000)::DECIMAL(3)", exact(decimal3TypeLimits[0])),
                 Arguments.arguments(decimal3Type, "(-999)::DECIMAL(3)", exact(decimal3TypeLimits[0])),
                 Arguments.arguments(decimal3Type, "999::DECIMAL(3)", exact(decimal3TypeLimits[1])),
-                Arguments.arguments(decimal3Type, "1000::DECIMAL(3)",  exact(decimal3TypeLimits[1])),
+                Arguments.arguments(decimal3Type, "1000::DECIMAL(3)", exact(decimal3TypeLimits[1])),
 
-                Arguments.arguments(decimal53Type, "(-100.000)::DECIMAL(5, 3)",  exact(decimal53TypeLimits[0])),
-                Arguments.arguments(decimal53Type, "(100.000)::DECIMAL(5, 3)",  exact(decimal53TypeLimits[1])),
+                Arguments.arguments(decimal53Type, "(-100.000)::DECIMAL(5, 3)", exact(decimal53TypeLimits[0])),
+                Arguments.arguments(decimal53Type, "(100.000)::DECIMAL(5, 3)", exact(decimal53TypeLimits[1])),
 
                 // TODO https://issues.apache.org/jira/browse/IGNITE-19858
                 //  Cause serialization/deserialization mismatch in AbstractPlannerTest::checkSplitAndSerialization
@@ -556,7 +542,7 @@ public class IndexSearchBoundsPlannerTest extends AbstractPlannerTest {
                 .and(scan -> matchBounds(scan.searchBounds(), predicates))), params);
     }
 
-    private static boolean  matchBounds(List<SearchBounds> searchBounds, Predicate<SearchBounds>... predicates) {
+    private static boolean matchBounds(List<SearchBounds> searchBounds, Predicate<SearchBounds>... predicates) {
         for (int i = 0; i < predicates.length; i++) {
             if (!predicates[i].test(searchBounds.get(i))) {
                 return false;
@@ -610,21 +596,31 @@ public class IndexSearchBoundsPlannerTest extends AbstractPlannerTest {
         };
     }
 
-    private TestTable createTableWithIndex(String tableName, String column, RelDataType type) {
-        IgniteTypeFactory typeFactory = Commons.typeFactory();
-
-        RelDataType rowType = new Builder(typeFactory)
-                .add("C1", typeFactory.createTypeWithNullability(typeFactory.createSqlType(SqlTypeName.INTEGER), true))
-                .add(column, typeFactory.createTypeWithNullability(type, true))
-                .build();
-        TestTable testTable = new TestTable(tableName, rowType, 400d) {
-            @Override
-            public IgniteDistribution distribution() {
-                return IgniteDistributions.single();
-            }
-        };
+    private static UnaryOperator<TableBuilder> tableA(String tableName) {
+        return tableBuilder -> tableBuilder
+                .name(tableName)
+                .name("TEST")
+                .addColumn("C1", NativeTypes.INT32)
+                .addColumn("C2", NativeTypes.STRING)
+                .addColumn("C3", NativeTypes.INT32)
+                .addColumn("C4", NativeTypes.INT32)
+                .addColumn("C5", NativeTypes.INT8)
+                .distribution(IgniteDistributions.single())
+                .size(100)
+                .sortedIndex()
+                .name("C1C2C3")
+                .addColumn("C1", Collation.ASC_NULLS_LAST)
+                .addColumn("C2", Collation.ASC_NULLS_LAST)
+                .addColumn("C3", Collation.ASC_NULLS_LAST)
+                .end();
+    }
 
-        testTable.addIndex(tableName + "_" + column + "_IDX", 1);
-        return testTable;
+    private static UnaryOperator<TableBuilder> tableB(String tableName, String column, RelDataType type) {
+        return tableBuilder -> tableBuilder
+                .name(tableName)
+                .addColumn("C1", NativeTypes.INT32)
+                .addColumn(column, IgniteTypeFactory.relDataTypeToNative(type))
+                .size(400)
+                .distribution(IgniteDistributions.single());
     }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/JoinColocationPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/JoinColocationPlannerTest.java
index b8decb7a1f..eb4f84a4bb 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/JoinColocationPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/JoinColocationPlannerTest.java
@@ -26,17 +26,20 @@ import static org.hamcrest.Matchers.hasSize;
 
 import java.util.List;
 import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.util.ImmutableIntList;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestTable;
 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.IgniteMergeJoin;
 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.IgniteTableScan;
-import org.apache.ignite.internal.sql.engine.schema.IgniteIndex;
+import org.apache.ignite.internal.sql.engine.schema.IgniteIndex.Collation;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
+import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
 import org.junit.jupiter.api.Test;
 
@@ -49,14 +52,7 @@ public class JoinColocationPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void joinSameTableSimpleAff() throws Exception {
-        TestTable tbl = createTable(
-                "TEST_TBL",
-                IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID),
-                "ID", Integer.class,
-                "VAL", String.class
-        );
-
-        tbl.addIndex(new IgniteIndex(TestSortedIndex.create(RelCollations.of(0), "PK", tbl)));
+        TestTable tbl = simpleTable("TEST_TBL", DEFAULT_TBL_SIZE);
 
         IgniteSchema schema = createSchema(tbl);
 
@@ -81,15 +77,7 @@ public class JoinColocationPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void joinSameTableComplexAff() throws Exception {
-        TestTable tbl = createTable(
-                "TEST_TBL",
-                IgniteDistributions.affinity(ImmutableIntList.of(0, 1), nextTableId(), DEFAULT_ZONE_ID),
-                "ID1", Integer.class,
-                "ID2", Integer.class,
-                "VAL", String.class
-        );
-
-        tbl.addIndex(new IgniteIndex(TestSortedIndex.create(RelCollations.of(ImmutableIntList.of(0, 1)), "PK", tbl)));
+        TestTable tbl = complexTbl("TEST_TBL");
 
         IgniteSchema schema = createSchema(tbl);
 
@@ -116,27 +104,10 @@ public class JoinColocationPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void joinComplexToSimpleAff() throws Exception {
-        TestTable complexTbl = createTable(
-                "COMPLEX_TBL",
-                2 * DEFAULT_TBL_SIZE,
-                IgniteDistributions.affinity(ImmutableIntList.of(0, 1), nextTableId(), DEFAULT_ZONE_ID),
-                "ID1", Integer.class,
-                "ID2", Integer.class,
-                "VAL", String.class
-        );
+        TestTable complexTbl = complexTbl("COMPLEX_TBL", 2 * DEFAULT_TBL_SIZE,
+                IgniteDistributions.affinity(ImmutableIntList.of(0, 1), nextTableId(), DEFAULT_ZONE_ID));
 
-        complexTbl.addIndex(new IgniteIndex(TestSortedIndex.create(RelCollations.of(ImmutableIntList.of(0, 1)), "PK", complexTbl)));
-
-        TestTable simpleTbl = createTable(
-                "SIMPLE_TBL",
-                DEFAULT_TBL_SIZE,
-                IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID),
-                "ID", Integer.class,
-                "ID2", Integer.class,
-                "VAL", String.class
-        );
-
-        simpleTbl.addIndex(new IgniteIndex(TestSortedIndex.create(RelCollations.of(0), "PK", simpleTbl)));
+        TestTable simpleTbl = simpleTable("SIMPLE_TBL", DEFAULT_TBL_SIZE);
 
         IgniteSchema schema = createSchema(complexTbl, simpleTbl);
 
@@ -170,29 +141,15 @@ public class JoinColocationPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void joinComplexToComplexAffWithDifferentOrder() throws Exception {
-        TestTable complexTblDirect = createTable(
+        TestTable complexTblDirect = complexTbl(
                 "COMPLEX_TBL_DIRECT",
                 2 * DEFAULT_TBL_SIZE,
-                IgniteDistributions.affinity(ImmutableIntList.of(0, 1), nextTableId(), DEFAULT_ZONE_ID),
-                "ID1", Integer.class,
-                "ID2", Integer.class,
-                "VAL", String.class
-        );
-
-        complexTblDirect.addIndex(new IgniteIndex(
-                TestSortedIndex.create(RelCollations.of(ImmutableIntList.of(0, 1)), "PK", complexTblDirect)));
+                IgniteDistributions.affinity(ImmutableIntList.of(0, 1), nextTableId(), DEFAULT_ZONE_ID));
 
-        TestTable complexTblIndirect = createTable(
+        TestTable complexTblIndirect = complexTbl(
                 "COMPLEX_TBL_INDIRECT",
                 DEFAULT_TBL_SIZE,
-                IgniteDistributions.affinity(ImmutableIntList.of(1, 0), nextTableId(), DEFAULT_ZONE_ID),
-                "ID1", Integer.class,
-                "ID2", Integer.class,
-                "VAL", String.class
-        );
-
-        complexTblIndirect.addIndex(new IgniteIndex(
-                TestSortedIndex.create(RelCollations.of(ImmutableIntList.of(0, 1)), "PK", complexTblIndirect)));
+                IgniteDistributions.affinity(ImmutableIntList.of(1, 0), nextTableId(), DEFAULT_ZONE_ID));
 
         IgniteSchema schema = createSchema(complexTblDirect, complexTblIndirect);
 
@@ -217,4 +174,40 @@ public class JoinColocationPlannerTest extends AbstractPlannerTest {
         assertThat(invalidPlanMsg, exchanges.get(0).getInput(0)
                 .getTable().unwrap(TestTable.class), equalTo(complexTblIndirect));
     }
+
+    private static TestTable simpleTable(String tableName, int size) {
+        return TestBuilders.table()
+                .name(tableName)
+                .size(size)
+                .distribution(someAffinity())
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("ID2", NativeTypes.INT32)
+                .addColumn("VAL", NativeTypes.STRING)
+                .sortedIndex()
+                .name("PK")
+                .addColumn("ID", Collation.ASC_NULLS_LAST)
+                .end()
+                .build();
+    }
+
+    private static TestTable complexTbl(String tableName) {
+        return complexTbl(tableName, DEFAULT_TBL_SIZE,
+                IgniteDistributions.affinity(ImmutableIntList.of(0, 1), nextTableId(), DEFAULT_ZONE_ID));
+    }
+
+    private static TestTable complexTbl(String tableName, int size, IgniteDistribution distribution) {
+        return TestBuilders.table()
+                .name(tableName)
+                .size(size)
+                .distribution(distribution)
+                .addColumn("ID1", NativeTypes.INT32)
+                .addColumn("ID2", NativeTypes.INT32)
+                .addColumn("VAL", NativeTypes.STRING)
+                .sortedIndex()
+                .name("PK")
+                .addColumn("ID1", Collation.ASC_NULLS_LAST)
+                .addColumn("ID2", Collation.ASC_NULLS_LAST)
+                .end()
+                .build();
+    }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/JoinCommutePlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/JoinCommutePlannerTest.java
index bf59930835..fe6dc5e8a1 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/JoinCommutePlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/JoinCommutePlannerTest.java
@@ -35,7 +35,6 @@ import org.apache.calcite.rel.rules.CoreRules;
 import org.apache.calcite.rel.rules.FilterJoinRule.JoinConditionPushRule;
 import org.apache.calcite.rel.rules.FilterJoinRule.JoinConditionPushRule.JoinConditionPushRuleConfig;
 import org.apache.calcite.rel.rules.JoinCommuteRule;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.ignite.internal.schema.NativeTypes;
 import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
 import org.apache.ignite.internal.sql.engine.prepare.PlanningContext;
@@ -45,7 +44,6 @@ import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
 import org.apache.ignite.internal.sql.engine.rel.IgniteTableScan;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
 import org.apache.ignite.internal.sql.engine.schema.IgniteTable;
-import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Disabled;
@@ -63,28 +61,18 @@ public class JoinCommutePlannerTest extends AbstractPlannerTest {
     @BeforeAll
     public static void init() {
         publicSchema = createSchema(
-                new TestTable(
-                        "HUGE",
-                        new RelDataTypeFactory.Builder(TYPE_FACTORY)
-                                .add("ID", TYPE_FACTORY.createJavaType(Integer.class))
-                                .build(), 1_000) {
-
-                    @Override
-                    public IgniteDistribution distribution() {
-                        return IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID);
-                    }
-                },
-                new TestTable(
-                        "SMALL",
-                        new RelDataTypeFactory.Builder(TYPE_FACTORY)
-                                .add("ID", TYPE_FACTORY.createJavaType(Integer.class))
-                                .build(), 10) {
-
-                    @Override
-                    public IgniteDistribution distribution() {
-                        return IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID);
-                    }
-                }
+                TestBuilders.table()
+                        .name("HUGE")
+                        .addColumn("ID", NativeTypes.INT32)
+                        .distribution(IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID))
+                        .size(1_000)
+                        .build(),
+                TestBuilders.table()
+                        .name("SMALL")
+                        .addColumn("ID", NativeTypes.INT32)
+                        .distribution(IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID))
+                        .size(10)
+                        .build()
         );
     }
 
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/JoinWithUsingPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/JoinWithUsingPlannerTest.java
index ddfb0aec8e..b527352070 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/JoinWithUsingPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/JoinWithUsingPlannerTest.java
@@ -17,9 +17,11 @@
 
 package org.apache.ignite.internal.sql.engine.planner;
 
-import java.sql.Date;
 import java.util.ArrayList;
 import java.util.Collection;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestTable;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
 import org.junit.jupiter.api.BeforeAll;
@@ -34,20 +36,44 @@ public class JoinWithUsingPlannerTest extends AbstractPlannerTest {
 
     @BeforeAll
     public static void init() {
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-        IgniteSchema otherSchema = new IgniteSchema("OTHER");
-
-        createTable(publicSchema, "T1", IgniteDistributions.random(),
-                "EMPID", Integer.class, "DEPTID", Integer.class, "NAME", String.class);
-        createTable(publicSchema, "T2", IgniteDistributions.random(),
-                "DEPTID", Integer.class, "NAME", String.class, "PARENTID", Integer.class);
-        createTable(otherSchema, "T3", IgniteDistributions.random(),
-                "EMPID", Integer.class, "DEPTID", Integer.class, "D", Date.class);
+        IgniteSchema publicSchema = createSchema("PUBLIC",
+                TestBuilders.table().name("T1")
+                        .addColumn("EMPID", NativeTypes.INT32)
+                        .addColumn("DEPTID", NativeTypes.INT32)
+                        .addColumn("NAME", NativeTypes.STRING)
+                        .distribution(IgniteDistributions.random())
+                        .build(),
+                TestBuilders.table().name("T2")
+                        .addColumn("DEPTID", NativeTypes.INT32)
+                        .addColumn("NAME", NativeTypes.STRING)
+                        .addColumn("PARENTID", NativeTypes.INT32)
+                        .distribution(IgniteDistributions.random())
+                        .build()
+        );
+
+        IgniteSchema otherSchema = createSchema("OTHER",
+                TestBuilders.table().name("T3")
+                        .addColumn("EMPID", NativeTypes.INT32)
+                        .addColumn("DEPTID", NativeTypes.INT32)
+                        .addColumn("D", NativeTypes.DATE)
+                        .distribution(IgniteDistributions.random())
+                        .build()
+        );
 
         schemas.add(publicSchema);
         schemas.add(otherSchema);
     }
 
+    private static IgniteSchema createSchema(String schemaName, TestTable... tables) {
+        IgniteSchema schema = new IgniteSchema(schemaName);
+
+        for (TestTable table : tables) {
+            schema.addTable(table);
+        }
+
+        return schema;
+    }
+
     @Test
     public void testJoinWithUsing() throws Exception {
         // Join tables without aliases.
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 8c82c52da1..8e5dba7441 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
@@ -19,9 +19,10 @@ 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;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 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;
@@ -31,9 +32,6 @@ 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;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
-import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.internal.sql.engine.util.Commons;
-import org.apache.ignite.internal.util.ArrayUtils;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -41,7 +39,7 @@ import org.junit.jupiter.api.Test;
  */
 public class LimitOffsetPlannerTest extends AbstractPlannerTest {
     /** Rows count in table. */
-    private static final double ROW_CNT = 100d;
+    private static final int ROW_CNT = 100;
 
     @Test
     public void testLimit() throws Exception {
@@ -168,7 +166,7 @@ public class LimitOffsetPlannerTest extends AbstractPlannerTest {
                                         .and(s -> doubleFromRex(s.offset, -1) == 1)
                                         .and(s -> doubleFromRex(s.fetch, -1) == 1)))))));
 
-        publicSchema = createSchemaWithTable(IgniteDistributions.random(), 0);
+        publicSchema = createSchemaWithTable(IgniteDistributions.random(), "ID");
 
         // Sort node is not required, since collation of the Limit node equals to the index collation.
         assertPlan("SELECT * FROM TEST ORDER BY ID LIMIT 10 OFFSET 10", publicSchema,
@@ -177,7 +175,7 @@ public class LimitOffsetPlannerTest extends AbstractPlannerTest {
                         .and(input(isInstanceOf(IgniteIndexScan.class)))))
                     .and(hasChildThat(isInstanceOf(IgniteSort.class)).negate()));
 
-        publicSchema = createSchemaWithTable(IgniteDistributions.random(), 0, 1);
+        publicSchema = createSchemaWithTable(IgniteDistributions.random(), "ID", "VAL");
 
         // Sort node is not required, since collation of the Limit node satisfies the index collation.
         assertPlan("SELECT * FROM TEST ORDER BY ID LIMIT 10 OFFSET 10", publicSchema,
@@ -198,24 +196,18 @@ public class LimitOffsetPlannerTest extends AbstractPlannerTest {
     /**
      * Creates PUBLIC schema with one TEST table.
      */
-    private IgniteSchema createSchemaWithTable(IgniteDistribution distr, int... indexedColumns) {
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        RelDataType type = new RelDataTypeFactory.Builder(f)
-                .add("ID", f.createJavaType(Integer.class))
-                .add("VAL", f.createJavaType(String.class))
-                .build();
-
-        TestTable table = new TestTable("TEST", type, ROW_CNT) {
-            @Override public IgniteDistribution distribution() {
-                return distr;
-            }
-        };
-
-        if (!ArrayUtils.nullOrEmpty(indexedColumns)) {
-            table.addIndex("test_idx", indexedColumns);
+    private static IgniteSchema createSchemaWithTable(IgniteDistribution distr, String... indexesColumns) {
+        TableBuilder builder = TestBuilders.table()
+                .name("TEST")
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("VAL", NativeTypes.STRING)
+                .size(ROW_CNT)
+                .distribution(distr);
+
+        if (indexesColumns.length > 0) {
+            addSortIndex(indexesColumns).apply(builder);
         }
 
-        return createSchema(table);
+        return createSchema(builder.build());
     }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/MapReduceSortAggregatePlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/MapReduceSortAggregatePlannerTest.java
index d4c6fd7171..40488cd113 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/MapReduceSortAggregatePlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/MapReduceSortAggregatePlannerTest.java
@@ -168,7 +168,7 @@ public class MapReduceSortAggregatePlannerTest extends AbstractAggregatePlannerT
                         .and(input(isInstanceOf(IgniteMapSortAggregate.class)
                                 .and(not(hasAggregate()))
                                 .and(hasGroups())
-                                .and(input(isIndexScan("TEST", "grp0_grp1")))
+                                .and(input(isIndexScan("TEST", "idx_grp0_grp1")))
                         ))
                 ),
                 disableRules
@@ -182,7 +182,7 @@ public class MapReduceSortAggregatePlannerTest extends AbstractAggregatePlannerT
                                 .and(input(isInstanceOf(IgniteMapSortAggregate.class)
                                         .and(not(hasAggregate()))
                                         .and(hasGroups())
-                                        .and(input(isIndexScan("TEST", "grp0_grp1")))
+                                        .and(input(isIndexScan("TEST", "idx_grp0_grp1")))
                                 ))
                         ))
                 ),
@@ -218,7 +218,7 @@ public class MapReduceSortAggregatePlannerTest extends AbstractAggregatePlannerT
         assertPlan(TestCase.CASE_16,
                 nodeOrAnyChild(isInstanceOf(IgniteReduceSortAggregate.class)
                         .and(input(isInstanceOf(IgniteMapSortAggregate.class)
-                                .and(input(isIndexScan("TEST", "val0")))
+                                .and(input(isIndexScan("TEST", "idx_val0")))
                         ))
                 ),
                 ArrayUtils.concat(disableRules, additionalRulesToDisable)
@@ -228,7 +228,7 @@ public class MapReduceSortAggregatePlannerTest extends AbstractAggregatePlannerT
                 nodeOrAnyChild(isInstanceOf(IgniteReduceSortAggregate.class)
                         .and(input(isInstanceOf(IgniteExchange.class)
                                 .and(input(isInstanceOf(IgniteMapSortAggregate.class)
-                                        .and(input(isIndexScan("TEST", "val0")))
+                                        .and(input(isIndexScan("TEST", "idx_val0")))
                                 ))
                         ))
                 ),
@@ -526,7 +526,7 @@ public class MapReduceSortAggregatePlannerTest extends AbstractAggregatePlannerT
                 nodeOrAnyChild(isInstanceOf(IgniteReduceSortAggregate.class)
                         .and(input(isInstanceOf(IgniteMapSortAggregate.class)
                                 .and(hasAggregate())
-                                .and(input(isIndexScan("TEST", "grp0_grp1")))
+                                .and(input(isIndexScan("TEST", "idx_grp0_grp1")))
                         ))
                 ),
                 disableRules
@@ -539,7 +539,7 @@ public class MapReduceSortAggregatePlannerTest extends AbstractAggregatePlannerT
                         .and(input(isInstanceOf(IgniteExchange.class)
                                 .and(input(isInstanceOf(IgniteMapSortAggregate.class)
                                         .and(hasAggregate())
-                                        .and(input(isIndexScan("TEST", "grp0_grp1")))
+                                        .and(input(isIndexScan("TEST", "idx_grp0_grp1")))
                                 ))
                         ))
                 ),
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/MergeJoinPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/MergeJoinPlannerTest.java
index abe724a8ab..0a84a14c23 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/MergeJoinPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/MergeJoinPlannerTest.java
@@ -23,13 +23,19 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 
 import java.util.List;
+import java.util.function.Consumer;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.core.Join;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
+import org.apache.ignite.internal.sql.engine.framework.TestTable;
 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.IgniteTableScan;
+import org.apache.ignite.internal.sql.engine.schema.IgniteIndex.Collation;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
 import org.junit.jupiter.api.Test;
@@ -54,8 +60,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByLeft1() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -91,8 +97,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByLeft2() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -128,8 +134,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByLeft3() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -165,8 +171,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByLeft4() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -202,8 +208,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByLeft5() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -232,16 +238,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     /**
      * Test verifies the collation propagation from a parent node.
      *
-     * <p>In case of inner join, collation that is superset of join keys should be propagated as is, if it doesn't include fields from right
-     * table.
+     * <p>In case of inner join, collation that is superset of join keys should be propagated as is, if it doesn't include fields from
+     * right table.
      *
      * @throws Exception In case of any unexpected error.
      */
     @Test
     public void testInnerPassThroughOrderByLeft6() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -278,16 +284,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     /**
      * Test verifies the collation propagation from a parent node.
      *
-     * <p>In case of inner join, collation that is superset of join keys should be propagated as is, if it doesn't include fields from right
-     * table.
+     * <p>In case of inner join, collation that is superset of join keys should be propagated as is, if it doesn't include fields from
+     * right table.
      *
      * @throws Exception In case of any unexpected error.
      */
     @Test
     public void testInnerPassThroughOrderByLeft7() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -324,16 +330,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     /**
      * Test verifies the collation propagation from a parent node.
      *
-     * <p>In case of inner join, collation that is superset of join keys should be propagated as is, if it doesn't include fields from right
-     * table.
+     * <p>In case of inner join, collation that is superset of join keys should be propagated as is, if it doesn't include fields from
+     * right table.
      *
      * @throws Exception In case of any unexpected error.
      */
     @Test
     public void testInnerPassThroughOrderByLeft8() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -370,16 +376,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     /**
      * Test verifies the collation propagation from a parent node.
      *
-     * <p>In case of inner join, collation that is superset of join keys should be propagated as is, if it doesn't include fields from right
-     * table.
+     * <p>In case of inner join, collation that is superset of join keys should be propagated as is, if it doesn't include fields from
+     * right table.
      *
      * @throws Exception In case of any unexpected error.
      */
     @Test
     public void testInnerPassThroughOrderByLeft9() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -416,16 +422,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     /**
      * Test verifies the collation propagation from a parent node.
      *
-     * <p>In case of inner join, collation that is superset of join keys should be propagated as is, if it doesn't include fields from right
-     * table.
+     * <p>In case of inner join, collation that is superset of join keys should be propagated as is, if it doesn't include fields from
+     * right table.
      *
      * @throws Exception In case of any unexpected error.
      */
     @Test
     public void testInnerPassThroughOrderByLeft10() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -470,8 +476,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByLeft11() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -523,8 +529,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByLeft12() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -562,8 +568,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByLeft13() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -601,8 +607,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByLeft14() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -640,8 +646,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByLeft15() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -679,8 +685,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByLeft16() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -718,8 +724,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByRight1() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -755,8 +761,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByRight2() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -792,8 +798,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByRight3() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -829,8 +835,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByRight4() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -866,8 +872,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByRight5() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -903,8 +909,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByRight6() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -949,8 +955,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByRight7() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -988,8 +994,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByRight8() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1027,8 +1033,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByRight9() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1066,8 +1072,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByRight10() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1105,8 +1111,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testInnerPassThroughOrderByRight11() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1144,8 +1150,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testRightPassThroughOrderByLeft1() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1189,8 +1195,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testRightPassThroughOrderByLeft2() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1235,8 +1241,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testRightPassThroughOrderByRight1() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1272,8 +1278,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testRightPassThroughOrderByRight2() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1309,8 +1315,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testRightPassThroughOrderByRight3() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1346,8 +1352,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testRightPassThroughOrderByRight4() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1383,8 +1389,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testRightPassThroughOrderByRight5() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1420,8 +1426,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testLeftPassThroughOrderByRight1() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1463,8 +1469,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testLeftPassThroughOrderByRight2() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1508,8 +1514,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testFullPassThroughOrderByLeft1() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1551,8 +1557,8 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     @Test
     public void testFullPassThroughOrderByRight1() throws Exception {
         IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
+                createTableA("LEFT_T"),
+                createTableA("RIGHT_T")
         );
 
         String sql = ""
@@ -1593,21 +1599,15 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveLeft1() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING),
-                        new RelFieldCollation(1, ASCENDING)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.ASC_NULLS_LAST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                left,
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
-        );
+        IgniteSchema schema = createSchema(left, createTableB("RIGHT_T"));
 
         String sql = ""
                 + "select * "
@@ -1637,21 +1637,15 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveLeft2() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, DESCENDING),
-                        new RelFieldCollation(1, DESCENDING)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.DESC_NULLS_FIRST)
+                        .addColumn("C2", Collation.DESC_NULLS_FIRST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                left,
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
-        );
+        IgniteSchema schema = createSchema(left, createTableB("RIGHT_T"));
 
         String sql = ""
                 + "select * "
@@ -1681,21 +1675,15 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveLeft3() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, DESCENDING),
-                        new RelFieldCollation(1, ASCENDING)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.DESC_NULLS_FIRST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                left,
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
-        );
+        IgniteSchema schema = createSchema(left, createTableB("RIGHT_T"));
 
         String sql = ""
                 + "select * "
@@ -1725,21 +1713,15 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveLeft4() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING, RelFieldCollation.NullDirection.LAST),
-                        new RelFieldCollation(1, ASCENDING, RelFieldCollation.NullDirection.LAST)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.ASC_NULLS_LAST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                left,
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
-        );
+        IgniteSchema schema = createSchema(left, createTableB("RIGHT_T"));
 
         String sql = ""
                 + "select * "
@@ -1769,21 +1751,15 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveLeft5() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING, RelFieldCollation.NullDirection.FIRST),
-                        new RelFieldCollation(1, ASCENDING)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.ASC_NULLS_FIRST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                left,
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
-        );
+        IgniteSchema schema = createSchema(left, createTableB("RIGHT_T"));
 
         String sql = ""
                 + "select * "
@@ -1813,22 +1789,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveLeft6() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING),
-                        new RelFieldCollation(1, ASCENDING),
-                        new RelFieldCollation(2, ASCENDING)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.ASC_NULLS_LAST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .addColumn("C3", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                left,
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
-        );
+        IgniteSchema schema = createSchema(left, createTableB("RIGHT_T"));
 
         String sql = "select * "
                 + "  from LEFT_T "
@@ -1857,22 +1827,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveLeft7() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, DESCENDING),
-                        new RelFieldCollation(1, DESCENDING),
-                        new RelFieldCollation(2, DESCENDING)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.DESC_NULLS_FIRST)
+                        .addColumn("C2", Collation.DESC_NULLS_FIRST)
+                        .addColumn("C3", Collation.DESC_NULLS_FIRST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                left,
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
-        );
+        IgniteSchema schema = createSchema(left, createTableB("RIGHT_T"));
 
         String sql = ""
                 + "select * "
@@ -1902,22 +1866,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveLeft8() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, DESCENDING),
-                        new RelFieldCollation(1, ASCENDING),
-                        new RelFieldCollation(2, ASCENDING)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.DESC_NULLS_FIRST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .addColumn("C3", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                left,
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
-        );
+        IgniteSchema schema = createSchema(left, createTableB("RIGHT_T"));
 
         String sql = ""
                 + "select * "
@@ -1948,22 +1906,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveLeft9() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(2, ASCENDING),
-                        new RelFieldCollation(0, ASCENDING),
-                        new RelFieldCollation(1, ASCENDING)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C3", Collation.ASC_NULLS_LAST)
+                        .addColumn("C1", Collation.ASC_NULLS_LAST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                left,
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
-        );
+        IgniteSchema schema = createSchema(left, createTableB("RIGHT_T"));
 
         String sql = ""
                 + "select * "
@@ -1999,22 +1951,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveLeft10() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING, RelFieldCollation.NullDirection.FIRST),
-                        new RelFieldCollation(1, ASCENDING),
-                        new RelFieldCollation(2, ASCENDING)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.ASC_NULLS_FIRST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .addColumn("C3", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                left,
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
-        );
+        IgniteSchema schema = createSchema(left, createTableB("RIGHT_T"));
 
         String sql = ""
                 + "select * "
@@ -2044,21 +1990,15 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveLeft11() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING),
-                        new RelFieldCollation(1, ASCENDING)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.ASC_NULLS_LAST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                left,
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
-        );
+        IgniteSchema schema = createSchema(left, createTableB("RIGHT_T"));
 
         String sql = ""
                 + "select * "
@@ -2097,22 +2037,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveLeft12() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING),
-                        new RelFieldCollation(1, ASCENDING),
-                        new RelFieldCollation(2, ASCENDING)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.ASC_NULLS_LAST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .addColumn("C3", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                left,
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
-        );
+        IgniteSchema schema = createSchema(left, createTableB("RIGHT_T"));
 
         String sql = ""
                 + "select * "
@@ -2145,22 +2079,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveLeft13() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(2, ASCENDING),
-                        new RelFieldCollation(0, ASCENDING),
-                        new RelFieldCollation(1, ASCENDING)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C3", Collation.ASC_NULLS_LAST)
+                        .addColumn("C1", Collation.ASC_NULLS_LAST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                left,
-                createTable("RIGHT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class)
-        );
+        IgniteSchema schema = createSchema(left, createTableB("RIGHT_T"));
 
         String sql = ""
                 + "select * "
@@ -2199,21 +2127,15 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveRight1() throws Exception {
-        TestTable right = createTable("RIGHT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
+        TestTable right = createTableB("RIGHT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.ASC_NULLS_LAST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .end()
+                );
 
-        right.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING),
-                        new RelFieldCollation(1, ASCENDING)
-                ),
-                "idx"
-        );
-
-        IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                right
-        );
+        IgniteSchema schema = createSchema(createTableB("LEFT_T"), right);
 
         String sql = ""
                 + "select * "
@@ -2243,21 +2165,15 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveRight2() throws Exception {
-        TestTable right = createTable("RIGHT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        right.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, DESCENDING),
-                        new RelFieldCollation(1, DESCENDING)
-                ),
-                "idx"
+        TestTable right = createTableB("RIGHT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.DESC_NULLS_FIRST)
+                        .addColumn("C2", Collation.DESC_NULLS_FIRST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                right
-        );
+        IgniteSchema schema = createSchema(createTableB("LEFT_T"), right);
 
         String sql = ""
                 + "select * "
@@ -2287,21 +2203,15 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveRight3() throws Exception {
-        TestTable right = createTable("RIGHT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        right.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, DESCENDING, RelFieldCollation.NullDirection.LAST),
-                        new RelFieldCollation(1, ASCENDING, RelFieldCollation.NullDirection.FIRST)
-                ),
-                "idx"
+        TestTable right = createTableB("RIGHT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.DESC_NULLS_LAST)
+                        .addColumn("C2", Collation.ASC_NULLS_FIRST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                right
-        );
+        IgniteSchema schema = createSchema(createTableB("LEFT_T"), right);
 
         String sql = ""
                 + "select * "
@@ -2331,21 +2241,15 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveRight4() throws Exception {
-        TestTable right = createTable("RIGHT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        right.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING, RelFieldCollation.NullDirection.FIRST),
-                        new RelFieldCollation(1, ASCENDING, RelFieldCollation.NullDirection.FIRST)
-                ),
-                "idx"
+        TestTable right = createTableB("RIGHT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.ASC_NULLS_FIRST)
+                        .addColumn("C2", Collation.ASC_NULLS_FIRST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                right
-        );
+        IgniteSchema schema = createSchema(createTableB("LEFT_T"), right);
 
         String sql = ""
                 + "select * "
@@ -2375,21 +2279,15 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveRight5() throws Exception {
-        TestTable right = createTable("RIGHT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        right.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING, RelFieldCollation.NullDirection.FIRST),
-                        new RelFieldCollation(1, ASCENDING, RelFieldCollation.NullDirection.FIRST)
-                ),
-                "idx"
+        TestTable right = createTableB("RIGHT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.ASC_NULLS_FIRST)
+                        .addColumn("C2", Collation.ASC_NULLS_FIRST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                right
-        );
+        IgniteSchema schema = createSchema(createTableB("LEFT_T"), right);
 
         String sql = ""
                 + "select * "
@@ -2419,22 +2317,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveRight6() throws Exception {
-        TestTable right = createTable("RIGHT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        right.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING, RelFieldCollation.NullDirection.FIRST),
-                        new RelFieldCollation(1, ASCENDING, RelFieldCollation.NullDirection.FIRST),
-                        new RelFieldCollation(2, ASCENDING, RelFieldCollation.NullDirection.FIRST)
-                ),
-                "idx"
+        TestTable right = createTableB("RIGHT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.ASC_NULLS_FIRST)
+                        .addColumn("C2", Collation.ASC_NULLS_FIRST)
+                        .addColumn("C3", Collation.ASC_NULLS_FIRST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                right
-        );
+        IgniteSchema schema = createSchema(createTableB("LEFT_T"), right);
 
         String sql = ""
                 + "select * "
@@ -2464,22 +2356,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveRight7() throws Exception {
-        TestTable right = createTable("RIGHT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        right.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, DESCENDING, RelFieldCollation.NullDirection.LAST),
-                        new RelFieldCollation(1, DESCENDING, RelFieldCollation.NullDirection.LAST),
-                        new RelFieldCollation(2, DESCENDING, RelFieldCollation.NullDirection.LAST)
-                ),
-                "idx"
+        TestTable right = createTableB("RIGHT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.DESC_NULLS_LAST)
+                        .addColumn("C2", Collation.DESC_NULLS_LAST)
+                        .addColumn("C3", Collation.DESC_NULLS_FIRST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                right
-        );
+        IgniteSchema schema = createSchema(createTableB("LEFT_T"), right);
 
         String sql = ""
                 + "select * "
@@ -2509,22 +2395,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveRight8() throws Exception {
-        TestTable right = createTable("RIGHT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        right.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, DESCENDING, RelFieldCollation.NullDirection.LAST),
-                        new RelFieldCollation(1, ASCENDING, RelFieldCollation.NullDirection.FIRST),
-                        new RelFieldCollation(2, ASCENDING, RelFieldCollation.NullDirection.FIRST)
-                ),
-                "idx"
+        TestTable right = createTableB("RIGHT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.DESC_NULLS_LAST)
+                        .addColumn("C2", Collation.ASC_NULLS_FIRST)
+                        .addColumn("C3", Collation.ASC_NULLS_FIRST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                right
-        );
+        IgniteSchema schema = createSchema(createTableB("LEFT_T"), right);
 
         String sql = ""
                 + "select * "
@@ -2554,22 +2434,16 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveRight9() throws Exception {
-        TestTable right = createTable("RIGHT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        right.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING, RelFieldCollation.NullDirection.FIRST),
-                        new RelFieldCollation(1, ASCENDING, RelFieldCollation.NullDirection.FIRST),
-                        new RelFieldCollation(2, ASCENDING, RelFieldCollation.NullDirection.FIRST)
-                ),
-                "idx"
+        TestTable right = createTableB("RIGHT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.ASC_NULLS_FIRST)
+                        .addColumn("C2", Collation.ASC_NULLS_FIRST)
+                        .addColumn("C3", Collation.ASC_NULLS_FIRST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                right
-        );
+        IgniteSchema schema = createSchema(createTableB("LEFT_T"), right);
 
         String sql = ""
                 + "select * "
@@ -2599,21 +2473,15 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDerivePreserveRight10() throws Exception {
-        TestTable right = createTable("RIGHT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        right.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING),
-                        new RelFieldCollation(1, ASCENDING)
-                ),
-                "idx"
+        TestTable right = createTableB("RIGHT_T",
+                b -> b.sortedIndex()
+                        .name("idx")
+                        .addColumn("C1", Collation.ASC_NULLS_LAST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
-        IgniteSchema schema = createSchema(
-                createTable("LEFT_T", IgniteDistributions.single(), "C1", Integer.class, "C2", Integer.class, "C3", Integer.class),
-                right
-        );
+        IgniteSchema schema = createSchema(createTableB("LEFT_T"), right);
 
         String sql = ""
                 + "select * "
@@ -2652,26 +2520,20 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDeriveMixed1() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING),
-                        new RelFieldCollation(1, ASCENDING)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx1")
+                        .addColumn("C1", Collation.ASC_NULLS_LAST)
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
-        TestTable right = createTable("RIGHT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        right.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(1, ASCENDING),
-                        new RelFieldCollation(0, ASCENDING)
-                ),
-                "idx"
+        TestTable right = createTableB("RIGHT_T",
+                b -> b.sortedIndex()
+                        .name("idx2")
+                        .addColumn("C2", Collation.ASC_NULLS_LAST)
+                        .addColumn("C1", Collation.ASC_NULLS_LAST)
+                        .end()
         );
 
         IgniteSchema schema = createSchema(left, right);
@@ -2704,27 +2566,21 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testInnerDeriveMixed2() throws Exception {
-        TestTable left = createTable("LEFT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        left.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(0, ASCENDING, RelFieldCollation.NullDirection.FIRST),
-                        new RelFieldCollation(1, ASCENDING, RelFieldCollation.NullDirection.FIRST)
-                ),
-                "idx"
+        TestTable left = createTableB("LEFT_T",
+                b -> b.sortedIndex()
+                        .name("idx1")
+                        .addColumn("C1", Collation.ASC_NULLS_FIRST)
+                        .addColumn("C2", Collation.ASC_NULLS_FIRST)
+                        .end()
         );
 
-        TestTable right = createTable("RIGHT_T", IgniteDistributions.single(),
-                "C1", Integer.class, "C2", Integer.class, "C3", Integer.class);
-
-        right.addIndex(
-                RelCollations.of(
-                        new RelFieldCollation(2, ASCENDING, RelFieldCollation.NullDirection.FIRST),
-                        new RelFieldCollation(1, ASCENDING, RelFieldCollation.NullDirection.FIRST),
-                        new RelFieldCollation(0, ASCENDING, RelFieldCollation.NullDirection.FIRST)
-                ),
-                "idx"
+        TestTable right = createTableB("RIGHT_T",
+                b -> b.sortedIndex()
+                        .name("idx2")
+                        .addColumn("C3", Collation.ASC_NULLS_FIRST)
+                        .addColumn("C2", Collation.ASC_NULLS_FIRST)
+                        .addColumn("C1", Collation.ASC_NULLS_FIRST)
+                        .end()
         );
 
         IgniteSchema schema = createSchema(left, right);
@@ -2764,7 +2620,7 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
     /**
      * Search for sort node whose input is scan of the given table.
      *
-     * @param root      The root of the tree to search.
+     * @param root The root of the tree to search.
      * @param tableName Desired table name.
      * @return The sort node or {@code null}, if there is no such node.
      */
@@ -2796,4 +2652,32 @@ public class MergeJoinPlannerTest extends AbstractPlannerTest {
 
         return sortNodes.isEmpty() ? null : sortNodes.get(0);
     }
+
+    private static TestTable createTableA(String tableName) {
+        return TestBuilders.table()
+                .name(tableName)
+                .addColumn("C1", NativeTypes.INT32)
+                .addColumn("C2", NativeTypes.INT32)
+                .addColumn("C3", NativeTypes.INT32)
+                .distribution(IgniteDistributions.single())
+                .build();
+    }
+
+    private static TestTable createTableB(String tableName) {
+        return createTableB(tableName, ignore -> {
+        });
+    }
+
+    private static TestTable createTableB(String tableName, Consumer<TableBuilder> changer) {
+        TableBuilder tableBuilder = TestBuilders.table()
+                .name(tableName)
+                .distribution(IgniteDistributions.single())
+                .addColumn("C1", NativeTypes.INT32)
+                .addColumn("C2", NativeTypes.INT32)
+                .addColumn("C3", NativeTypes.INT32);
+
+        changer.accept(tableBuilder);
+
+        return tableBuilder.build();
+    }
 }
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 774436963a..2729786b9d 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
@@ -26,27 +26,24 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelRoot;
-import org.apache.calcite.rel.RelVisitor;
 import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.hint.HintStrategyTable;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.sql.SqlNode;
-import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Util;
+import org.apache.ignite.internal.schema.NativeTypes;
 import org.apache.ignite.internal.sql.api.ResultSetMetadataImpl;
 import org.apache.ignite.internal.sql.engine.SqlQueryType;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 import org.apache.ignite.internal.sql.engine.metadata.ColocationGroup;
 import org.apache.ignite.internal.sql.engine.metadata.FragmentMapping;
 import org.apache.ignite.internal.sql.engine.metadata.MappingService;
@@ -54,7 +51,6 @@ import org.apache.ignite.internal.sql.engine.metadata.NodeWithTerm;
 import org.apache.ignite.internal.sql.engine.metadata.cost.IgniteCostFactory;
 import org.apache.ignite.internal.sql.engine.prepare.Fragment;
 import org.apache.ignite.internal.sql.engine.prepare.IgnitePlanner;
-import org.apache.ignite.internal.sql.engine.prepare.IgniteRelShuttle;
 import org.apache.ignite.internal.sql.engine.prepare.MappingQueryContext;
 import org.apache.ignite.internal.sql.engine.prepare.MultiStepPlan;
 import org.apache.ignite.internal.sql.engine.prepare.PlannerPhase;
@@ -62,17 +58,13 @@ 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.rel.IgniteConvention;
 import org.apache.ignite.internal.sql.engine.rel.IgniteFilter;
-import org.apache.ignite.internal.sql.engine.rel.IgniteIndexScan;
 import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
-import org.apache.ignite.internal.sql.engine.rel.IgniteTableModify;
 import org.apache.ignite.internal.sql.engine.rel.IgniteTableScan;
-import org.apache.ignite.internal.sql.engine.schema.IgniteIndex;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
+import org.apache.ignite.internal.sql.engine.schema.IgniteTable;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
-import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
 import org.apache.ignite.internal.sql.engine.util.BaseQueryContext;
-import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.apache.ignite.internal.util.CollectionUtils;
 import org.apache.ignite.network.ClusterNode;
 import org.jetbrains.annotations.Nullable;
@@ -87,6 +79,10 @@ import org.junit.jupiter.api.condition.OS;
  */
 @DisabledOnOs(value = OS.WINDOWS, disabledReason = "https://issues.apache.org/jira/browse/IGNITE-17601")
 public class PlannerTest extends AbstractPlannerTest {
+    private static final String DEVELOPER_TABLE = "DEVELOPER";
+
+    private static final String PROJECT_TABLE = "PROJECT";
+
     private static List<String> NODES;
 
     private static List<NodeWithTerm> NODES_WITH_TERM;
@@ -110,59 +106,26 @@ public class PlannerTest extends AbstractPlannerTest {
 
     @Test
     public void testSplitterColocatedPartitionedPartitioned() throws Exception {
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        TestTable developer = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("PROJECTID", f.createJavaType(Integer.class))
-                        .build(), "DEVELOPER") {
-            @Override
-            public IgniteIndex getIndex(String idxName) {
-                throw new AssertionError("Should not be called");
-            }
-
-            @Override
-            public ColocationGroup colocationGroup() {
-                return ColocationGroup.forAssignments(Arrays.asList(
-                        select(NODES_WITH_TERM, 0, 1),
-                        select(NODES_WITH_TERM, 1, 2),
-                        select(NODES_WITH_TERM, 2, 0),
-                        select(NODES_WITH_TERM, 0, 1),
-                        select(NODES_WITH_TERM, 1, 2)
-                ));
-            }
-
-            @Override public IgniteDistribution distribution() {
-                return IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID);
-            }
-        };
+        ColocationGroup partitionedGroup = ColocationGroup.forAssignments(Arrays.asList(
+                select(NODES_WITH_TERM, 0, 1),
+                select(NODES_WITH_TERM, 1, 2),
+                select(NODES_WITH_TERM, 2, 0),
+                select(NODES_WITH_TERM, 0, 1),
+                select(NODES_WITH_TERM, 1, 2)
+        ));
+
+        IgniteSchema publicSchema = createSchemaFrom(
+                developerTable(IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID)),
+                projectsTable(IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID))
+        );
 
-        TestTable project = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                    .add("ID", f.createJavaType(Integer.class))
-                    .add("NAME", f.createJavaType(String.class))
-                    .add("VER", f.createJavaType(Integer.class))
-                    .build(), "PROJECT") {
-            @Override public ColocationGroup colocationGroup() {
-                return ColocationGroup.forAssignments(Arrays.asList(
-                    select(NODES_WITH_TERM, 0, 1),
-                    select(NODES_WITH_TERM, 1, 2),
-                    select(NODES_WITH_TERM, 2, 0),
-                    select(NODES_WITH_TERM, 0, 1),
-                    select(NODES_WITH_TERM, 1, 2)));
-            }
-
-            @Override public IgniteDistribution distribution() {
-                return IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID);
-            }
-        };
+        int developerTableId = ((IgniteTable) publicSchema.getTable(DEVELOPER_TABLE)).id();
+        int projectTableId = ((IgniteTable) publicSchema.getTable(PROJECT_TABLE)).id();
 
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-
-        publicSchema.addTable(developer);
-        publicSchema.addTable(project);
+        Map<Integer, ColocationGroup> colocationGroups = Map.of(
+                developerTableId, partitionedGroup,
+                projectTableId, partitionedGroup
+        );
 
         SchemaPlus schema = createRootSchema(false)
                 .add("PUBLIC", publicSchema);
@@ -173,15 +136,7 @@ public class PlannerTest extends AbstractPlannerTest {
                 + ") p "
                 + "ON d.id = p.id0";
 
-        PlanningContext ctx = PlanningContext.builder()
-                .parentContext(BaseQueryContext.builder()
-                        .logger(log)
-                        .frameworkConfig(newConfigBuilder(FRAMEWORK_CONFIG)
-                                .defaultSchema(schema)
-                                .build())
-                        .build())
-                .query(sql)
-                .build();
+        PlanningContext ctx = plannerContext(schema, sql);
 
         assertNotNull(ctx);
 
@@ -189,7 +144,8 @@ public class PlannerTest extends AbstractPlannerTest {
 
         assertNotNull(phys);
 
-        MultiStepPlan plan = newPlan(phys);
+        MultiStepPlan plan = newPlan(phys,
+                colocationGroups);
 
         assertNotNull(plan);
 
@@ -198,45 +154,20 @@ public class PlannerTest extends AbstractPlannerTest {
 
     @Test
     public void testSplitterColocatedReplicatedReplicated() throws Exception {
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        TestTable developer = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("PROJECTID", f.createJavaType(Integer.class))
-                        .build(), "DEVELOPER") {
-            @Override
-            public ColocationGroup colocationGroup() {
-                return ColocationGroup.forNodes(select(NODES, 0, 1, 2, 3));
-            }
-
-            @Override
-            public IgniteDistribution distribution() {
-                return IgniteDistributions.broadcast();
-            }
-        };
+        ColocationGroup replicatedGroup = ColocationGroup.forNodes(select(NODES, 0, 1, 2, 3));
 
-        TestTable project = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("VER", f.createJavaType(Integer.class))
-                        .build(), "PROJECT") {
-            @Override
-            public ColocationGroup colocationGroup() {
-                return ColocationGroup.forNodes(select(NODES, 0, 1, 2, 3));
-            }
-
-            @Override public IgniteDistribution distribution() {
-                return IgniteDistributions.broadcast();
-            }
-        };
+        IgniteSchema publicSchema = createSchemaFrom(
+                developerTable(IgniteDistributions.broadcast()),
+                projectsTable(IgniteDistributions.broadcast())
+        );
 
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
+        int developerTableId = ((IgniteTable) publicSchema.getTable(DEVELOPER_TABLE)).id();
+        int projectTableId = ((IgniteTable) publicSchema.getTable(PROJECT_TABLE)).id();
 
-        publicSchema.addTable(developer);
-        publicSchema.addTable(project);
+        Map<Integer, ColocationGroup> colocationGroups = Map.of(
+                developerTableId, replicatedGroup,
+                projectTableId, replicatedGroup
+        );
 
         SchemaPlus schema = createRootSchema(false)
                 .add("PUBLIC", publicSchema);
@@ -248,22 +179,13 @@ public class PlannerTest extends AbstractPlannerTest {
                 + "ON d.id = p.id0 "
                 + "WHERE (d.projectId + 1) > ?";
 
-        PlanningContext ctx = PlanningContext.builder()
-                .parentContext(BaseQueryContext.builder()
-                        .logger(log)
-                        .parameters(2)
-                        .frameworkConfig(newConfigBuilder(FRAMEWORK_CONFIG)
-                                .defaultSchema(schema)
-                                .build())
-                        .build())
-                .query(sql)
-                .build();
+        PlanningContext ctx = plannerContext(schema, sql, 2);
 
         IgniteRel phys = physicalPlan(ctx);
 
         assertNotNull(phys);
 
-        MultiStepPlan plan = newPlan(phys);
+        MultiStepPlan plan = newPlan(phys, colocationGroups);
 
         assertNotNull(plan);
 
@@ -272,50 +194,26 @@ public class PlannerTest extends AbstractPlannerTest {
 
     @Test
     public void testSplitterPartiallyColocatedReplicatedAndPartitioned() throws Exception {
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        TestTable developer = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("PROJECTID", f.createJavaType(Integer.class))
-                        .build(), "DEVELOPER") {
-            @Override
-            public ColocationGroup colocationGroup() {
-                return ColocationGroup.forNodes(select(NODES, 0));
-            }
-
-            @Override
-            public IgniteDistribution distribution() {
-                return IgniteDistributions.broadcast();
-            }
-        };
-
-        TestTable project = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("VER", f.createJavaType(Integer.class))
-                        .build(), "PROJECT") {
-            @Override
-            public ColocationGroup colocationGroup() {
-                return ColocationGroup.forAssignments(Arrays.asList(
-                        select(NODES_WITH_TERM, 1, 2),
-                        select(NODES_WITH_TERM, 2, 3),
-                        select(NODES_WITH_TERM, 3, 0),
-                        select(NODES_WITH_TERM, 0, 1)
-                ));
-            }
-
-            @Override public IgniteDistribution distribution() {
-                return IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID);
-            }
-        };
+        ColocationGroup replicatedGroup = ColocationGroup.forNodes(select(NODES, 0));
+        ColocationGroup partitionedGroup = ColocationGroup.forAssignments(Arrays.asList(
+                select(NODES_WITH_TERM, 1, 2),
+                select(NODES_WITH_TERM, 2, 3),
+                select(NODES_WITH_TERM, 3, 0),
+                select(NODES_WITH_TERM, 0, 1)
+        ));
+
+        IgniteSchema publicSchema = createSchemaFrom(
+                developerTable(IgniteDistributions.broadcast()),
+                projectsTable(IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID))
+        );
 
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
+        int developerTableId = ((IgniteTable) publicSchema.getTable(DEVELOPER_TABLE)).id();
+        int projectTableId = ((IgniteTable) publicSchema.getTable(PROJECT_TABLE)).id();
 
-        publicSchema.addTable(developer);
-        publicSchema.addTable(project);
+        Map<Integer, ColocationGroup> colocationGroups = Map.of(
+                developerTableId, replicatedGroup,
+                projectTableId, partitionedGroup
+        );
 
         SchemaPlus schema = createRootSchema(false)
                 .add("PUBLIC", publicSchema);
@@ -327,72 +225,38 @@ public class PlannerTest extends AbstractPlannerTest {
                 + "ON d.id = p.id0 "
                 + "WHERE (d.projectId + 1) > ?";
 
-        PlanningContext ctx = PlanningContext.builder()
-                .parentContext(BaseQueryContext.builder()
-                        .logger(log)
-                        .parameters(2)
-                        .frameworkConfig(newConfigBuilder(FRAMEWORK_CONFIG)
-                                .defaultSchema(schema)
-                                .build())
-                        .build())
-                .query(sql)
-                .build();
+        PlanningContext ctx = plannerContext(schema, sql, 2);
 
         IgniteRel phys = physicalPlan(ctx);
 
         assertNotNull(phys);
 
-        MultiStepPlan plan = newPlan(phys);
+        MultiStepPlan plan = newPlan(phys, colocationGroups);
 
         assertEquals(3, plan.fragments().size());
     }
 
     @Test
     public void testSplitterPartiallyColocated1() throws Exception {
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        TestTable developer = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("PROJECTID", f.createJavaType(Integer.class))
-                        .build(), "DEVELOPER") {
-            @Override
-            public ColocationGroup colocationGroup() {
-                return ColocationGroup.forNodes(select(NODES, 1, 2, 3));
-            }
-
-            @Override
-            public IgniteDistribution distribution() {
-                return IgniteDistributions.broadcast();
-            }
-        };
-
-        TestTable project = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("VER", f.createJavaType(Integer.class))
-                        .build(), "PROJECT") {
-            @Override
-            public ColocationGroup colocationGroup() {
-                return ColocationGroup.forAssignments(Arrays.asList(
-                        select(NODES_WITH_TERM, 0),
-                        select(NODES_WITH_TERM, 1),
-                        select(NODES_WITH_TERM, 2)
-                ));
-            }
-
-            @Override
-            public IgniteDistribution distribution() {
-                return IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID);
-            }
-        };
+        ColocationGroup replicatedGroup = ColocationGroup.forNodes(select(NODES, 1, 2, 3));
+        ColocationGroup partitionedGroup = ColocationGroup.forAssignments(Arrays.asList(
+                select(NODES_WITH_TERM, 0),
+                select(NODES_WITH_TERM, 1),
+                select(NODES_WITH_TERM, 2)
+        ));
+
+        IgniteSchema publicSchema = createSchemaFrom(
+                developerTable(IgniteDistributions.broadcast()),
+                projectsTable(IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID))
+        );
 
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
+        int developerTableId = ((IgniteTable) publicSchema.getTable(DEVELOPER_TABLE)).id();
+        int projectTableId = ((IgniteTable) publicSchema.getTable(PROJECT_TABLE)).id();
 
-        publicSchema.addTable(developer);
-        publicSchema.addTable(project);
+        Map<Integer, ColocationGroup> colocationGroups = Map.of(
+                developerTableId, replicatedGroup,
+                projectTableId, partitionedGroup
+        );
 
         SchemaPlus schema = createRootSchema(false)
                 .add("PUBLIC", publicSchema);
@@ -404,22 +268,13 @@ public class PlannerTest extends AbstractPlannerTest {
                 + "ON d.projectId = p.id0 "
                 + "WHERE (d.projectId + 1) > ?";
 
-        PlanningContext ctx = PlanningContext.builder()
-                .parentContext(BaseQueryContext.builder()
-                        .logger(log)
-                        .parameters(2)
-                        .frameworkConfig(newConfigBuilder(FRAMEWORK_CONFIG)
-                                .defaultSchema(schema)
-                                .build())
-                        .build())
-                .query(sql)
-                .build();
+        PlanningContext ctx = plannerContext(schema, sql, 2);
 
         IgniteRel phys = physicalPlan(ctx);
 
         assertNotNull(phys);
 
-        MultiStepPlan plan = newPlan(phys);
+        MultiStepPlan plan = newPlan(phys, colocationGroups);
 
         assertNotNull(plan);
 
@@ -428,52 +283,28 @@ public class PlannerTest extends AbstractPlannerTest {
 
     @Test
     public void testSplitterPartiallyColocated2() throws Exception {
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        TestTable developer = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("PROJECTID", f.createJavaType(Integer.class))
-                        .build(), "DEVELOPER") {
-            @Override
-            public ColocationGroup colocationGroup() {
-                return ColocationGroup.forNodes(select(NODES, 0));
-            }
-
-            @Override public IgniteDistribution distribution() {
-                return IgniteDistributions.broadcast();
-            }
-        };
-
-        TestTable project = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("VER", f.createJavaType(Integer.class))
-                        .build(), "PROJECT") {
-            @Override
-            public ColocationGroup colocationGroup() {
-                return ColocationGroup.forAssignments(Arrays.asList(
-                        select(NODES_WITH_TERM, 1),
-                        select(NODES_WITH_TERM, 2),
-                        select(NODES_WITH_TERM, 3)
-                ));
-            }
-
-            @Override
-            public IgniteDistribution distribution() {
-                return IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID);
-            }
-        };
+        ColocationGroup replicatedGroup = ColocationGroup.forNodes(select(NODES, 0));
+        ColocationGroup partitionedGroup = ColocationGroup.forAssignments(Arrays.asList(
+                select(NODES_WITH_TERM, 1),
+                select(NODES_WITH_TERM, 2),
+                select(NODES_WITH_TERM, 3)
+        ));
+
+        IgniteSchema publicSchema = createSchemaFrom(
+                developerTable(IgniteDistributions.broadcast()),
+                projectsTable(IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID))
+        );
 
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
+        int developerTableId = ((IgniteTable) publicSchema.getTable(DEVELOPER_TABLE)).id();
+        int projectTableId = ((IgniteTable) publicSchema.getTable(PROJECT_TABLE)).id();
 
-        publicSchema.addTable(developer);
-        publicSchema.addTable(project);
+        Map<Integer, ColocationGroup> colocationGroups = Map.of(
+                developerTableId, replicatedGroup,
+                projectTableId, partitionedGroup
+        );
 
         SchemaPlus schema = createRootSchema(false)
-                  .add("PUBLIC", publicSchema);
+                .add("PUBLIC", publicSchema);
 
         String sql = "SELECT d.id, d.name, d.projectId, p.id0, p.ver0 "
                 + "FROM PUBLIC.Developer d JOIN ("
@@ -482,68 +313,34 @@ public class PlannerTest extends AbstractPlannerTest {
                 + "ON d.projectId = p.id0 "
                 + "WHERE (d.projectId + 1) > ?";
 
-        PlanningContext ctx = PlanningContext.builder()
-                .parentContext(BaseQueryContext.builder()
-                        .logger(log)
-                        .parameters(2)
-                        .frameworkConfig(newConfigBuilder(FRAMEWORK_CONFIG)
-                                .defaultSchema(schema)
-                                .build())
-                        .build())
-                .query(sql)
-                .build();
+        PlanningContext ctx = plannerContext(schema, sql, 2);
 
         IgniteRel phys = physicalPlan(ctx);
 
         assertNotNull(phys);
 
-        MultiStepPlan plan = newPlan(phys);
+        MultiStepPlan plan = newPlan(phys, colocationGroups);
 
         assertEquals(3, plan.fragments().size());
     }
 
     @Test
     public void testSplitterNonColocated() throws Exception {
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        TestTable developer = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("PROJECTID", f.createJavaType(Integer.class))
-                        .build(), "DEVELOPER") {
-            @Override
-            public ColocationGroup colocationGroup() {
-                return ColocationGroup.forNodes(select(NODES, 2));
-            }
-
-            @Override
-            public IgniteDistribution distribution() {
-                return IgniteDistributions.broadcast();
-            }
-        };
+        ColocationGroup developerGroup = ColocationGroup.forNodes(select(NODES, 2));
+        ColocationGroup projectsGroup = ColocationGroup.forNodes(select(NODES, 0, 1));
 
-        TestTable project = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("VER", f.createJavaType(Integer.class))
-                        .build(), "PROJECT") {
-            @Override
-            public ColocationGroup colocationGroup() {
-                return ColocationGroup.forNodes(select(NODES, 0, 1));
-            }
-
-            @Override
-            public IgniteDistribution distribution() {
-                return IgniteDistributions.broadcast();
-            }
-        };
+        IgniteSchema publicSchema = createSchemaFrom(
+                developerTable(IgniteDistributions.broadcast()),
+                projectsTable(IgniteDistributions.broadcast())
+        );
 
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
+        int developerTableId = ((IgniteTable) publicSchema.getTable(DEVELOPER_TABLE)).id();
+        int projectTableId = ((IgniteTable) publicSchema.getTable(PROJECT_TABLE)).id();
 
-        publicSchema.addTable(developer);
-        publicSchema.addTable(project);
+        Map<Integer, ColocationGroup> colocationGroups = Map.of(
+                developerTableId, developerGroup,
+                projectTableId, projectsGroup
+        );
 
         SchemaPlus schema = createRootSchema(false)
                 .add("PUBLIC", publicSchema);
@@ -555,22 +352,13 @@ public class PlannerTest extends AbstractPlannerTest {
                 + "ON d.projectId = p.ver0 "
                 + "WHERE (d.projectId + 1) > ?";
 
-        PlanningContext ctx = PlanningContext.builder()
-                .parentContext(BaseQueryContext.builder()
-                        .logger(log)
-                        .parameters(2)
-                        .frameworkConfig(newConfigBuilder(FRAMEWORK_CONFIG)
-                                .defaultSchema(schema)
-                                .build())
-                        .build())
-                .query(sql)
-                .build();
+        PlanningContext ctx = plannerContext(schema, sql, 2);
 
         IgniteRel phys = physicalPlan(ctx);
 
         assertNotNull(phys);
 
-        MultiStepPlan plan = newPlan(phys);
+        MultiStepPlan plan = newPlan(phys, colocationGroups);
 
         assertNotNull(plan);
 
@@ -579,25 +367,12 @@ public class PlannerTest extends AbstractPlannerTest {
 
     @Test
     public void testMergeFilters() throws Exception {
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        TestTable testTbl = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("VAL", f.createJavaType(String.class))
-                        .build(), "TEST") {
-            @Override
-            public IgniteDistribution distribution() {
-                return IgniteDistributions.single();
-            }
-        };
-
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-
-        publicSchema.addTable(testTbl);
-
-        SchemaPlus schema = createRootSchema(false)
-                .add("PUBLIC", publicSchema);
+        IgniteSchema publicSchema = createSchema(TestBuilders.table()
+                .name("TEST")
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("VAL", NativeTypes.STRING)
+                .distribution(IgniteDistributions.single())
+                .build());
 
         String sql = "SELECT val from (\n"
                 + "   SELECT * \n"
@@ -605,66 +380,18 @@ public class PlannerTest extends AbstractPlannerTest {
                 + "   WHERE VAL = 10) \n"
                 + "WHERE VAL = 10";
 
-        RelNode phys = physicalPlan(sql, publicSchema);
-
-        assertNotNull(phys);
-
-        AtomicInteger filterCnt = new AtomicInteger();
-
-        // Counts filters af the plan.
-        phys.childrenAccept(
-            new RelVisitor() {
-                @Override public void visit(RelNode node, int ordinal, RelNode parent) {
-                    if (node instanceof IgniteFilter) {
-                        filterCnt.incrementAndGet();
-                    }
-
-                    super.visit(node, ordinal, parent);
-                }
-            }
-        );
-
-        // Checks that two filter merged into one filter.
-        // Expected plan:
-        // IgniteProject(VAL=[$1])
-        //  IgniteProject(ID=[$0], VAL=[$1])
-        //    IgniteFilter(condition=[=(CAST($1):INTEGER, 10)])
-        //      IgniteTableScan(table=[[PUBLIC, TEST]])
-        assertEquals(0, filterCnt.get());
+        assertPlan(sql, publicSchema, Predicate.not(nodeOrAnyChild(isInstanceOf(IgniteFilter.class)))
+                .and(nodeOrAnyChild(isInstanceOf(IgniteTableScan.class)
+                        .and(scan -> scan.condition() != null)
+                )));
     }
 
     @Test
     public void testJoinPushExpressionRule() throws Exception {
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        TestTable emp = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("DEPTNO", f.createJavaType(Integer.class))
-                        .build(), "EMP") {
-
-            @Override public IgniteDistribution distribution() {
-                return IgniteDistributions.broadcast();
-            }
-        };
-
-        TestTable dept = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("DEPTNO", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .build(), "DEPT") {
-
-            @Override
-            public IgniteDistribution distribution() {
-                return IgniteDistributions.broadcast();
-            }
-        };
-
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-
-        publicSchema.addTable(emp);
-        publicSchema.addTable(dept);
+        IgniteSchema publicSchema = createSchemaFrom(
+                employerTable(IgniteDistributions.broadcast()),
+                departmentTable(IgniteDistributions.broadcast())
+        );
 
         SchemaPlus schema = createRootSchema(false)
                 .add("PUBLIC", publicSchema);
@@ -706,7 +433,7 @@ public class PlannerTest extends AbstractPlannerTest {
 
             assertNotNull(rel);
             assertEquals("LogicalProject(DEPTNO=[$0], DEPTNO0=[$4])\n"
-                            + "  LogicalFilter(condition=[=(CAST(+($0, $4)):INTEGER, 2)])\n"
+                            + "  LogicalFilter(condition=[=(+($0, $4), 2)])\n"
                             + "    LogicalJoin(condition=[true], joinType=[inner])\n"
                             + "      IgniteLogicalTableScan(table=[[PUBLIC, DEPT]])\n"
                             + "      IgniteLogicalTableScan(table=[[PUBLIC, EMP]])\n",
@@ -723,10 +450,10 @@ public class PlannerTest extends AbstractPlannerTest {
             assertNotNull(phys);
             assertEquals(
                     "IgniteProject(DEPTNO=[$3], DEPTNO0=[$2])\n"
-                            + "  IgniteCorrelatedNestedLoopJoin(condition=[=(CAST(+($3, $2)):INTEGER, 2)], joinType=[inner], "
+                            + "  IgniteCorrelatedNestedLoopJoin(condition=[=(+($3, $2), 2)], joinType=[inner], "
                             + "variablesSet=[[$cor2]])\n"
                             + "    IgniteTableScan(table=[[PUBLIC, EMP]])\n"
-                            + "    IgniteTableScan(table=[[PUBLIC, DEPT]], filters=[=(CAST(+($t0, $cor2.DEPTNO)):INTEGER, 2)])\n",
+                            + "    IgniteTableScan(table=[[PUBLIC, DEPT]], filters=[=(+($t0, $cor2.DEPTNO), 2)])\n",
                     RelOptUtil.toString(phys),
                     "Invalid plan:\n" + RelOptUtil.toString(phys)
             );
@@ -737,41 +464,14 @@ public class PlannerTest extends AbstractPlannerTest {
 
     @Test
     public void testMergeJoinIsNotAppliedForNonEquiJoin() throws Exception {
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        TestTable emp = new TestTable("EMP",
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("DEPTNO", f.createJavaType(Integer.class))
-                        .build(), 1000) {
-
-            @Override
-            public IgniteDistribution distribution() {
-                return IgniteDistributions.broadcast();
-            }
-        };
-
-        emp.addIndex(new IgniteIndex(TestSortedIndex.create(RelCollations.of(ImmutableIntList.of(1, 2)), "emp_idx", emp)));
-
-        TestTable dept = new TestTable("DEPT",
-                new RelDataTypeFactory.Builder(f)
-                        .add("DEPTNO", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .build(), 100) {
-
-            @Override
-            public IgniteDistribution distribution() {
-                return IgniteDistributions.broadcast();
-            }
-        };
-
-        dept.addIndex(new IgniteIndex(TestSortedIndex.create(RelCollations.of(ImmutableIntList.of(1, 0)), "dep_idx", dept)));
-
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-
-        publicSchema.addTable(emp);
-        publicSchema.addTable(dept);
+        IgniteSchema publicSchema = createSchemaFrom(
+                employerTable(IgniteDistributions.broadcast())
+                        .andThen(setSize(1_000))
+                        .andThen(addSortIndex("NAME", "DEPTNO")),
+                departmentTable(IgniteDistributions.broadcast())
+                        .andThen(setSize(100))
+                        .andThen(addSortIndex("NAME", "DEPTNO"))
+        );
 
         String sql = "select d.deptno, d.name, e.id, e.name from dept d join emp e "
                 + "on d.deptno = e.deptno and e.name >= d.name order by e.name, d.deptno";
@@ -789,22 +489,12 @@ public class PlannerTest extends AbstractPlannerTest {
 
     @Test
     public void testNotStandardFunctions() throws Exception {
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        publicSchema.addTable(
-                new TestTable(
-                        new RelDataTypeFactory.Builder(f)
-                                .add("ID", f.createJavaType(Integer.class))
-                                .add("VAL", f.createJavaType(String.class))
-                                .build(), "TEST") {
-
-                    @Override
-                    public IgniteDistribution distribution() {
-                        return IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID);
-                    }
-                }
-        );
+        IgniteSchema publicSchema = createSchema(TestBuilders.table()
+                .name("TEST")
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("VAL", NativeTypes.STRING)
+                .distribution(IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID))
+                .build());
 
         String[] queries = {
                 "select REVERSE(val) from TEST", // MYSQL
@@ -823,31 +513,21 @@ public class PlannerTest extends AbstractPlannerTest {
 
     @Test
     public void correctPlanningWithOrToUnion() throws Exception {
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        TestTable tab0 = new TestTable(
-                new RelDataTypeFactory.Builder(f)
-                        .add("PK", f.createJavaType(Integer.class))
-                        .add("COL0", f.createJavaType(Integer.class))
-                        .add("COL1", f.createJavaType(Float.class))
-                        .add("COL2", f.createJavaType(String.class))
-                        .add("COL3", f.createJavaType(Integer.class))
-                        .add("COL4", f.createJavaType(Float.class))
-                        .build(), "TAB0") {
-
-            @Override public IgniteDistribution distribution() {
-                return IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID);
-            }
-        };
+        IgniteSchema publicSchema = createSchema(TestBuilders.table()
+                .name("TAB0")
+                .addColumn("PK", NativeTypes.INT32)
+                .addColumn("COL0", NativeTypes.INT32)
+                .addColumn("COL1", NativeTypes.FLOAT)
+                .addColumn("COL2", NativeTypes.STRING)
+                .addColumn("COL3", NativeTypes.INT32)
+                .addColumn("COL4", NativeTypes.FLOAT)
+                .distribution(IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID))
+                .build());
 
         String sql = "SELECT pk FROM tab0 WHERE (((((col4 < 341.32))) AND col3 IN (SELECT col0 FROM tab0 WHERE ((col0 > 564) "
                 + "AND col0 >= 344 AND (col0 IN (574) AND col0 > 600 AND ((col1 >= 568.71) AND col3 = 114 AND (col3 < 869))))) "
                 + "OR col4 >= 811.8)) ORDER BY 1 DESC";
 
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-
-        publicSchema.addTable(tab0);
-
         // just check for planning completeness for finite time.
         assertPlan(sql, publicSchema, (k) -> true);
     }
@@ -855,12 +535,18 @@ public class PlannerTest extends AbstractPlannerTest {
     @Test
     public void checkTableHintsHandling() throws Exception {
         IgniteSchema publicSchema = createSchema(
-                createTable("PERSON", IgniteDistributions.affinity(0, nextTableId(), Integer.MIN_VALUE),
-                        "PK", Integer.class, "ORG_ID", Integer.class
-                ),
-                createTable("COMPANY", IgniteDistributions.affinity(0, nextTableId(), Integer.MIN_VALUE),
-                        "PK", Integer.class, "ID", Integer.class
-                )
+                TestBuilders.table()
+                        .name("PERSON")
+                        .distribution(IgniteDistributions.affinity(0, nextTableId(), Integer.MIN_VALUE))
+                        .addColumn("PK", NativeTypes.INT32)
+                        .addColumn("ORG_ID", NativeTypes.INT32)
+                        .build(),
+                TestBuilders.table()
+                        .name("COMPANY")
+                        .distribution(IgniteDistributions.affinity(0, nextTableId(), Integer.MIN_VALUE))
+                        .addColumn("PK", NativeTypes.INT32)
+                        .addColumn("ID", NativeTypes.INT32)
+                        .build()
         );
 
         String sql = "SELECT * FROM person /*+ use_index(ORG_ID), extra */ t1 JOIN company /*+ use_index(ID) */ t2 ON t1.org_id = t2.id";
@@ -889,15 +575,11 @@ public class PlannerTest extends AbstractPlannerTest {
         checkSplitAndSerialization(phys, publicSchema);
     }
 
-    private MultiStepPlan newPlan(IgniteRel phys) {
+    private MultiStepPlan newPlan(IgniteRel phys, Map<Integer, ColocationGroup> colocationGroups) {
         List<Fragment> fragments = new Splitter().go(phys);
         MappingQueryContext ctx = mapContext(CollectionUtils.first(NODES), this::intermediateMapping);
 
-        CollectColocationGroups colocationGroups = new CollectColocationGroups();
-
-        phys.accept(colocationGroups);
-
-        List<Fragment> mappedFragments = FragmentMapping.mapFragments(ctx, fragments, colocationGroups.colocationGroups);
+        List<Fragment> mappedFragments = FragmentMapping.mapFragments(ctx, fragments, colocationGroups);
 
         return new MultiStepPlan(SqlQueryType.QUERY, mappedFragments, new ResultSetMetadataImpl(Collections.emptyList()));
     }
@@ -916,62 +598,55 @@ public class PlannerTest extends AbstractPlannerTest {
         return new MappingQueryContext(locNodeName, mappingService);
     }
 
-    abstract static class TestTable extends AbstractPlannerTest.TestTable {
-
-        private ColocationGroup colocationGroup;
-
-        TestTable(RelDataType type, String name) {
-            super(type, name);
-        }
-
-        TestTable(String name, RelDataType type, double rowCnt) {
-            super(name, type, rowCnt);
-        }
-
-        public ColocationGroup colocationGroup() {
-            throw new IllegalStateException("Colocation group has not been specified");
-        }
-
-        ColocationGroup getColocationGroup() {
-            if (colocationGroup == null) {
-                this.colocationGroup = colocationGroup();
-            }
-            return colocationGroup;
-        }
+    private static PlanningContext plannerContext(SchemaPlus schema, String sql, Object... params) {
+        return PlanningContext.builder()
+                .parentContext(BaseQueryContext.builder()
+                        .logger(log)
+                        .parameters(params)
+                        .frameworkConfig(newConfigBuilder(FRAMEWORK_CONFIG)
+                                .defaultSchema(schema)
+                                .build())
+                        .build())
+                .query(sql)
+                .build();
     }
 
-    private static final class CollectColocationGroups extends IgniteRelShuttle {
-
-        private final Map<Integer, ColocationGroup> colocationGroups = new HashMap<>();
-
-        @Override
-        public IgniteRel visit(IgniteTableModify rel) {
-            TestTable testTable = rel.getTable().unwrapOrThrow(TestTable.class);
-            ColocationGroup group = testTable.getColocationGroup();
-
-            colocationGroups.put(testTable.id(), group);
-
-            return super.visit(rel);
-        }
-
-        @Override
-        public IgniteRel visit(IgniteIndexScan rel) {
-            TestTable testTable = rel.getTable().unwrapOrThrow(TestTable.class);
-            ColocationGroup group = testTable.getColocationGroup();
-
-            colocationGroups.put(testTable.id(), group);
-
-            return super.visit(rel);
-        }
+    private static UnaryOperator<TableBuilder> employerTable(IgniteDistribution distribution) {
+        return tableBuilder -> tableBuilder
+                .name("EMP")
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("NAME", NativeTypes.STRING)
+                .addColumn("DEPTNO", NativeTypes.INT32)
+                .size(100)
+                .distribution(distribution);
+    }
 
-        @Override
-        public IgniteRel visit(IgniteTableScan rel) {
-            TestTable testTable = rel.getTable().unwrapOrThrow(TestTable.class);
-            ColocationGroup group = testTable.getColocationGroup();
+    private static UnaryOperator<TableBuilder> departmentTable(IgniteDistribution distribution) {
+        return tableBuilder -> tableBuilder
+                .name("DEPT")
+                .addColumn("DEPTNO", NativeTypes.INT32)
+                .addColumn("NAME", NativeTypes.STRING)
+                .size(100)
+                .distribution(distribution);
+    }
 
-            colocationGroups.put(testTable.id(), group);
+    private static UnaryOperator<TableBuilder> developerTable(IgniteDistribution distribution) {
+        return tableBuilder -> tableBuilder
+                .name(DEVELOPER_TABLE)
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("NAME", NativeTypes.STRING)
+                .addColumn("PROJECTID", NativeTypes.INT32)
+                .size(100)
+                .distribution(distribution);
+    }
 
-            return super.visit(rel);
-        }
+    private static UnaryOperator<TableBuilder> projectsTable(IgniteDistribution distribution) {
+        return tableBuilder -> tableBuilder
+                .name(PROJECT_TABLE)
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("NAME", NativeTypes.STRING)
+                .addColumn("VER", NativeTypes.INT32)
+                .size(100)
+                .distribution(distribution);
     }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PlannerTimeoutTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PlannerTimeoutTest.java
index db84572ded..5ac8bce263 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PlannerTimeoutTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PlannerTimeoutTest.java
@@ -23,6 +23,7 @@ import static org.apache.ignite.lang.ErrorGroups.Sql.PLANNING_TIMEOUT_ERR;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 
 import java.time.Duration;
 import java.util.Collections;
@@ -32,9 +33,9 @@ import org.apache.calcite.plan.volcano.VolcanoPlanner;
 import org.apache.calcite.plan.volcano.VolcanoTimeoutException;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelVisitor;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestTable;
 import org.apache.ignite.internal.sql.engine.prepare.IgnitePlanner;
 import org.apache.ignite.internal.sql.engine.prepare.PlanningContext;
 import org.apache.ignite.internal.sql.engine.prepare.PrepareService;
@@ -48,8 +49,8 @@ import org.apache.ignite.internal.sql.engine.sql.ParserServiceImpl;
 import org.apache.ignite.internal.sql.engine.util.BaseQueryContext;
 import org.apache.ignite.internal.sql.engine.util.EmptyCacheFactory;
 import org.apache.ignite.internal.sql.engine.util.SqlTestUtils;
-import org.jetbrains.annotations.NotNull;
 import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
 
 /**
  * Test planner timeout.
@@ -59,7 +60,7 @@ public class PlannerTimeoutTest extends AbstractPlannerTest {
     @Test
     public void testPlannerTimeout() throws Exception {
         long plannerTimeout = 1L;
-        IgniteSchema schema = createSchema(createTestTable("T1", "A", Integer.class, "B", Integer.class));
+        IgniteSchema schema = createSchema(createTestTable("T1"));
         BaseQueryContext ctx = baseQueryContext(Collections.singletonList(schema), null);
 
         PrepareService prepareService = new PrepareServiceImpl("test", 0, null, plannerTimeout);
@@ -78,12 +79,12 @@ public class PlannerTimeoutTest extends AbstractPlannerTest {
     }
 
     @Test
-    public void testLongPlanningTimeout() throws Exception {
+    public void testLongPlanningTimeout() {
         final long plannerTimeout = 500;
 
         IgniteSchema schema = createSchema(
-                createTestTable("T1", "A", Integer.class, "B", Integer.class),
-                createTestTable("T2", "A", Integer.class, "B", Integer.class)
+                createTestTable("T1"),
+                createTestTable("T2")
         );
 
         String sql = "SELECT * FROM T1 JOIN T2 ON T1.A = T2.A";
@@ -130,25 +131,30 @@ public class PlannerTimeoutTest extends AbstractPlannerTest {
         }
     }
 
-    @NotNull
-    private static TestTable createTestTable(String name, Object... cols) {
-        RelDataTypeFactory.Builder b = new RelDataTypeFactory.Builder(TYPE_FACTORY);
+    private static TestTable createTestTable(String tableName) {
+        TestTable testTable = TestBuilders.table()
+                .name(tableName)
+                .addColumn("A", NativeTypes.INT32)
+                .addColumn("B", NativeTypes.INT32)
+                .distribution(someAffinity())
+                .size(DEFAULT_TBL_SIZE)
+                .build();
 
-        for (int i = 0; i < cols.length; i += 2) {
-            b.add((String) cols[i], TYPE_FACTORY.createJavaType((Class<?>) cols[i + 1]));
-        }
+        // Create a proxy.
+        TestTable spyTable = Mockito.spy(testTable);
 
-        return new TestTable(name, b.build(), DEFAULT_TBL_SIZE) {
-            @Override
-            public RelDataType getRowType(RelDataTypeFactory typeFactory, ImmutableBitSet bitSet) {
-                try {
-                    Thread.sleep(300);
-                } catch (InterruptedException e) {
-                    throw new RuntimeException(e);
-                }
-                return super.getRowType(typeFactory, bitSet);
+        // Override and slowdown a method, which is called by Planner, to emulate long planning.
+        Mockito.doAnswer(inv -> {
+            try {
+                Thread.sleep(300);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
             }
-        };
+            // Call original method.
+            return testTable.getRowType(inv.getArgument(0), inv.getArgument(1));
+        }).when(spyTable).getRowType(any(), any());
+
+        return spyTable;
     }
 }
 
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ProjectFilterScanMergePlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ProjectFilterScanMergePlannerTest.java
index 066bc211c0..ba24a24197 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ProjectFilterScanMergePlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ProjectFilterScanMergePlannerTest.java
@@ -19,22 +19,18 @@ package org.apache.ignite.internal.sql.engine.planner;
 
 import java.util.List;
 import java.util.Objects;
+import java.util.function.UnaryOperator;
 import java.util.stream.Collectors;
-import org.apache.calcite.rel.RelCollations;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 import org.apache.ignite.internal.sql.engine.prepare.bounds.SearchBounds;
 import org.apache.ignite.internal.sql.engine.rel.IgniteAggregate;
 import org.apache.ignite.internal.sql.engine.rel.IgniteIndexScan;
 import org.apache.ignite.internal.sql.engine.rel.IgniteTableScan;
-import org.apache.ignite.internal.sql.engine.schema.IgniteIndex;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
-import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
@@ -51,17 +47,7 @@ public class ProjectFilterScanMergePlannerTest extends AbstractPlannerTest {
     /** {@inheritDoc} */
     @BeforeEach
     public void setup() {
-        publicSchema = new IgniteSchema("PUBLIC");
-
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        RelDataType type = new RelDataTypeFactory.Builder(f)
-                .add("A", f.createSqlType(SqlTypeName.INTEGER))
-                .add("B", f.createSqlType(SqlTypeName.INTEGER))
-                .add("C", f.createSqlType(SqlTypeName.INTEGER))
-                .build();
-
-        createTable(publicSchema, "TBL", type, IgniteDistributions.single());
+        publicSchema = createSchemaFrom(createTestTable());
     }
 
     @Test
@@ -90,8 +76,7 @@ public class ProjectFilterScanMergePlannerTest extends AbstractPlannerTest {
     @Test
     public void testProjectFilterMergeSortedIndex() throws Exception {
         // Test project and filter merge into index scan.
-        TestTable tbl = ((TestTable) publicSchema.getTable("TBL"));
-        tbl.addIndex(new IgniteIndex(TestSortedIndex.create(RelCollations.of(2), "IDX_C", tbl)));
+        publicSchema = createSchemaFrom(createTestTable().andThen(addSortIndex("C")));
 
         // Without index condition shift.
         assertPlan("SELECT a, b FROM tbl WHERE c = 0", publicSchema, isInstanceOf(IgniteIndexScan.class)
@@ -117,8 +102,7 @@ public class ProjectFilterScanMergePlannerTest extends AbstractPlannerTest {
     @Test
     public void testProjectFilterMergeHashIndex() throws Exception {
         // Test project and filter merge into index scan.
-        TestTable tbl = ((TestTable) publicSchema.getTable("TBL"));
-        tbl.addIndex(new IgniteIndex(TestHashIndex.create(List.of("c"), "IDX_C")));
+        publicSchema = createSchemaFrom(createTestTable().andThen(addHashIndex("C")));
 
         // Without index condition shift.
         assertPlan("SELECT a, b FROM tbl WHERE c = 0", publicSchema, isInstanceOf(IgniteIndexScan.class)
@@ -144,8 +128,7 @@ public class ProjectFilterScanMergePlannerTest extends AbstractPlannerTest {
     @Test
     public void testIdentityFilterMergeIndex() throws Exception {
         // Test project and filter merge into index scan.
-        TestTable tbl = ((TestTable) publicSchema.getTable("TBL"));
-        tbl.addIndex(new IgniteIndex(TestSortedIndex.create(RelCollations.of(2), "IDX_C", tbl)));
+        publicSchema = createSchemaFrom(createTestTable().andThen(addSortIndex("C")));
 
         // Without index condition shift.
         assertPlan("SELECT a, b, c FROM tbl WHERE c = 0", publicSchema, isInstanceOf(IgniteIndexScan.class)
@@ -169,8 +152,7 @@ public class ProjectFilterScanMergePlannerTest extends AbstractPlannerTest {
     @Test
     public void testIdentityFilterMergeHashIndex() throws Exception {
         // Test project and filter merge into index scan.
-        TestTable tbl = ((TestTable) publicSchema.getTable("TBL"));
-        tbl.addIndex(new IgniteIndex(TestHashIndex.create(List.of("c"), "IDX_C")));
+        publicSchema = createSchemaFrom(createTestTable().andThen(addHashIndex("C")));
 
         // Without index condition shift.
         assertPlan("SELECT a, b, c FROM tbl WHERE c = 0", publicSchema, isInstanceOf(IgniteIndexScan.class)
@@ -299,4 +281,12 @@ public class ProjectFilterScanMergePlannerTest extends AbstractPlannerTest {
     private static List<RexNode> searchBoundsCondition(List<SearchBounds> searchBounds) {
         return searchBounds.stream().filter(Objects::nonNull).map(SearchBounds::condition).collect(Collectors.toList());
     }
+
+    private static UnaryOperator<TableBuilder> createTestTable() {
+        return t -> t.name("TBL")
+                .addColumn("A", NativeTypes.INT32)
+                .addColumn("B", NativeTypes.INT32)
+                .addColumn("C", NativeTypes.INT32)
+                .distribution(IgniteDistributions.single());
+    }
 }
\ No newline at end of file
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SetOpPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SetOpPlannerTest.java
index c2fd38c0ff..71307b59bd 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SetOpPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SetOpPlannerTest.java
@@ -18,9 +18,10 @@
 package org.apache.ignite.internal.sql.engine.planner;
 
 import java.util.List;
+import java.util.function.UnaryOperator;
 import org.apache.calcite.rel.RelDistribution.Type;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 import org.apache.ignite.internal.sql.engine.rel.IgniteExchange;
 import org.apache.ignite.internal.sql.engine.rel.IgniteTrimExchange;
 import org.apache.ignite.internal.sql.engine.rel.set.IgniteColocatedIntersect;
@@ -34,9 +35,8 @@ import org.apache.ignite.internal.sql.engine.rel.set.IgniteReduceMinus;
 import org.apache.ignite.internal.sql.engine.rel.set.IgniteReduceSetOp;
 import org.apache.ignite.internal.sql.engine.rel.set.IgniteSetOp;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
+import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
-import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.TestInstance;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -57,27 +57,28 @@ public class SetOpPlannerTest extends AbstractPlannerTest {
      */
     @BeforeAll
     public void setup() {
-        publicSchema = new IgniteSchema("PUBLIC");
-
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        RelDataType type = new RelDataTypeFactory.Builder(f)
-                .add("ID", f.createJavaType(Integer.class))
-                .add("NAME", f.createJavaType(String.class))
-                .add("SALARY", f.createJavaType(Double.class))
-                .build();
-
-        createTable(publicSchema, "RANDOM_TBL1", type, IgniteDistributions.random());
-        createTable(publicSchema, "RANDOM_TBL2", type, IgniteDistributions.random());
-        createTable(publicSchema, "BROADCAST_TBL1", type, IgniteDistributions.broadcast());
-        createTable(publicSchema, "BROADCAST_TBL2", type, IgniteDistributions.broadcast());
-        createTable(publicSchema, "SINGLE_TBL1", type, IgniteDistributions.single());
-        createTable(publicSchema, "SINGLE_TBL2", type, IgniteDistributions.single());
-        createTable(publicSchema, "AFFINITY_TBL1", type, IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID));
-        createTable(publicSchema, "HASH_TBL1", type, IgniteDistributions.hash(List.of(0)));
-        createTable(publicSchema, "AFFINITY_TBL2", type, IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID));
-        createTable(publicSchema, "AFFINITY_TBL3", type, IgniteDistributions.affinity(1, nextTableId(), DEFAULT_ZONE_ID));
-        createTable(publicSchema, "AFFINITY_TBL4", type, IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID + 1));
+        publicSchema = createSchemaFrom(
+                createTable("RANDOM_TBL1", IgniteDistributions.random()),
+                createTable("RANDOM_TBL2", IgniteDistributions.random()),
+                createTable("BROADCAST_TBL1", IgniteDistributions.broadcast()),
+                createTable("BROADCAST_TBL2", IgniteDistributions.broadcast()),
+                createTable("SINGLE_TBL1", IgniteDistributions.single()),
+                createTable("SINGLE_TBL2", IgniteDistributions.single()),
+                createTable("AFFINITY_TBL1", IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID)),
+                createTable("HASH_TBL1", IgniteDistributions.hash(List.of(0))),
+                createTable("AFFINITY_TBL2", IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID)),
+                createTable("AFFINITY_TBL3", IgniteDistributions.affinity(1, nextTableId(), DEFAULT_ZONE_ID)),
+                createTable("AFFINITY_TBL4", IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID + 1))
+        );
+    }
+
+    private static UnaryOperator<TableBuilder> createTable(String tableName, IgniteDistribution distribution) {
+        return tableBuilder -> tableBuilder
+                .name(tableName)
+                .distribution(distribution)
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("NAME", NativeTypes.STRING)
+                .addColumn("SALARY", NativeTypes.DOUBLE);
     }
 
     /**
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SortedIndexSpoolPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SortedIndexSpoolPlannerTest.java
index c5749bb3e0..e65f443eb7 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SortedIndexSpoolPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/SortedIndexSpoolPlannerTest.java
@@ -24,21 +24,19 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.List;
+import java.util.function.UnaryOperator;
 import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.rel.RelCollations;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rex.RexFieldAccess;
-import org.apache.ignite.internal.index.ColumnCollation;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 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.IgniteCorrelatedNestedLoopJoin;
 import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
 import org.apache.ignite.internal.sql.engine.rel.IgniteSortedIndexSpool;
+import org.apache.ignite.internal.sql.engine.schema.IgniteIndex.Collation;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
-import org.apache.ignite.internal.sql.engine.trait.TraitUtils;
-import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
@@ -53,28 +51,10 @@ public class SortedIndexSpoolPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testNotColocatedEqJoin() throws Exception {
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        createTable(publicSchema,
-                "T0",
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("JID", f.createJavaType(Integer.class))
-                        .add("VAL", f.createJavaType(String.class))
-                        .build(),
-                someAffinity()
-        ).addIndex("t0_jid_idx", 1, 0);
-
-        createTable(publicSchema,
-                "T1",
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("JID", f.createJavaType(Integer.class))
-                        .add("VAL", f.createJavaType(String.class))
-                        .build(),
-                someAffinity()
-        ).addIndex("t1_jid_idx", 1, 0);
+        IgniteSchema publicSchema = createSchemaFrom(
+                tableA("T0").andThen(addSortIndex("JID", "ID")),
+                tableA("T1").andThen(addSortIndex("JID", "ID"))
+        );
 
         String sql = "select * "
                 + "from t0 "
@@ -103,31 +83,11 @@ public class SortedIndexSpoolPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testPartialIndexForCondition() throws Exception {
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        createTable(publicSchema,
-                "T0",
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("JID0", f.createJavaType(Integer.class))
-                        .add("JID1", f.createJavaType(Integer.class))
-                        .add("VAL", f.createJavaType(String.class))
-                        .build(),
-                someAffinity()
+        IgniteSchema publicSchema = createSchemaFrom(
+                tableB("T0"),
+                tableB("T1").andThen(addSortIndex("JID2", "JID1"))
         );
 
-        createTable(publicSchema,
-                "T1",
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("JID0", f.createJavaType(Integer.class))
-                        .add("JID1", f.createJavaType(Integer.class))
-                        .add("VAL", f.createJavaType(String.class))
-                        .build(),
-                someAffinity()
-        ).addIndex("t1_jid0_idx", 2, 1);
-
         String sql = "select * "
                 + "from t0 "
                 + "join t1 on t0.jid0 = t1.jid0 and t0.jid1 = t1.jid1";
@@ -158,13 +118,9 @@ public class SortedIndexSpoolPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void testDescFields() throws Exception {
-        IgniteSchema publicSchema = createSchema(
-                createTable("T0", 10, someAffinity(),
-                        "ID", Integer.class, "JID", Integer.class, "VAL", String.class)
-                        .addIndex("t0_jid_idx", 1),
-                createTable("T1", 100, someAffinity(),
-                        "ID", Integer.class, "JID", Integer.class, "VAL", String.class)
-                        .addIndex(RelCollations.of(TraitUtils.createFieldCollation(1, ColumnCollation.DESC_NULLS_LAST)), "t1_jid_idx")
+        IgniteSchema publicSchema = createSchemaFrom(
+                tableA("T0").andThen(setSize(10)),
+                tableA("T1").andThen(setSize(100)).andThen(index("jid", Collation.DESC_NULLS_LAST))
         );
 
         String sql = "select * "
@@ -192,9 +148,35 @@ public class SortedIndexSpoolPlannerTest extends AbstractPlannerTest {
 
                                     return true;
                                 })
-                                .and(hasChildThat(isIndexScan("T1", "t1_jid_idx")))
+                                .and(hasChildThat(isIndexScan("T1", "idx_jid")))
                         )),
                 "MergeJoinConverter", "NestedLoopJoinConverter", "FilterSpoolMergeToHashIndexSpoolRule"
         );
     }
+
+    private static UnaryOperator<TableBuilder> tableA(String tableName) {
+        return tableBuilder -> tableBuilder
+                .name(tableName)
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("JID", NativeTypes.INT32)
+                .addColumn("VAL", NativeTypes.STRING)
+                .distribution(someAffinity());
+    }
+
+    private static UnaryOperator<TableBuilder> tableB(String tableName) {
+        return tableBuilder -> tableBuilder
+                .name(tableName)
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("JID0", NativeTypes.INT32)
+                .addColumn("JID1", NativeTypes.INT32)
+                .addColumn("VAL", NativeTypes.STRING)
+                .distribution(someAffinity());
+    }
+
+    private static UnaryOperator<TableBuilder> index(String column, Collation collation) {
+        return tableBuilder -> tableBuilder.sortedIndex()
+                .name("idx_" + column)
+                .addColumn(column, collation)
+                .end();
+    }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/TableFunctionPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/TableFunctionPlannerTest.java
index 7134116a18..2cbba14dd9 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/TableFunctionPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/TableFunctionPlannerTest.java
@@ -17,16 +17,16 @@
 
 package org.apache.ignite.internal.sql.engine.planner;
 
+import java.util.function.UnaryOperator;
 import org.apache.calcite.rel.core.Join;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 import org.apache.ignite.internal.sql.engine.rel.IgniteCorrelatedNestedLoopJoin;
 import org.apache.ignite.internal.sql.engine.rel.IgniteExchange;
 import org.apache.ignite.internal.sql.engine.rel.IgniteTableFunctionScan;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
+import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
-import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestInstance;
@@ -45,18 +45,10 @@ public class TableFunctionPlannerTest extends AbstractPlannerTest {
      */
     @BeforeAll
     public void setup() {
-        publicSchema = new IgniteSchema("PUBLIC");
-
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        RelDataType type = new RelDataTypeFactory.Builder(f)
-                .add("ID", f.createJavaType(Integer.class))
-                .add("NAME", f.createJavaType(String.class))
-                .add("SALARY", f.createJavaType(Double.class))
-                .build();
-
-        createTable(publicSchema, "RANDOM_TBL", type, IgniteDistributions.random());
-        createTable(publicSchema, "BROADCAST_TBL", type, IgniteDistributions.broadcast());
+        publicSchema = createSchemaFrom(
+                createTestTable("RANDOM_TBL", IgniteDistributions.random()),
+                createTestTable("BROADCAST_TBL", IgniteDistributions.broadcast())
+        );
     }
 
     /**
@@ -121,4 +113,13 @@ public class TableFunctionPlannerTest extends AbstractPlannerTest {
                 .and(input(1, nodeOrAnyChild(isInstanceOf(IgniteTableFunctionScan.class))))
         ));
     }
+
+    private static UnaryOperator<TableBuilder> createTestTable(String tableName, IgniteDistribution distribution) {
+        return tableBuilder -> tableBuilder
+                .name(tableName)
+                .distribution(distribution)
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("NAME", NativeTypes.STRING)
+                .addColumn("SALARY", NativeTypes.DOUBLE);
+    }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/TableSpoolPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/TableSpoolPlannerTest.java
index 5e46300b7a..c8037d2480 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/TableSpoolPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/TableSpoolPlannerTest.java
@@ -19,13 +19,13 @@ package org.apache.ignite.internal.sql.engine.planner;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
+import java.util.function.UnaryOperator;
 import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
 import org.apache.ignite.internal.sql.engine.rel.IgniteTableSpool;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
-import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
@@ -42,27 +42,9 @@ public class TableSpoolPlannerTest extends AbstractPlannerTest {
      */
     @Test
     public void tableSpoolDistributed() throws Exception {
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        createTable(publicSchema,
-                "T0",
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("JID", f.createJavaType(Integer.class))
-                        .add("VAL", f.createJavaType(String.class))
-                        .build(),
-                someAffinity()
-        );
-
-        createTable(publicSchema,
-                "T1",
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("JID", f.createJavaType(Integer.class))
-                        .add("VAL", f.createJavaType(String.class))
-                        .build(),
-                someAffinity()
+        IgniteSchema publicSchema = createSchemaFrom(
+                createTestTable("T0"),
+                createTestTable("T1")
         );
 
         String sql = "select * "
@@ -80,4 +62,13 @@ public class TableSpoolPlannerTest extends AbstractPlannerTest {
 
         checkSplitAndSerialization(phys, publicSchema);
     }
+
+    private static UnaryOperator<TableBuilder> createTestTable(String tableName) {
+        return tableBuilder -> tableBuilder
+                .name(tableName)
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("JID", NativeTypes.INT32)
+                .addColumn("VAL", NativeTypes.STRING)
+                .distribution(someAffinity());
+    }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/UnionPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/UnionPlannerTest.java
index 48b9b763c9..477755cfaf 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/UnionPlannerTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/UnionPlannerTest.java
@@ -17,14 +17,13 @@
 
 package org.apache.ignite.internal.sql.engine.planner;
 
+import java.util.function.UnaryOperator;
 import org.apache.calcite.rel.core.Union;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 import org.apache.ignite.internal.sql.engine.rel.IgniteUnionAll;
 import org.apache.ignite.internal.sql.engine.rel.agg.IgniteReduceAggregateBase;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
-import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
-import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -75,41 +74,20 @@ public class UnionPlannerTest extends AbstractPlannerTest {
      *
      * @return Ignite schema.
      */
-    private IgniteSchema prepareSchema() {
-        IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
-
-        IgniteTypeFactory f = Commons.typeFactory();
-
-        createTable(publicSchema,
-                "TABLE1",
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("SALARY", f.createJavaType(Double.class))
-                        .build(),
-                IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID)
-        );
-
-        createTable(publicSchema,
-                "TABLE2",
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("SALARY", f.createJavaType(Double.class))
-                        .build(),
-                IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID)
-        );
-
-        createTable(publicSchema,
-                "TABLE3",
-                new RelDataTypeFactory.Builder(f)
-                        .add("ID", f.createJavaType(Integer.class))
-                        .add("NAME", f.createJavaType(String.class))
-                        .add("SALARY", f.createJavaType(Double.class))
-                        .build(),
-                IgniteDistributions.affinity(0, nextTableId(), DEFAULT_ZONE_ID)
+    private static IgniteSchema prepareSchema() {
+        return createSchemaFrom(
+                createTestTable("TABLE1"),
+                createTestTable("TABLE2"),
+                createTestTable("TABLE3")
         );
+    }
 
-        return publicSchema;
+    private static UnaryOperator<TableBuilder> createTestTable(String tableName) {
+        return tableBuilder -> tableBuilder
+                .name(tableName)
+                .distribution(someAffinity())
+                .addColumn("ID", NativeTypes.INT32)
+                .addColumn("NAME", NativeTypes.STRING)
+                .addColumn("SALARY", NativeTypes.DOUBLE);
     }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/TypeCoercionTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/TypeCoercionTest.java
index 27dd399b4e..1d69733523 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/TypeCoercionTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/TypeCoercionTest.java
@@ -27,14 +27,24 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.function.BiConsumer;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.apache.calcite.avatica.util.TimeUnit;
+import org.apache.calcite.config.CalciteConnectionConfig;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.hint.RelHint;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rel.type.RelDataTypeImpl;
+import org.apache.calcite.rel.type.RelProtoDataType;
+import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.runtime.CalciteContextException;
+import org.apache.calcite.schema.Schema;
+import org.apache.calcite.schema.Statistic;
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlIntervalQualifier;
 import org.apache.calcite.sql.SqlNode;
@@ -45,8 +55,16 @@ import org.apache.calcite.sql.parser.SqlParseException;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.ignite.internal.sql.engine.framework.TestStatistic;
 import org.apache.ignite.internal.sql.engine.planner.AbstractPlannerTest;
+import org.apache.ignite.internal.sql.engine.rel.logical.IgniteLogicalIndexScan;
+import org.apache.ignite.internal.sql.engine.rel.logical.IgniteLogicalTableScan;
+import org.apache.ignite.internal.sql.engine.schema.IgniteIndex;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
+import org.apache.ignite.internal.sql.engine.schema.IgniteTable;
+import org.apache.ignite.internal.sql.engine.schema.TableDescriptor;
+import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
 import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
 import org.apache.ignite.internal.sql.engine.type.IgniteCustomTypeCoercionRules;
@@ -70,7 +88,7 @@ public class TypeCoercionTest extends AbstractPlannerTest {
 
     private static final RelDataType VARCHAR = TYPE_FACTORY.createSqlType(SqlTypeName.VARCHAR, 20);
 
-    private static final List<RelDataType> NUMERIC_TYPES =  SqlTypeName.NUMERIC_TYPES.stream().map(t -> {
+    private static final List<RelDataType> NUMERIC_TYPES = SqlTypeName.NUMERIC_TYPES.stream().map(t -> {
         if (t == SqlTypeName.DECIMAL) {
             return TYPE_FACTORY.createSqlType(t, 10, 2);
         } else {
@@ -370,24 +388,18 @@ public class TypeCoercionTest extends AbstractPlannerTest {
                 .add("C2", rule.rhs)
                 .build();
 
+        TestTable testTable = new TestTable("A", tableType, IgniteDistributions.single());
+
         String dummyQuery = String.format("SELECT c1 %s c2 FROM A", rule.operator.getName());
-        runTest(dummyQuery, testCase, tableType);
+        runTest(dummyQuery, testCase, createSchema(testTable));
     }
 
     private void runTest(String query, BiConsumer<IgnitePlanner, SqlNode> testCase) {
-        runTest(query, testCase, null);
+        runTest(query, testCase, createSchema());
     }
 
-    private void runTest(String query, BiConsumer<IgnitePlanner, SqlNode> testCase, @Nullable RelDataType tableType) {
-        IgniteSchema igniteSchema;
-        if (tableType != null) {
-            TestTable testTable = createTable("A", tableType, DEFAULT_TBL_SIZE, IgniteDistributions.single());
-            igniteSchema = createSchema(testTable);
-        } else {
-            igniteSchema = createSchema();
-        }
-
-        PlanningContext planningCtx = plannerCtx(query, igniteSchema);
+    private void runTest(String query, BiConsumer<IgnitePlanner, SqlNode> testCase, IgniteSchema schema) {
+        PlanningContext planningCtx = plannerCtx(query, schema);
 
         try (IgnitePlanner planner = planningCtx.planner()) {
             SqlNode node;
@@ -569,4 +581,130 @@ public class TypeCoercionTest extends AbstractPlannerTest {
     private static RelDataType nullable(RelDataType relDataType) {
         return TYPE_FACTORY.createTypeWithNullability(relDataType, true);
     }
+
+    //TODO https://issues.apache.org/jira/browse/IGNITE-15200 Replace with TestTable from test framework.
+    // This class allows to verify some negative type-coercion tests, and can be dropped when INTERVAL type will be supported natively.
+
+    /** Test table. */
+    @Deprecated
+    private static class TestTable implements IgniteTable {
+        private final String name;
+
+        private final RelProtoDataType protoType;
+
+        private final int id = nextTableId();
+        private final IgniteDistribution distribution;
+
+        /** Constructor. */
+        private TestTable(String name, RelDataType type, IgniteDistribution distribution) {
+            protoType = RelDataTypeImpl.proto(type);
+            this.name = name;
+            this.distribution = distribution;
+        }
+
+        @Override
+        public int id() {
+            return id;
+        }
+
+        @Override
+        public int version() {
+            return 0;
+        }
+
+        @Override
+        public IgniteLogicalTableScan toRel(
+                RelOptCluster cluster,
+                RelOptTable relOptTbl,
+                List<RelHint> hints,
+                @Nullable List<RexNode> proj,
+                @Nullable RexNode cond,
+                @Nullable ImmutableBitSet requiredColumns
+        ) {
+            return IgniteLogicalTableScan.create(cluster, cluster.traitSet(), hints, relOptTbl, proj, cond, requiredColumns);
+        }
+
+        @Override
+        public IgniteLogicalIndexScan toRel(
+                RelOptCluster cluster,
+                RelOptTable relOptTbl,
+                String idxName,
+                @Nullable List<RexNode> proj,
+                @Nullable RexNode cond,
+                @Nullable ImmutableBitSet requiredColumns
+        ) {
+            return IgniteLogicalIndexScan.create(cluster, cluster.traitSet(), relOptTbl, idxName, proj, cond, requiredColumns);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public RelDataType getRowType(RelDataTypeFactory typeFactory, ImmutableBitSet bitSet) {
+            RelDataType rowType = protoType.apply(typeFactory);
+
+            if (bitSet != null) {
+                RelDataTypeFactory.Builder b = new RelDataTypeFactory.Builder(typeFactory);
+                for (int i = bitSet.nextSetBit(0); i != -1; i = bitSet.nextSetBit(i + 1)) {
+                    b.add(rowType.getFieldList().get(i));
+                }
+                rowType = b.build();
+            }
+
+            return rowType;
+        }
+
+        @Override
+        public Statistic getStatistic() {
+            return new TestStatistic(100.0);
+        }
+
+        @Override
+        public Schema.TableType getJdbcTableType() {
+            throw new AssertionError();
+        }
+
+        @Override
+        public boolean isRolledUp(String col) {
+            return false;
+        }
+
+        @Override
+        public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call, SqlNode parent, CalciteConnectionConfig config) {
+            throw new AssertionError();
+        }
+
+        @Override
+        public IgniteDistribution distribution() {
+            return distribution;
+        }
+
+        @Override
+        public TableDescriptor descriptor() {
+            throw new AssertionError();
+        }
+
+        @Override
+        public Map<String, IgniteIndex> indexes() {
+            return Map.of();
+        }
+
+        @Override
+        public void addIndex(IgniteIndex idxTbl) {
+            throw new AssertionError();
+        }
+
+        @Override
+        public IgniteIndex getIndex(String idxName) {
+            throw new AssertionError();
+        }
+
+        @Override
+        public void removeIndex(String idxName) {
+            throw new AssertionError();
+        }
+
+        @Override
+        public String name() {
+            return name;
+        }
+    }
 }