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/07/28 13:31:17 UTC

[ignite-3] 03/08: Mirror Index changes from Config to Catalog

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

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

commit 0c2690164ce429cd325694d8b96a3d23c1965744
Author: amashenkov <an...@gmail.com>
AuthorDate: Tue Jul 11 19:30:31 2023 +0300

    Mirror Index changes from Config to Catalog
---
 .../internal/catalog/commands/CatalogUtils.java    |   1 -
 .../apache/ignite/internal/index/IndexManager.java | 139 ++++++++++++++++++++-
 .../ignite/internal/index/IndexManagerTest.java    |  90 +++++++++----
 .../ignite/internal/index/ItIndexManagerTest.java  |  23 ++--
 .../runner/app/ItIgniteNodeRestartTest.java        |   8 +-
 .../org/apache/ignite/internal/app/IgniteImpl.java |   2 +-
 .../sql/engine/exec/ddl/DdlCommandHandler.java     |   2 +-
 .../engine/exec/ddl/DdlCommandHandlerWrapper.java  |  37 +++---
 .../sql/engine/exec/MockedStructuresTest.java      |  17 ++-
 .../internal/table/distributed/TableManager.java   |   8 +-
 .../table/distributed/TableManagerTest.java        |  11 +-
 11 files changed, 271 insertions(+), 67 deletions(-)

diff --git a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CatalogUtils.java b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CatalogUtils.java
index d157cbaba2..7d53598e23 100644
--- a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CatalogUtils.java
+++ b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CatalogUtils.java
@@ -208,5 +208,4 @@ public class CatalogUtils {
                 return 0;
         }
     }
-
 }
diff --git a/modules/index/src/main/java/org/apache/ignite/internal/index/IndexManager.java b/modules/index/src/main/java/org/apache/ignite/internal/index/IndexManager.java
index a9bbdf6c45..2944ef3f6e 100644
--- a/modules/index/src/main/java/org/apache/ignite/internal/index/IndexManager.java
+++ b/modules/index/src/main/java/org/apache/ignite/internal/index/IndexManager.java
@@ -36,6 +36,10 @@ import java.util.function.Function;
 import org.apache.ignite.configuration.NamedListView;
 import org.apache.ignite.configuration.notifications.ConfigurationNamedListListener;
 import org.apache.ignite.configuration.notifications.ConfigurationNotificationEvent;
+import org.apache.ignite.internal.catalog.CatalogManager;
+import org.apache.ignite.internal.catalog.commands.CreateHashIndexParams;
+import org.apache.ignite.internal.catalog.commands.CreateSortedIndexParams;
+import org.apache.ignite.internal.catalog.commands.DropIndexParams;
 import org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation;
 import org.apache.ignite.internal.catalog.descriptors.CatalogHashIndexDescriptor;
 import org.apache.ignite.internal.catalog.descriptors.CatalogIndexColumnDescriptor;
@@ -59,6 +63,7 @@ import org.apache.ignite.internal.schema.configuration.TableView;
 import org.apache.ignite.internal.schema.configuration.TablesConfiguration;
 import org.apache.ignite.internal.schema.configuration.TablesView;
 import org.apache.ignite.internal.schema.configuration.index.HashIndexChange;
+import org.apache.ignite.internal.schema.configuration.index.SortedIndexChange;
 import org.apache.ignite.internal.schema.configuration.index.TableIndexChange;
 import org.apache.ignite.internal.schema.configuration.index.TableIndexConfiguration;
 import org.apache.ignite.internal.schema.configuration.index.TableIndexView;
@@ -73,6 +78,7 @@ import org.apache.ignite.internal.util.IgniteSpinBusyLock;
 import org.apache.ignite.internal.util.StringUtils;
 import org.apache.ignite.lang.ErrorGroups;
 import org.apache.ignite.lang.ErrorGroups.Common;
+import org.apache.ignite.lang.IgniteException;
 import org.apache.ignite.lang.IgniteInternalException;
 import org.apache.ignite.lang.IndexAlreadyExistsException;
 import org.apache.ignite.lang.IndexNotFoundException;
@@ -96,6 +102,9 @@ public class IndexManager extends Producer<IndexEvent, IndexEventParameters> imp
     /** Table manager. */
     private final TableManager tableManager;
 
+    /** Catalog manager. */
+    private final CatalogManager catalogManager;
+
     /** Busy lock to stop synchronously. */
     private final IgniteSpinBusyLock busyLock = new IgniteSpinBusyLock();
 
@@ -106,17 +115,20 @@ public class IndexManager extends Producer<IndexEvent, IndexEventParameters> imp
      * Constructor.
      *
      * @param tablesCfg Tables and indexes configuration.
+     * @param catalogManager Catalog manager.
      * @param schemaManager Schema manager.
      * @param tableManager Table manager.
      */
     public IndexManager(
             TablesConfiguration tablesCfg,
+            CatalogManager catalogManager,
             SchemaManager schemaManager,
             TableManager tableManager
     ) {
         this.tablesCfg = Objects.requireNonNull(tablesCfg, "tablesCfg");
         this.schemaManager = Objects.requireNonNull(schemaManager, "schemaManager");
         this.tableManager = tableManager;
+        this.catalogManager = catalogManager;
     }
 
     /** {@inheritDoc} */
@@ -142,8 +154,10 @@ public class IndexManager extends Producer<IndexEvent, IndexEventParameters> imp
                                 .toArray(String[]::new);
 
                         String pkName = table.name() + "_PK";
+                        int pkId = table.tableId() + 1;
 
-                        return createIndexAsync("PUBLIC", pkName, table.name(), false,
+                        // Update config bypassing the Catalog, because PK has just been created in Catalog with the table.
+                        return createIndexInternal(pkId, "PUBLIC", pkName, table.name(), false,
                                 change -> change.changeUniq(true).convert(HashIndexChange.class)
                                         .changeColumnNames(pkColumns)
                         );
@@ -186,12 +200,104 @@ public class IndexManager extends Producer<IndexEvent, IndexEventParameters> imp
      * @param indexChange A consumer that suppose to change the configuration in order to provide description of an index.
      * @return A future represented the result of creation.
      */
+    @Deprecated(forRemoval = true)
     public CompletableFuture<Boolean> createIndexAsync(
             String schemaName,
             String indexName,
             String tableName,
             boolean failIfExists,
             Consumer<TableIndexChange> indexChange
+    ) {
+        throw new UnsupportedOperationException("Method is no longer supported.");
+    }
+
+    /**
+     * Creates sorted index from provided parameters.
+     */
+    @Deprecated(forRemoval = true)
+    public CompletableFuture<Boolean> createSortedIndexAsync(CreateSortedIndexParams params) {
+        if (!busyLock.enterBusy()) {
+            return failedFuture(new NodeStoppingException());
+        }
+
+        try {
+            Consumer<TableIndexChange> indexChanger = tableIndexChange -> {
+                tableIndexChange.convert(SortedIndexChange.class).changeColumns(colsInit -> {
+                    for (int i = 0; i < params.columns().size(); i++) {
+                        String columnName = params.columns().get(i);
+                        CatalogColumnCollation collation = params.collations().get(i);
+                        //TODO: https://issues.apache.org/jira/browse/IGNITE-17563 Pass null ordering for columns.
+                        colsInit.create(columnName, colInit -> colInit.changeAsc(collation.asc()));
+                    }
+                });
+            };
+
+            return catalogManager.createIndex(params)
+                    .thenApply(ignore -> {
+                        CatalogIndexDescriptor index = catalogManager.index(params.indexName(), Long.MAX_VALUE);
+                        return index.id();
+                    })
+                    .thenCompose(indexId ->
+                            createIndexInternal(
+                                    indexId,
+                                    params.schemaName(),
+                                    params.indexName(),
+                                    params.tableName(),
+                                    true,
+                                    indexChanger
+                            )
+                    );
+        } catch (Exception ex) {
+            return failedFuture(ex);
+        } finally {
+            busyLock.leaveBusy();
+        }
+    }
+
+    /**
+     * Creates hash index from provided parameters.
+     */
+    @Deprecated(forRemoval = true)
+    public CompletableFuture<Boolean> createHashIndexAsync(CreateHashIndexParams params) {
+        if (!busyLock.enterBusy()) {
+            return failedFuture(new NodeStoppingException());
+        }
+
+        try {
+            Consumer<TableIndexChange> indexChanger = tableIndexChange -> {
+                tableIndexChange.convert(HashIndexChange.class)
+                        .changeColumnNames(params.columns().toArray(STRING_EMPTY_ARRAY));
+            };
+
+            return catalogManager.createIndex(params)
+                    .thenApply(ignore -> {
+                        CatalogIndexDescriptor index = catalogManager.index(params.indexName(), Long.MAX_VALUE);
+                        return index.id();
+                    })
+                    .thenCompose(indexId ->
+                            createIndexInternal(
+                                    indexId,
+                                    params.schemaName(),
+                                    params.indexName(),
+                                    params.tableName(),
+                                    true,
+                                    indexChanger
+                            )
+                    );
+        } catch (Exception ex) {
+            return failedFuture(ex);
+        } finally {
+            busyLock.leaveBusy();
+        }
+    }
+
+    private CompletableFuture<Boolean> createIndexInternal(
+            int indexId,
+            String schemaName,
+            String indexName,
+            String tableName,
+            boolean failIfExists,
+            Consumer<TableIndexChange> indexChange
     ) {
         if (!busyLock.enterBusy()) {
             return failedFuture(new NodeStoppingException());
@@ -224,8 +330,6 @@ public class IndexManager extends Producer<IndexEvent, IndexEventParameters> imp
 
                 int tableId = tableCfg.id();
 
-                int indexId = tablesChange.globalIdCounter() + 1;
-
                 tablesChange.changeGlobalIdCounter(indexId);
 
                 Consumer<TableIndexChange> chg = indexChange.andThen(c -> c.changeTableId(tableId).changeId(indexId));
@@ -281,6 +385,33 @@ public class IndexManager extends Producer<IndexEvent, IndexEventParameters> imp
             String schemaName,
             String indexName,
             boolean failIfNotExists
+    ) {
+        throw new UnsupportedOperationException("Method is no longer supported.");
+    }
+
+    /**
+     * Drops the index with a given parameters asynchronously.
+     */
+    public CompletableFuture<Boolean> dropIndexAsync(DropIndexParams params) {
+        if (!busyLock.enterBusy()) {
+            throw new IgniteException(new NodeStoppingException());
+        }
+        try {
+            CompletableFuture<Boolean> future = catalogManager.dropIndex(params)
+                    .thenCompose(ignore -> dropIndexAsyncInternal(params.schemaName(), params.indexName(), true));
+
+            future.whenComplete((res, ex) -> ex.printStackTrace());
+
+            return future;
+        } finally {
+            busyLock.leaveBusy();
+        }
+    }
+
+    private CompletableFuture<Boolean> dropIndexAsyncInternal(
+            String schemaName,
+            String indexName,
+            boolean failIfNotExists
     ) {
         if (!busyLock.enterBusy()) {
             return failedFuture(new NodeStoppingException());
@@ -325,6 +456,8 @@ public class IndexManager extends Producer<IndexEvent, IndexEventParameters> imp
             });
 
             return future;
+        } catch (Exception ex) {
+            return failedFuture(ex);
         } finally {
             busyLock.leaveBusy();
         }
diff --git a/modules/index/src/test/java/org/apache/ignite/internal/index/IndexManagerTest.java b/modules/index/src/test/java/org/apache/ignite/internal/index/IndexManagerTest.java
index 8230656614..40fb2c13f7 100644
--- a/modules/index/src/test/java/org/apache/ignite/internal/index/IndexManagerTest.java
+++ b/modules/index/src/test/java/org/apache/ignite/internal/index/IndexManagerTest.java
@@ -27,8 +27,10 @@ import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.notNullValue;
 import static org.junit.jupiter.api.Assertions.fail;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -38,6 +40,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicReference;
+import org.apache.ignite.internal.catalog.CatalogManager;
+import org.apache.ignite.internal.catalog.commands.CreateHashIndexParams;
+import org.apache.ignite.internal.catalog.commands.CreateSortedIndexParams;
+import org.apache.ignite.internal.catalog.commands.DropIndexParams;
+import org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation;
+import org.apache.ignite.internal.catalog.descriptors.CatalogIndexDescriptor;
 import org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
 import org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
 import org.apache.ignite.internal.configuration.tree.ConverterToMapVisitor;
@@ -47,7 +55,6 @@ import org.apache.ignite.internal.index.event.IndexEventParameters;
 import org.apache.ignite.internal.schema.SchemaManager;
 import org.apache.ignite.internal.schema.configuration.ExtendedTableChange;
 import org.apache.ignite.internal.schema.configuration.TablesConfiguration;
-import org.apache.ignite.internal.schema.configuration.index.SortedIndexChange;
 import org.apache.ignite.internal.schema.configuration.index.TableIndexView;
 import org.apache.ignite.internal.table.InternalTable;
 import org.apache.ignite.internal.table.TableImpl;
@@ -104,7 +111,16 @@ public class IndexManagerTest {
 
         when(schManager.schemaRegistry(anyLong(), anyInt())).thenReturn(completedFuture(null));
 
-        indexManager = new IndexManager(tablesConfig, schManager, tableManagerMock);
+        //TODO IGNITE-19082 drop mocked catalog manager.
+        CatalogManager catalogManager = mock(CatalogManager.class);
+        CatalogIndexDescriptor indexDescriptor = mock(CatalogIndexDescriptor.class);
+        when(catalogManager.createIndex(any(CreateHashIndexParams.class))).thenReturn(completedFuture(null));
+        when(catalogManager.createIndex(any(CreateSortedIndexParams.class))).thenReturn(completedFuture(null));
+        when(catalogManager.dropIndex(any())).thenReturn(completedFuture(null));
+        when(catalogManager.index(anyString(), anyLong())).thenReturn(indexDescriptor);
+        when(indexDescriptor.id()).thenReturn(1);
+
+        indexManager = new IndexManager(tablesConfig, catalogManager, schManager, tableManagerMock);
         indexManager.start();
 
         assertThat(
@@ -125,16 +141,14 @@ public class IndexManagerTest {
     void configurationChangedWhenCreateIsInvoked() {
         String indexName = "idx";
 
-        assertThat(indexManager.createIndexAsync("sName", indexName, "tName", true, indexChange -> {
-            SortedIndexChange sortedIndexChange = indexChange.convert(SortedIndexChange.class);
-
-            sortedIndexChange.changeColumns(columns -> {
-                columns.create("c1", columnChange -> columnChange.changeAsc(true));
-                columns.create("c2", columnChange -> columnChange.changeAsc(false));
-            });
-
-            sortedIndexChange.changeTableId(tableId());
-        }), willCompleteSuccessfully());
+        assertThat(indexManager.createSortedIndexAsync(
+                CreateSortedIndexParams.builder()
+                        .schemaName(CatalogManager.DEFAULT_SCHEMA_NAME)
+                        .tableName("tName")
+                        .indexName(indexName)
+                        .columns(List.of("c1", "c2"))
+                        .collations(List.of(CatalogColumnCollation.ASC_NULLS_LAST, CatalogColumnCollation.DESC_NULLS_FIRST))
+                        .build()), willCompleteSuccessfully());
 
         var expected = List.of(
                 Map.of(
@@ -162,7 +176,24 @@ public class IndexManagerTest {
     @Test
     public void createIndexWithEmptyName() {
         assertThat(
-                indexManager.createIndexAsync("sName", "", "tName", true, indexChange -> {/* doesn't matter */}),
+                indexManager.createHashIndexAsync(
+                        CreateHashIndexParams.builder()
+                                .schemaName(CatalogManager.DEFAULT_SCHEMA_NAME)
+                                .tableName("tName")
+                                .indexName("")
+                                .columns(List.of("c1"))
+                                .build()),
+                willThrowFast(IgniteInternalException.class, "Index name should be at least 1 character long")
+        );
+
+        assertThat(
+                indexManager.createSortedIndexAsync(
+                        CreateSortedIndexParams.builder()
+                                .schemaName(CatalogManager.DEFAULT_SCHEMA_NAME)
+                                .tableName("tName")
+                                .indexName("")
+                                .columns(List.of("c1"))
+                                .build()),
                 willThrowFast(IgniteInternalException.class, "Index name should be at least 1 character long")
         );
     }
@@ -170,8 +201,12 @@ public class IndexManagerTest {
     @Test
     public void dropNonExistingIndex() {
         assertThat(
-                indexManager.dropIndexAsync("sName", "nonExisting", true),
-                willThrowFast(IndexNotFoundException.class, "Index does not exist [name=\"sName\".\"nonExisting\"]")
+                indexManager.dropIndexAsync(
+                        DropIndexParams.builder()
+                                .schemaName(CatalogManager.DEFAULT_SCHEMA_NAME)
+                                .indexName("nonExisting")
+                                .build()),
+                willThrowFast(IndexNotFoundException.class, "Index does not exist [name=\"PUBLIC\".\"nonExisting\"]")
         );
     }
 
@@ -194,15 +229,15 @@ public class IndexManagerTest {
             return completedFuture(true);
         });
 
-        assertThat(indexManager.createIndexAsync("sName", indexName, "tName", true, indexChange -> {
-            SortedIndexChange sortedIndexChange = indexChange.convert(SortedIndexChange.class);
-
-            sortedIndexChange.changeColumns(columns -> {
-                columns.create("c2", columnChange -> columnChange.changeAsc(true));
-            });
-
-            sortedIndexChange.changeTableId(tableId());
-        }), willCompleteSuccessfully());
+        assertThat(indexManager.createSortedIndexAsync(
+                        CreateSortedIndexParams.builder()
+                                .schemaName(CatalogManager.DEFAULT_SCHEMA_NAME)
+                                .indexName(indexName)
+                                .tableName("tName")
+                                .columns(List.of("c2"))
+                                .collations(List.of(CatalogColumnCollation.ASC_NULLS_LAST))
+                                .build()),
+                willCompleteSuccessfully());
 
         List<Integer> indexIds = tablesConfig.indexes().value().stream()
                 .map(TableIndexView::id)
@@ -217,7 +252,12 @@ public class IndexManagerTest {
         assertThat(holder.get().tableId(), equalTo(tableId()));
         assertThat(holder.get().indexDescriptor().name(), equalTo(indexName));
 
-        assertThat(indexManager.dropIndexAsync("sName", indexName, true), willCompleteSuccessfully());
+        assertThat(indexManager.dropIndexAsync(
+                DropIndexParams.builder()
+                        .schemaName(CatalogManager.DEFAULT_SCHEMA_NAME)
+                        .indexName(indexName)
+                        .build()),
+                willCompleteSuccessfully());
 
         assertThat(holder.get(), notNullValue());
         assertThat(holder.get().indexId(), equalTo(indexId));
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/index/ItIndexManagerTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/index/ItIndexManagerTest.java
index e511cac7c0..3c7eca2188 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/index/ItIndexManagerTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/index/ItIndexManagerTest.java
@@ -23,12 +23,14 @@ import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.hasItems;
 import static org.hamcrest.Matchers.notNullValue;
 
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.internal.app.IgniteImpl;
+import org.apache.ignite.internal.catalog.commands.CreateHashIndexParams;
+import org.apache.ignite.internal.catalog.commands.DropIndexParams;
 import org.apache.ignite.internal.index.event.IndexEvent;
 import org.apache.ignite.internal.index.event.IndexEventParameters;
-import org.apache.ignite.internal.schema.configuration.index.HashIndexChange;
 import org.apache.ignite.internal.sql.engine.ClusterPerClassIntegrationTest;
 import org.apache.ignite.internal.table.TableImpl;
 import org.apache.ignite.internal.testframework.WorkDirectoryExtension;
@@ -68,12 +70,13 @@ public class ItIndexManagerTest extends ClusterPerClassIntegrationTest {
 
         CompletableFuture<IndexEventParameters> indexCreatedFuture = registerListener(indexManager, IndexEvent.CREATE);
 
-        await(indexManager.createIndexAsync(
-                "PUBLIC",
-                "INAME",
-                "TNAME",
-                true,
-                tableIndexChange -> tableIndexChange.convert(HashIndexChange.class).changeColumnNames("C3", "C2")
+        await(indexManager.createHashIndexAsync(
+                CreateHashIndexParams.builder()
+                        .schemaName("PUBLIC")
+                        .indexName("INAME")
+                        .tableName("TNAME")
+                        .columns(List.of("C3", "C2"))
+                        .build()
                 ));
 
         int createdIndexId;
@@ -90,7 +93,11 @@ public class ItIndexManagerTest extends ClusterPerClassIntegrationTest {
 
         CompletableFuture<IndexEventParameters> indexDroppedFuture = registerListener(indexManager, IndexEvent.DROP);
 
-        await(indexManager.dropIndexAsync("PUBLIC", "INAME", true));
+        await(indexManager.dropIndexAsync(
+                DropIndexParams.builder()
+                        .schemaName("PUBLIC")
+                        .indexName("INAME")
+                        .build()));
 
         {
             IndexEventParameters params = await(indexDroppedFuture);
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java
index 1b782195ce..00bf165d11 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java
@@ -386,7 +386,7 @@ public class ItIgniteNodeRestartTest extends BaseIgniteRestartTest {
                 null
         );
 
-        var indexManager = new IndexManager(tablesConfig, schemaManager, tableManager);
+        var indexManager = new IndexManager(tablesConfig, catalogManager, schemaManager, tableManager);
 
         SqlQueryProcessor qryEngine = new SqlQueryProcessor(
                 registry,
@@ -1205,9 +1205,9 @@ public class ItIgniteNodeRestartTest extends BaseIgniteRestartTest {
      */
     private void createTableWithData(List<IgniteImpl> nodes, String name, int replicas, int partitions) {
         try (Session session = nodes.get(0).sql().createSession()) {
-            session.execute(null,
-                    String.format("CREATE ZONE IF NOT EXISTS ZONE_%s WITH REPLICAS=%d, PARTITIONS=%d", name, replicas, partitions));
-            session.execute(null, "CREATE TABLE IF NOT EXISTS " + name
+            session.execute(null, String.format("CREATE ZONE IF NOT EXISTS ZONE_%s WITH REPLICAS=%d, PARTITIONS=%d",
+                            name.toUpperCase(), replicas, partitions));
+            session.execute(null, "CREATE TABLE IF NOT EXISTS " + name.toUpperCase()
                     + "(id INT PRIMARY KEY, name VARCHAR) WITH PRIMARY_ZONE='ZONE_" + name.toUpperCase() + "';");
 
             for (int i = 0; i < 100; i++) {
diff --git a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
index d38a1597e8..a9cd3b548b 100644
--- a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
+++ b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
@@ -550,7 +550,7 @@ public class IgniteImpl implements Ignite {
                 distributionZoneManager
         );
 
-        indexManager = new IndexManager(tablesConfig, schemaManager, distributedTblMgr);
+        indexManager = new IndexManager(tablesConfig, catalogManager, schemaManager, distributedTblMgr);
 
         qryEngine = new SqlQueryProcessor(
                 registry,
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ddl/DdlCommandHandler.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ddl/DdlCommandHandler.java
index f56848c215..5760dc2a85 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ddl/DdlCommandHandler.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ddl/DdlCommandHandler.java
@@ -106,7 +106,7 @@ public class DdlCommandHandler {
 
     protected final TableManager tableManager;
 
-    private final IndexManager indexManager;
+    protected final IndexManager indexManager;
 
     private final DataStorageManager dataStorageManager;
 
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ddl/DdlCommandHandlerWrapper.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ddl/DdlCommandHandlerWrapper.java
index bb702d4566..7fbd884f9b 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ddl/DdlCommandHandlerWrapper.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ddl/DdlCommandHandlerWrapper.java
@@ -17,6 +17,9 @@
 
 package org.apache.ignite.internal.sql.engine.exec.ddl;
 
+import static java.util.concurrent.CompletableFuture.failedFuture;
+import static org.apache.ignite.lang.ErrorGroups.Sql.UNSUPPORTED_DDL_OPERATION_ERR;
+
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 import org.apache.ignite.internal.catalog.CatalogManager;
@@ -35,6 +38,7 @@ import org.apache.ignite.internal.sql.engine.prepare.ddl.DropIndexCommand;
 import org.apache.ignite.internal.sql.engine.prepare.ddl.DropTableCommand;
 import org.apache.ignite.internal.storage.DataStorageManager;
 import org.apache.ignite.internal.table.distributed.TableManager;
+import org.apache.ignite.lang.IgniteInternalCheckedException;
 import org.apache.ignite.lang.IndexAlreadyExistsException;
 import org.apache.ignite.lang.IndexNotFoundException;
 import org.apache.ignite.lang.TableAlreadyExistsException;
@@ -86,28 +90,25 @@ public class DdlCommandHandlerWrapper extends DdlCommandHandler {
         } else if (cmd instanceof AlterColumnCommand) {
             return catalogManager.alterColumn(DdlToCatalogCommandConverter.convert((AlterColumnCommand) cmd))
                     .handle(handleModificationResult(((AlterColumnCommand) cmd).ifTableExists(), TableNotFoundException.class));
-        }
+        } else if (cmd instanceof CreateIndexCommand) {
+            AbstractIndexCommandParams params = DdlToCatalogCommandConverter.convert((CreateIndexCommand) cmd);
 
-        // Handle command in usual way.
-        CompletableFuture<Boolean> ddlCommandFuture = super.handle(cmd);
+            if (params instanceof CreateSortedIndexParams) {
+                return indexManager.createSortedIndexAsync((CreateSortedIndexParams) params)
+                        .handle(handleModificationResult(((CreateIndexCommand) cmd).ifNotExists(), IndexAlreadyExistsException.class));
+            } else if (params instanceof CreateHashIndexParams) {
+                return indexManager.createHashIndexAsync((CreateHashIndexParams) params)
+                        .handle(handleModificationResult(((CreateIndexCommand) cmd).ifNotExists(), IndexAlreadyExistsException.class));
+            }
 
-        if (cmd instanceof CreateIndexCommand) {
-            return ddlCommandFuture
-                    .thenCompose(res -> {
-                        AbstractIndexCommandParams params = DdlToCatalogCommandConverter.convert((CreateIndexCommand) cmd);
-                        if (params instanceof CreateSortedIndexParams) {
-                            return catalogManager.createIndex((CreateSortedIndexParams) params);
-                        } else {
-                            return catalogManager.createIndex((CreateHashIndexParams) params);
-                        }
-                    }).handle(handleModificationResult(((CreateIndexCommand) cmd).ifNotExists(), IndexAlreadyExistsException.class));
+            return failedFuture(new IgniteInternalCheckedException(UNSUPPORTED_DDL_OPERATION_ERR, "Unsupported DDL operation ["
+                    + "cmdName=" + cmd.getClass().getSimpleName() + "]"));
         } else if (cmd instanceof DropIndexCommand) {
-            return ddlCommandFuture
-                    .thenCompose(res -> catalogManager.dropIndex(DdlToCatalogCommandConverter.convert((DropIndexCommand) cmd))
-                            .handle(handleModificationResult(((DropIndexCommand) cmd).ifNotExists(), IndexNotFoundException.class))
-                    );
+            return indexManager.dropIndexAsync(DdlToCatalogCommandConverter.convert((DropIndexCommand) cmd))
+                    .handle(handleModificationResult(((DropIndexCommand) cmd).ifNotExists(), IndexNotFoundException.class));
         }
 
-        return ddlCommandFuture;
+        // Handle other commands in usual way.
+        return super.handle(cmd);
     }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java
index 9aa9471037..955a4223c2 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java
@@ -48,6 +48,9 @@ import java.util.function.Consumer;
 import java.util.function.LongFunction;
 import org.apache.ignite.internal.baseline.BaselineManager;
 import org.apache.ignite.internal.catalog.CatalogManager;
+import org.apache.ignite.internal.catalog.commands.CreateHashIndexParams;
+import org.apache.ignite.internal.catalog.commands.CreateSortedIndexParams;
+import org.apache.ignite.internal.catalog.descriptors.CatalogIndexDescriptor;
 import org.apache.ignite.internal.catalog.descriptors.CatalogTableDescriptor;
 import org.apache.ignite.internal.cluster.management.ClusterManagementGroupManager;
 import org.apache.ignite.internal.cluster.management.topology.api.LogicalTopologySnapshot;
@@ -284,11 +287,17 @@ public class MockedStructuresTest extends IgniteAbstractTest {
 
         //TODO IGNITE-19082 drop mocked catalog manager.
         catalogManager = mock(CatalogManager.class);
-        CatalogTableDescriptor descriptor = mock(CatalogTableDescriptor.class);
-        when(descriptor.id()).thenReturn(1);
+        CatalogTableDescriptor tableDescriptor = mock(CatalogTableDescriptor.class);
+        CatalogIndexDescriptor indexDescriptor = mock(CatalogIndexDescriptor.class);
+        when(tableDescriptor.id()).thenReturn(1);
+        when(indexDescriptor.id()).thenReturn(1);
         when(catalogManager.createTable(any())).thenReturn(completedFuture(null));
+        when(catalogManager.createIndex(any(CreateHashIndexParams.class))).thenReturn(completedFuture(null));
+        when(catalogManager.createIndex(any(CreateSortedIndexParams.class))).thenReturn(completedFuture(null));
         when(catalogManager.dropTable(any())).thenReturn(completedFuture(null));
-        when(catalogManager.table(anyString(), anyLong())).thenReturn(descriptor);
+        when(catalogManager.dropIndex(any())).thenReturn(completedFuture(null));
+        when(catalogManager.table(anyString(), anyLong())).thenReturn(tableDescriptor);
+        when(catalogManager.index(anyString(), anyLong())).thenReturn(indexDescriptor);
 
         cmgMgr = mock(ClusterManagementGroupManager.class);
 
@@ -304,7 +313,7 @@ public class MockedStructuresTest extends IgniteAbstractTest {
 
         tblManager = mockManagers();
 
-        idxManager = new IndexManager(tblsCfg, schemaManager, tblManager);
+        idxManager = new IndexManager(tblsCfg, catalogManager, schemaManager, tblManager);
 
         idxManager.start();
 
diff --git a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/TableManager.java b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/TableManager.java
index 375a1fa542..6a7b8b7721 100644
--- a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/TableManager.java
+++ b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/TableManager.java
@@ -1746,7 +1746,13 @@ public class TableManager extends Producer<TableEvent, TableEventParameters> imp
         }
     }
 
-    /** See {@link #alterTableAsync(String, Function)} for details. */
+    /**
+     * Alter table configuration.
+     *
+     * @see AlterTableAddColumnParams
+     * @see AlterTableDropColumnParams
+     */
+    @Deprecated(forRemoval = true)
     private CompletableFuture<Void> alterTableAsyncInternal(String name, Function<TableChange, Boolean> tableChange) {
         CompletableFuture<Void> tblFut = new CompletableFuture<>();
 
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TableManagerTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TableManagerTest.java
index 883c0bf771..83b5e6f5ff 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TableManagerTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TableManagerTest.java
@@ -68,7 +68,10 @@ import org.apache.ignite.internal.affinity.AffinityUtils;
 import org.apache.ignite.internal.baseline.BaselineManager;
 import org.apache.ignite.internal.catalog.CatalogManager;
 import org.apache.ignite.internal.catalog.commands.AlterTableAddColumnParams;
+import org.apache.ignite.internal.catalog.commands.CreateHashIndexParams;
+import org.apache.ignite.internal.catalog.commands.CreateSortedIndexParams;
 import org.apache.ignite.internal.catalog.commands.DropTableParams;
+import org.apache.ignite.internal.catalog.descriptors.CatalogIndexDescriptor;
 import org.apache.ignite.internal.catalog.descriptors.CatalogTableDescriptor;
 import org.apache.ignite.internal.catalog.descriptors.CatalogZoneDescriptor;
 import org.apache.ignite.internal.cluster.management.ClusterManagementGroupManager;
@@ -861,10 +864,16 @@ public class TableManagerTest extends IgniteAbstractTest {
         //TODO IGNITE-19082 drop mocked catalog manager.
         CatalogManager catalogManager = mock(CatalogManager.class);
         CatalogTableDescriptor tableDescriptor = mock(CatalogTableDescriptor.class);
+        CatalogIndexDescriptor indexDescriptor = mock(CatalogIndexDescriptor.class);
+        when(tableDescriptor.id()).thenReturn(1);
+        when(indexDescriptor.id()).thenReturn(1);
         when(catalogManager.createTable(any())).thenReturn(completedFuture(null));
+        when(catalogManager.createIndex(any(CreateHashIndexParams.class))).thenReturn(completedFuture(null));
+        when(catalogManager.createIndex(any(CreateSortedIndexParams.class))).thenReturn(completedFuture(null));
         when(catalogManager.dropTable(any())).thenReturn(completedFuture(null));
+        when(catalogManager.dropIndex(any())).thenReturn(completedFuture(null));
         when(catalogManager.table(anyString(), anyLong())).thenReturn(tableDescriptor);
-        when(tableDescriptor.id()).thenReturn(1);
+        when(catalogManager.index(anyString(), anyLong())).thenReturn(indexDescriptor);
 
         TableManager tableManager = new TableManager(
                 "test",