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

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


The following commit(s) were added to refs/heads/main by this push:
     new 48505b660b IGNITE-20634 Sql. Indices with write-only status should not 
be accessible via sql schemas. (#2712)
48505b660b is described below

commit 48505b660b2ec2e50c9ed9f408b6abbebbfb9555
Author: Max Zhuravkov <[email protected]>
AuthorDate: Wed Nov 22 07:20:51 2023 +0200

    IGNITE-20634 Sql. Indices with write-only status should not be accessible 
via sql schemas. (#2712)
---
 modules/runner/build.gradle                        |   1 +
 .../internal/sql/BaseSqlIntegrationTest.java       |   2 +-
 .../ignite/internal/sql/api/ItSqlApiBaseTest.java  |   3 +
 .../internal/sql/engine/ItAggregatesTest.java      |   3 -
 .../sql/engine/ItBuildIndexOneNodeTest.java        |   6 ++
 .../internal/sql/engine/ItBuildIndexTest.java      |  32 ++++++
 .../internal/sql/engine/ItIndexSpoolTest.java      |   5 +-
 .../ignite/internal/sql/engine/ItJoinTest.java     |   2 +-
 .../internal/ClusterPerClassIntegrationTest.java   | 106 +++++++++++++++++-
 .../sql/engine/schema/SqlSchemaManagerImpl.java    |   4 +
 .../sql/engine/framework/TestBuilders.java         |  52 +++++++--
 .../engine/schema/SqlSchemaManagerImplTest.java    | 118 ++++++++++++++++-----
 12 files changed, 295 insertions(+), 39 deletions(-)

diff --git a/modules/runner/build.gradle b/modules/runner/build.gradle
index 7140543f41..ed44e9e90e 100644
--- a/modules/runner/build.gradle
+++ b/modules/runner/build.gradle
@@ -194,6 +194,7 @@ dependencies {
     testFixturesImplementation testFixtures(project(':ignite-core'))
     testFixturesImplementation testFixtures(project(':ignite-sql-engine'))
     testFixturesImplementation testFixtures(project(':ignite-network'))
+    testFixturesImplementation testFixtures(project(':ignite-catalog'))
     testFixturesImplementation libs.jetbrains.annotations
     testFixturesImplementation libs.hamcrest.core
     testFixturesImplementation libs.auto.service.annotations
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/BaseSqlIntegrationTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/BaseSqlIntegrationTest.java
index 08159d7567..49d96eeca2 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/BaseSqlIntegrationTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/BaseSqlIntegrationTest.java
@@ -256,7 +256,7 @@ public class BaseSqlIntegrationTest extends 
ClusterPerClassIntegrationTest {
      * @return Nodes on which the partition index was built.
      * @throws Exception If failed.
      */
-    protected static Map<Integer, List<Ignite>> waitForIndexBuild(String 
tableName, String indexName) throws Exception {
+    protected static Map<Integer, List<Ignite>> waitForIndexBuild(String 
tableName, String indexName) {
         Map<Integer, List<Ignite>> partitionIdToNodes = new HashMap<>();
 
         CLUSTER.runningNodes().forEach(clusterNode -> {
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlApiBaseTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlApiBaseTest.java
index 1e9eace154..ba287ca8de 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlApiBaseTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlApiBaseTest.java
@@ -83,6 +83,9 @@ public abstract class ItSqlApiBaseTest extends 
BaseSqlIntegrationTest {
 
     @Test
     public void ddl() throws Exception {
+        // Do not wait for indexes to become available.
+        setAwaitIndexAvailability(false);
+
         IgniteSql sql = igniteSql();
         Session ses = sql.createSession();
 
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAggregatesTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAggregatesTest.java
index fb4df325f1..42510495ba 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAggregatesTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAggregatesTest.java
@@ -65,9 +65,6 @@ public class ItAggregatesTest extends BaseSqlIntegrationTest {
         sql("CREATE TABLE test (id INT PRIMARY KEY, grp0 INT, grp1 INT, val0 
INT, val1 INT) WITH PRIMARY_ZONE='TEST_ZONE'");
         sql("CREATE TABLE test_one_col_idx (pk INT PRIMARY KEY, col0 INT)");
 
-        sql("CREATE INDEX test_idx ON test(grp0, grp1)");
-        sql("CREATE INDEX test_one_col_idx_idx ON test_one_col_idx(col0)");
-
         for (int i = 0; i < ROWS; i++) {
             sql("INSERT INTO test (id, grp0, grp1, val0, val1) VALUES (?, ?, 
?, ?, ?)", i, i / 10, i / 100, 1, 2);
             sql("INSERT INTO test_one_col_idx (pk, col0) VALUES (?, ?)", i, i);
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItBuildIndexOneNodeTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItBuildIndexOneNodeTest.java
index 8d6cf2cc9a..8941337b4b 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItBuildIndexOneNodeTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItBuildIndexOneNodeTest.java
@@ -31,6 +31,7 @@ import org.apache.ignite.internal.hlc.HybridClock;
 import org.apache.ignite.internal.sql.BaseSqlIntegrationTest;
 import 
org.apache.ignite.internal.table.distributed.replication.request.BuildIndexReplicaRequest;
 import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 /** Integration test for testing the building of an index in a single node 
cluster. */
@@ -46,6 +47,11 @@ public class ItBuildIndexOneNodeTest extends 
BaseSqlIntegrationTest {
         return 1;
     }
 
+    @BeforeEach
+    void setup() {
+        setAwaitIndexAvailability(false);
+    }
+
     @AfterEach
     void tearDown() {
         sql("DROP TABLE IF EXISTS " + TABLE_NAME);
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItBuildIndexTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItBuildIndexTest.java
index e3366fc3eb..1c7d913e19 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItBuildIndexTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItBuildIndexTest.java
@@ -39,7 +39,9 @@ import java.util.function.BiPredicate;
 import java.util.stream.Stream;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.internal.app.IgniteImpl;
+import org.apache.ignite.internal.catalog.CatalogManager;
 import org.apache.ignite.internal.catalog.descriptors.CatalogIndexDescriptor;
+import org.apache.ignite.internal.hlc.HybridClock;
 import org.apache.ignite.internal.lang.IgniteStringFormatter;
 import org.apache.ignite.internal.raft.Command;
 import org.apache.ignite.internal.raft.Peer;
@@ -54,6 +56,7 @@ import org.apache.ignite.raft.jraft.rpc.WriteActionRequest;
 import org.jetbrains.annotations.Nullable;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -67,6 +70,12 @@ public class ItBuildIndexTest extends BaseSqlIntegrationTest 
{
 
     private static final String INDEX_NAME = "TEST_INDEX";
 
+    @BeforeEach
+    void setup() {
+        // Do not wait for indexes to become available.
+        setAwaitIndexAvailability(false);
+    }
+
     @AfterEach
     void tearDown() {
         sql("DROP TABLE IF EXISTS " + TABLE_NAME);
@@ -275,6 +284,10 @@ public class ItBuildIndexTest extends 
BaseSqlIntegrationTest {
                     IgniteStringFormatter.format("p={}, nodes={}", 
entry.getKey(), entry.getValue())
             );
         }
+
+        assertTrue(waitForCondition(() -> isIndexAvailable(INDEX_NAME), 
10_000));
+
+        waitForReadTimestampThatObservesMostRecentCatalog();
     }
 
     /**
@@ -288,4 +301,23 @@ public class ItBuildIndexTest extends 
BaseSqlIntegrationTest {
 
         return indexDescriptor == null ? null : indexDescriptor.id();
     }
+
+    /**
+     * Returns {@code true} if index with the given name is available.
+     *
+     * @param indexName Index nane.
+     * @return True if index is available or false if index does not exist or 
is not available.
+     */
+    private static boolean isIndexAvailable(String indexName) {
+        IgniteImpl ignite = CLUSTER.runningNodes()
+                .findAny()
+                .orElseThrow(() -> new IllegalStateException("No running 
nodes"));
+
+        CatalogManager catalogManager = ignite.catalogManager();
+        HybridClock clock = ignite.clock();
+
+        CatalogIndexDescriptor indexDescriptor = 
catalogManager.index(indexName, clock.nowLong());
+
+        return indexDescriptor != null && indexDescriptor.available();
+    }
 }
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItIndexSpoolTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItIndexSpoolTest.java
index 93233f9602..dd4b3e3432 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItIndexSpoolTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItIndexSpoolTest.java
@@ -26,6 +26,7 @@ import java.util.stream.Stream;
 import org.apache.ignite.internal.ClusterPerClassIntegrationTest;
 import org.apache.ignite.internal.logger.IgniteLogger;
 import org.apache.ignite.internal.logger.Loggers;
+import org.apache.ignite.internal.sql.BaseSqlIntegrationTest;
 import org.apache.ignite.table.Table;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -35,7 +36,7 @@ import org.junit.jupiter.params.provider.MethodSource;
 /**
  * Index spool test.
  */
-public class ItIndexSpoolTest extends ClusterPerClassIntegrationTest {
+public class ItIndexSpoolTest extends BaseSqlIntegrationTest {
     private static final IgniteLogger LOG = 
Loggers.forClass(ClusterPerClassIntegrationTest.class);
 
     /**
@@ -86,7 +87,7 @@ public class ItIndexSpoolTest extends 
ClusterPerClassIntegrationTest {
         res.forEach(r -> assertThat(r.get(0), is(r.get(1))));
     }
 
-    private void prepareDataSet(int rowsCount, int parts) throws 
InterruptedException {
+    private void prepareDataSet(int rowsCount, int parts) {
         Object[][] dataRows = new Object[rowsCount][];
 
         for (int i = 0; i < rowsCount; i++) {
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItJoinTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItJoinTest.java
index 7ea2a07aac..183e62d243 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItJoinTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItJoinTest.java
@@ -791,7 +791,7 @@ public class ItJoinTest extends BaseSqlIntegrationTest {
     @ParameterizedTest(name = "join algo : {0}, index present: {1}")
     @MethodSource("joinTypes")
     @WithSystemProperty(key = "IMPLICIT_PK_ENABLED", value = "true")
-    public void testIsNotDistinctFrom(JoinType joinType, boolean indexScan) 
throws InterruptedException {
+    public void testIsNotDistinctFrom(JoinType joinType, boolean indexScan) {
         try {
             sql("CREATE TABLE t11(i1 INTEGER, i2 INTEGER)");
 
diff --git 
a/modules/runner/src/testFixtures/java/org/apache/ignite/internal/ClusterPerClassIntegrationTest.java
 
b/modules/runner/src/testFixtures/java/org/apache/ignite/internal/ClusterPerClassIntegrationTest.java
index 6e7ea31302..6f4fb844b9 100644
--- 
a/modules/runner/src/testFixtures/java/org/apache/ignite/internal/ClusterPerClassIntegrationTest.java
+++ 
b/modules/runner/src/testFixtures/java/org/apache/ignite/internal/ClusterPerClassIntegrationTest.java
@@ -18,19 +18,33 @@
 package org.apache.ignite.internal;
 
 import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
+import static 
org.apache.ignite.internal.testframework.IgniteTestUtils.waitForCondition;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.nio.file.Path;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.apache.ignite.internal.app.IgniteImpl;
+import org.apache.ignite.internal.catalog.CatalogManager;
+import org.apache.ignite.internal.catalog.descriptors.CatalogIndexDescriptor;
+import org.apache.ignite.internal.catalog.descriptors.CatalogObjectDescriptor;
+import org.apache.ignite.internal.hlc.HybridTimestamp;
 import org.apache.ignite.internal.sql.engine.util.SqlTestUtils;
+import org.apache.ignite.internal.testframework.TestIgnitionManager;
 import org.apache.ignite.internal.testframework.WorkDirectory;
 import org.apache.ignite.table.Table;
 import org.apache.ignite.tx.Transaction;
 import org.jetbrains.annotations.Nullable;
 import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.TestInfo;
 import org.junit.jupiter.api.TestInstance;
 
@@ -57,10 +71,22 @@ public abstract class ClusterPerClassIntegrationTest 
extends IgniteIntegrationTe
     /** Cluster nodes. */
     protected static Cluster CLUSTER;
 
+    private static final boolean DEFAULT_WAIT_FOR_INDEX_AVAILABLE = true;
+
+    /** Whether to wait for indexes to become available or not. Default is 
{@code true}. */
+    private static final AtomicBoolean AWAIT_INDEX_AVAILABILITY = new 
AtomicBoolean(DEFAULT_WAIT_FOR_INDEX_AVAILABLE);
+
     /** Work directory. */
     @WorkDirectory
     private static Path WORK_DIR;
 
+    /** Reset {@link #AWAIT_INDEX_AVAILABILITY}. */
+    @BeforeEach
+    @AfterEach
+    void resetIndexAvailabilityFlag() {
+        setAwaitIndexAvailability(DEFAULT_WAIT_FOR_INDEX_AVAILABLE);
+    }
+
     /**
      * Before all.
      *
@@ -170,6 +196,15 @@ public abstract class ClusterPerClassIntegrationTest 
extends IgniteIntegrationTe
         sql(format("CREATE INDEX {} ON {} ({})", indexName, tableName, 
columnName));
     }
 
+    /**
+     * Sets whether to wait for indexes to become available.
+     *
+     * @param value Whether to wait for indexes to become available.
+     */
+    protected static void setAwaitIndexAvailability(boolean value) {
+        AWAIT_INDEX_AVAILABILITY.set(value);
+    }
+
     protected static void insertData(String tblName, List<String> columnNames, 
Object[]... tuples) {
         Transaction tx = CLUSTER.node(0).transactions().begin();
 
@@ -192,7 +227,12 @@ public abstract class ClusterPerClassIntegrationTest 
extends IgniteIntegrationTe
     }
 
     protected static List<List<Object>> sql(@Nullable Transaction tx, String 
sql, Object... args) {
-        return SqlTestUtils.sql(CLUSTER.node(0), tx, sql, args);
+        IgniteImpl node = CLUSTER.node(0);
+        if (!AWAIT_INDEX_AVAILABILITY.get()) {
+            return SqlTestUtils.sql(node, tx, sql, args);
+        } else {
+            return executeAwaitingIndexes(node, (n) -> SqlTestUtils.sql(n, tx, 
sql, args));
+        }
     }
 
     /**
@@ -227,4 +267,68 @@ public abstract class ClusterPerClassIntegrationTest 
extends IgniteIntegrationTe
             this.salary = salary;
         }
     }
+
+    /**
+     * Waits for some amount of time so that read-only transactions can 
observe the most recent version of the catalog.
+     */
+    protected static void waitForReadTimestampThatObservesMostRecentCatalog()  
{
+        // See TxManagerImpl::currentReadTimestamp.
+        long delay = HybridTimestamp.CLOCK_SKEW + 
TestIgnitionManager.DEFAULT_PARTITION_IDLE_SYNC_TIME_INTERVAL_MS;
+        try {
+            TimeUnit.MILLISECONDS.sleep(delay);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static List<List<Object>> executeAwaitingIndexes(IgniteImpl node, 
Function<IgniteImpl, List<List<Object>>> statement) {
+        CatalogManager catalogManager = node.catalogManager();
+
+        // Get existing indexes
+        Set<Integer> existing = 
catalogManager.indexes(catalogManager.latestCatalogVersion())
+                .stream().map(CatalogObjectDescriptor::id)
+                .collect(Collectors.toSet());
+
+        List<List<Object>> result = statement.apply(node);
+
+        // Get indexes after a statement and compute the difference
+        Set<Integer> difference = 
catalogManager.indexes(catalogManager.latestCatalogVersion()).stream()
+                .map(CatalogObjectDescriptor::id)
+                .collect(Collectors.toSet());
+
+        difference.removeAll(existing);
+
+        if (difference.isEmpty()) {
+            return result;
+        }
+
+        // If there are new indexes, wait for them to become available.
+
+        try {
+            assertTrue(waitForCondition(() -> {
+                int latestVersion = catalogManager.latestCatalogVersion();
+                int notAvailable = 0;
+
+                for (CatalogIndexDescriptor index : 
catalogManager.indexes(latestVersion)) {
+                    if (!index.available() && difference.contains(index.id())) 
{
+                        notAvailable++;
+                    }
+                }
+
+                return notAvailable == 0;
+            }, 10_000));
+
+            // We have no knowledge whether the next transaction is readonly 
or not,
+            // so we have to assume that the next transaction is read only 
transaction.
+            // otherwise the statements in that transaction may not observe
+            // the latest catalog version.
+            waitForReadTimestampThatObservesMostRecentCatalog();
+
+            return result;
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+
+            throw new IllegalStateException(e);
+        }
+    }
 }
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/SqlSchemaManagerImpl.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/SqlSchemaManagerImpl.java
index 5c6ac58a02..b6889d32ed 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/SqlSchemaManagerImpl.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/SqlSchemaManagerImpl.java
@@ -177,6 +177,10 @@ public class SqlSchemaManagerImpl implements 
SqlSchemaManager {
 
         // Assemble indexes as they are required by tables.
         for (CatalogIndexDescriptor indexDescriptor : 
schemaDescriptor.indexes()) {
+            if (!indexDescriptor.available()) {
+                continue;
+            }
+
             int tableId = indexDescriptor.tableId();
             TableDescriptor tableDescriptor = tableDescriptorMap.get(tableId);
             assert tableDescriptor != null : "Table is not found in schema: " 
+ tableId;
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 200db05a0f..2f73c043c0 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
@@ -38,7 +38,9 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Flow.Publisher;
 import java.util.function.Function;
 import java.util.stream.Collectors;
+import org.apache.ignite.internal.catalog.Catalog;
 import org.apache.ignite.internal.catalog.CatalogCommand;
+import org.apache.ignite.internal.catalog.CatalogManager;
 import org.apache.ignite.internal.catalog.CatalogManagerImpl;
 import org.apache.ignite.internal.catalog.CatalogTestUtils;
 import org.apache.ignite.internal.catalog.commands.ColumnParams;
@@ -47,7 +49,10 @@ import 
org.apache.ignite.internal.catalog.commands.CreateHashIndexCommand;
 import org.apache.ignite.internal.catalog.commands.CreateSortedIndexCommand;
 import org.apache.ignite.internal.catalog.commands.CreateTableCommand;
 import org.apache.ignite.internal.catalog.commands.DefaultValue;
+import org.apache.ignite.internal.catalog.commands.MakeIndexAvailableCommand;
 import org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation;
+import org.apache.ignite.internal.catalog.descriptors.CatalogIndexDescriptor;
+import org.apache.ignite.internal.catalog.descriptors.CatalogSchemaDescriptor;
 import org.apache.ignite.internal.cluster.management.topology.api.LogicalNode;
 import 
org.apache.ignite.internal.cluster.management.topology.api.LogicalTopologySnapshot;
 import org.apache.ignite.internal.hlc.HybridClockImpl;
@@ -542,11 +547,7 @@ public class TestBuilders {
                 }
             }
 
-            List<CatalogCommand> initialSchema = tableBuilders.stream()
-                    .flatMap(builder -> builder.build().stream())
-                    .collect(Collectors.toList());
-
-            Runnable initClosure = () -> 
await(catalogManager.execute(initialSchema));
+            Runnable initClosure = () -> initAction(catalogManager);
 
             var ddlHandler = new DdlCommandHandler(catalogManager);
             var schemaManager = new SqlSchemaManagerImpl(catalogManager, 
CaffeineCacheFactory.INSTANCE, 0);
@@ -624,6 +625,41 @@ public class TestBuilders {
                         + "[{}]", problematicTablesString));
             }
         }
+
+        private void initAction(CatalogManager catalogManager) {
+            List<CatalogCommand> initialSchema = tableBuilders.stream()
+                    .flatMap(builder -> builder.build().stream())
+                    .collect(Collectors.toList());
+
+            // Init schema
+            await(catalogManager.execute(initialSchema));
+
+            // Make indexes available
+            List<CatalogCommand> makeIndexesAvailable = new ArrayList<>();
+
+            Catalog catalog = 
catalogManager.catalog(catalogManager.latestCatalogVersion());
+
+            for (ClusterTableBuilderImpl tableBuilder : tableBuilders) {
+                String schemaName = tableBuilder.schemaName;
+                CatalogSchemaDescriptor schema = catalog.schema(schemaName);
+                assert schema != null : "SchemaDescriptor does not exist: " + 
schemaName;
+
+                for (AbstractClusterTableIndexBuilderImpl<?> indexBuilder : 
tableBuilder.indexBuilders) {
+                    String indexName = indexBuilder.name;
+                    CatalogIndexDescriptor index = 
Arrays.stream(schema.indexes())
+                            .filter(idx -> idx.name().equals(indexName))
+                            .findAny()
+                            .orElseThrow(() -> new 
AssertionError("IndexDescriptor does not exist: " + indexName));
+
+                    CatalogCommand command = 
MakeIndexAvailableCommand.builder()
+                            .indexId(index.id())
+                            .build();
+                    makeIndexesAvailable.add(command);
+                }
+            }
+
+            await(catalogManager.execute(makeIndexesAvailable));
+        }
     }
 
     private static class TableBuilderImpl implements TableBuilder {
@@ -759,6 +795,8 @@ public class TestBuilders {
 
         private final ClusterBuilderImpl parent;
 
+        private final String schemaName = CatalogManager.DEFAULT_SCHEMA_NAME;
+
         private String name;
 
         private ClusterTableBuilderImpl(ClusterBuilderImpl parent) {
@@ -825,7 +863,7 @@ public class TestBuilders {
 
             commands.add(
                     CreateTableCommand.builder()
-                            .schemaName("PUBLIC")
+                            .schemaName(schemaName)
                             .tableName(name)
                             .columns(columns)
                             .primaryKeyColumns(keyColumns)
@@ -833,7 +871,7 @@ public class TestBuilders {
             );
 
             for (AbstractClusterTableIndexBuilderImpl<?> builder : 
indexBuilders) {
-                commands.add(builder.build("PUBLIC", name));
+                commands.add(builder.build(schemaName, name));
             }
 
             return commands;
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/schema/SqlSchemaManagerImplTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/schema/SqlSchemaManagerImplTest.java
index 10078b4e99..24f5ab8037 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/schema/SqlSchemaManagerImplTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/schema/SqlSchemaManagerImplTest.java
@@ -34,7 +34,9 @@ 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.Function;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
@@ -52,7 +54,9 @@ import 
org.apache.ignite.internal.catalog.commands.CreateSystemViewCommand;
 import org.apache.ignite.internal.catalog.commands.CreateTableCommand;
 import org.apache.ignite.internal.catalog.commands.CreateTableCommandBuilder;
 import org.apache.ignite.internal.catalog.commands.DefaultValue;
+import org.apache.ignite.internal.catalog.commands.MakeIndexAvailableCommand;
 import org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation;
+import org.apache.ignite.internal.catalog.descriptors.CatalogIndexDescriptor;
 import org.apache.ignite.internal.catalog.descriptors.CatalogSchemaDescriptor;
 import 
org.apache.ignite.internal.catalog.descriptors.CatalogSystemViewDescriptor;
 import 
org.apache.ignite.internal.catalog.descriptors.CatalogSystemViewDescriptor.SystemViewType;
@@ -67,6 +71,7 @@ import 
org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
 import org.apache.ignite.internal.sql.engine.util.cache.CaffeineCacheFactory;
 import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
 import org.apache.ignite.sql.ColumnType;
+import org.jetbrains.annotations.Nullable;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -403,25 +408,41 @@ public class SqlSchemaManagerImplTest extends 
BaseIgniteAbstractTest {
                 createHashIndex("T1", "VAL1_IDX", "VAL1")
         )));
 
-        int versionAfter = catalogManager.latestCatalogVersion();
-        assertThat(versionAfter, equalTo(versionBefore + 1));
+        {
+            int versionAfter = catalogManager.latestCatalogVersion();
+            assertThat(versionAfter, equalTo(versionBefore + 1));
 
-        SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
-        assertNotNull(rootSchema);
+            SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
+            assertNotNull(rootSchema);
 
-        SchemaPlus schemaPlus = rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
-        assertNotNull(schemaPlus);
+            SchemaPlus schemaPlus = 
rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
+            assertNotNull(schemaPlus);
 
-        IgniteTable table = getTable(unwrapSchema(schemaPlus), "T1");
-        assertNotNull(table);
+            IgniteIndex index = findIndex(unwrapSchema(schemaPlus), "T1", 
"VAL1_IDX");
+            assertNull(index, "Index should not be available");
+        }
 
-        IgniteIndex index = table.indexes().get("VAL1_IDX");
+        makeIndexAvailable("VAL1_IDX");
 
-        assertThat(index.name(), equalTo("VAL1_IDX"));
-        assertThat(index.type(), equalTo(Type.HASH));
-        assertThat(index.collation(), equalTo(RelCollations.of(
-                new RelFieldCollation(1, Direction.CLUSTERED, 
NullDirection.UNSPECIFIED)
-        )));
+        {
+            int versionAfter = catalogManager.latestCatalogVersion();
+            assertThat(versionAfter, equalTo(versionBefore + 2));
+
+            SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
+            assertNotNull(rootSchema);
+
+            SchemaPlus schemaPlus = 
rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
+            assertNotNull(schemaPlus);
+
+            IgniteIndex index = findIndex(unwrapSchema(schemaPlus), "T1", 
"VAL1_IDX");
+            assertNotNull(index);
+
+            assertThat(index.name(), equalTo("VAL1_IDX"));
+            assertThat(index.type(), equalTo(Type.HASH));
+            assertThat(index.collation(), equalTo(RelCollations.of(
+                    new RelFieldCollation(1, Direction.CLUSTERED, 
NullDirection.UNSPECIFIED)
+            )));
+        }
     }
 
     @Test
@@ -435,20 +456,37 @@ public class SqlSchemaManagerImplTest extends 
BaseIgniteAbstractTest {
                         List.of(CatalogColumnCollation.DESC_NULLS_FIRST, 
CatalogColumnCollation.DESC_NULLS_LAST))
         )));
 
-        int versionAfter = catalogManager.latestCatalogVersion();
-        assertThat(versionAfter, equalTo(versionBefore + 1));
+        {
+            int versionAfter = catalogManager.latestCatalogVersion();
+            assertThat(versionAfter, equalTo(versionBefore + 1));
 
-        SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
-        assertNotNull(rootSchema);
+            SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
+            assertNotNull(rootSchema);
 
-        SchemaPlus schemaPlus = rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
-        assertNotNull(schemaPlus);
+            SchemaPlus schemaPlus = 
rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
+            assertNotNull(schemaPlus);
 
-        IgniteTable table = getTable(unwrapSchema(schemaPlus), "T1");
-        assertNotNull(table);
+            IgniteIndex index1 = findIndex(unwrapSchema(schemaPlus), "T1", 
"IDX1");
+            assertNull(index1);
+
+            IgniteIndex index2 = findIndex(unwrapSchema(schemaPlus), "T1", 
"IDX2");
+            assertNull(index2);
+        }
+
+        makeIndexAvailable("IDX1");
 
         {
-            IgniteIndex index = table.indexes().get("IDX1");
+            int versionAfter = catalogManager.latestCatalogVersion();
+            assertThat(versionAfter, equalTo(versionBefore + 2));
+
+            SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
+            assertNotNull(rootSchema);
+
+            SchemaPlus schemaPlus = 
rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
+            assertNotNull(schemaPlus);
+
+            IgniteIndex index = findIndex(unwrapSchema(schemaPlus), "T1", 
"IDX1");
+            assertNotNull(index);
 
             assertThat(index.name(), equalTo("IDX1"));
             assertThat(index.type(), equalTo(Type.SORTED));
@@ -458,8 +496,20 @@ public class SqlSchemaManagerImplTest extends 
BaseIgniteAbstractTest {
             )));
         }
 
+        makeIndexAvailable("IDX2");
+
         {
-            IgniteIndex index = table.indexes().get("IDX2");
+            int versionAfter = catalogManager.latestCatalogVersion();
+            assertThat(versionAfter, equalTo(versionBefore + 3));
+
+            SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
+            assertNotNull(rootSchema);
+
+            SchemaPlus schemaPlus = 
rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
+            assertNotNull(schemaPlus);
+
+            IgniteIndex index = findIndex(unwrapSchema(schemaPlus), "T1", 
"IDX2");
+            assertNotNull(index);
 
             assertThat(index.name(), equalTo("IDX2"));
             assertThat(index.type(), equalTo(Type.SORTED));
@@ -470,6 +520,20 @@ public class SqlSchemaManagerImplTest extends 
BaseIgniteAbstractTest {
         }
     }
 
+    private void makeIndexAvailable(String name) {
+        Map<String, CatalogIndexDescriptor> indices = 
catalogManager.indexes(catalogManager.latestCatalogVersion())
+                
.stream().collect(Collectors.toMap(CatalogIndexDescriptor::name, 
Function.identity()));
+
+        CatalogIndexDescriptor indexDescriptor = indices.get(name);
+        assertNotNull(indexDescriptor, indices.toString());
+
+        CatalogCommand makeAvailable = MakeIndexAvailableCommand.builder()
+                .indexId(indexDescriptor.id())
+                .build();
+
+        await(catalogManager.execute(List.of(makeAvailable)));
+    }
+
     @ParameterizedTest
     @MethodSource("systemViewDistributions")
     public void testBasicView(SystemViewType viewType, IgniteDistribution 
distribution) {
@@ -596,6 +660,12 @@ public class SqlSchemaManagerImplTest extends 
BaseIgniteAbstractTest {
         return table;
     }
 
+    private static @Nullable IgniteIndex findIndex(IgniteSchema schema, String 
tableName, String indexName) {
+        IgniteTable table = (IgniteTable) schema.getTable(tableName);
+        assertNotNull(table);
+        return table.indexes().get(indexName);
+    }
+
     private static Stream<Arguments> columnTypes() {
         return Stream.of(
                 Arguments.of(ColumnType.BOOLEAN, -1, -1),

Reply via email to