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

mpochatkin 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 69e5cf4b66 IGNITE-23185 Add methods to access table and zone 
definitions (#4452)
69e5cf4b66 is described below

commit 69e5cf4b662d9aaa8486637126820ab5df605e64
Author: Mikhail <[email protected]>
AuthorDate: Wed Oct 2 17:07:54 2024 +0300

    IGNITE-23185 Add methods to access table and zone definitions (#4452)
---
 .../org/apache/ignite/catalog/IgniteCatalog.java   |  32 ++++
 .../catalog/definitions/ColumnDefinition.java      |  19 ++
 .../catalog/definitions/IndexDefinition.java       |  20 ++
 .../catalog/definitions/TableDefinition.java       |  40 ++++
 .../ignite/catalog/definitions/ZoneDefinition.java |  16 ++
 .../ignite/internal/catalog/ItCatalogDslTest.java  |  84 ++++++++-
 .../internal/matcher/ColumnDefinitionsMatcher.java |  62 +++++++
 .../internal/matcher/TableDefinitionMatcher.java   | 203 +++++++++++++++++++++
 .../internal/matcher/ZoneDefinitionMatcher.java    | 186 +++++++++++++++++++
 .../catalog/sql/CreateFromDefinitionImpl.java      |   8 +-
 .../internal/catalog/sql/CreateTableImpl.java      |   4 +-
 .../internal/catalog/sql/CreateZoneImpl.java       |  18 +-
 .../internal/catalog/sql/IgniteCatalogSqlImpl.java |  85 ++++++++-
 .../apache/ignite/internal/catalog/sql/Option.java | 100 ++++++++++
 .../ignite/internal/catalog/sql/QueryContext.java  |   7 +
 .../ignite/internal/catalog/sql/QueryUtils.java    |   8 +
 .../internal/catalog/sql/SelectFromView.java       |  91 +++++++++
 .../catalog/sql/TableDefinitionCollector.java      | 171 +++++++++++++++++
 .../ignite/internal/catalog/sql/WithOption.java    |  80 --------
 .../ignite/internal/catalog/sql/QueryPartTest.java |   6 +-
 .../catalog/CatalogSystemViewRegistry.java         |   4 +-
 .../systemviews/TablesSystemViewProvider.java      | 146 +++++++++++++++
 .../systemviews/ZonesSystemViewProvider.java       |  51 +++++-
 .../ignite/internal/client/TcpIgniteClient.java    |   2 +-
 .../threading/PublicApiThreadingIgniteCatalog.java |  21 +++
 25 files changed, 1348 insertions(+), 116 deletions(-)

diff --git 
a/modules/api/src/main/java/org/apache/ignite/catalog/IgniteCatalog.java 
b/modules/api/src/main/java/org/apache/ignite/catalog/IgniteCatalog.java
index c4d37d9219..fc46666280 100644
--- a/modules/api/src/main/java/org/apache/ignite/catalog/IgniteCatalog.java
+++ b/modules/api/src/main/java/org/apache/ignite/catalog/IgniteCatalog.java
@@ -191,6 +191,22 @@ public interface IgniteCatalog {
      */
     Table createTable(TableDefinition definition);
 
+    /**
+     * Returns definition of the table with provided name or {@code null} if 
table doesn't exist.
+     *
+     * @param tableName Table name.
+     * @return Future with table definition with provided name or {@code null} 
if table doesn't exist.
+     */
+    CompletableFuture<TableDefinition> tableDefinitionAsync(String tableName);
+
+    /**
+     * Returns definition of the table with provided name or {@code null} if 
table doesn't exist.
+     *
+     * @param tableName Table name.
+     * @return Table definition with provided name.
+     */
+    TableDefinition tableDefinition(String tableName);
+
     /**
      * Creates a query object from the zone definition.
      *
@@ -205,6 +221,22 @@ public interface IgniteCatalog {
      */
     void createZone(ZoneDefinition definition);
 
+    /**
+     * Returns definition of the zone with provided name or {@code null} if 
zone doesn't exist.
+     *
+     * @param zoneName Zone name.
+     * @return Future with zone definition with provided name or {@code null} 
if zone doesn't exist.
+     */
+    CompletableFuture<ZoneDefinition> zoneDefinitionAsync(String zoneName);
+
+    /**
+     * Returns definition of the zone with provided name or {@code null} if 
zone doesn't exist.
+     *
+     * @param zoneName Zone name.
+     * @return Zone definition with provided name.
+     */
+    ZoneDefinition zoneDefinition(String zoneName);
+
     /**
      * Creates a {@code DROP TABLE} query object from the table definition.
      *
diff --git 
a/modules/api/src/main/java/org/apache/ignite/catalog/definitions/ColumnDefinition.java
 
b/modules/api/src/main/java/org/apache/ignite/catalog/definitions/ColumnDefinition.java
index af32f8dd92..f42bbf3960 100644
--- 
a/modules/api/src/main/java/org/apache/ignite/catalog/definitions/ColumnDefinition.java
+++ 
b/modules/api/src/main/java/org/apache/ignite/catalog/definitions/ColumnDefinition.java
@@ -100,4 +100,23 @@ public class ColumnDefinition {
     public @Nullable String definition() {
         return definition;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        ColumnDefinition that = (ColumnDefinition) o;
+        return Objects.equals(name, that.name)
+                && Objects.equals(type, that.type)
+                && Objects.equals(definition, that.definition);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, type, definition);
+    }
 }
diff --git 
a/modules/api/src/main/java/org/apache/ignite/catalog/definitions/IndexDefinition.java
 
b/modules/api/src/main/java/org/apache/ignite/catalog/definitions/IndexDefinition.java
index bc8f6d9fc5..6b0647fa33 100644
--- 
a/modules/api/src/main/java/org/apache/ignite/catalog/definitions/IndexDefinition.java
+++ 
b/modules/api/src/main/java/org/apache/ignite/catalog/definitions/IndexDefinition.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.catalog.definitions;
 
 import java.util.List;
+import java.util.Objects;
 import org.apache.ignite.catalog.ColumnSorted;
 import org.apache.ignite.catalog.IndexType;
 import org.jetbrains.annotations.Nullable;
@@ -65,4 +66,23 @@ public class IndexDefinition {
     public List<ColumnSorted> columns() {
         return columns;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        IndexDefinition that = (IndexDefinition) o;
+        return Objects.equals(name, that.name)
+                && type == that.type
+                && Objects.equals(columns, that.columns);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, type, columns);
+    }
 }
diff --git 
a/modules/api/src/main/java/org/apache/ignite/catalog/definitions/TableDefinition.java
 
b/modules/api/src/main/java/org/apache/ignite/catalog/definitions/TableDefinition.java
index fdbccc4726..e6c0fabf50 100644
--- 
a/modules/api/src/main/java/org/apache/ignite/catalog/definitions/TableDefinition.java
+++ 
b/modules/api/src/main/java/org/apache/ignite/catalog/definitions/TableDefinition.java
@@ -206,6 +206,46 @@ public class TableDefinition {
         return new Builder(this);
     }
 
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        TableDefinition that = (TableDefinition) o;
+        return ifNotExists == that.ifNotExists
+                && Objects.equals(tableName, that.tableName)
+                && Objects.equals(schemaName, that.schemaName)
+                && Objects.equals(columns, that.columns)
+                && pkType == that.pkType
+                && Objects.equals(pkColumns, that.pkColumns)
+                && Objects.equals(colocationColumns, that.colocationColumns)
+                && Objects.equals(zoneName, that.zoneName)
+                && Objects.equals(keyClass, that.keyClass)
+                && Objects.equals(valueClass, that.valueClass)
+                && Objects.equals(indexes, that.indexes);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                tableName,
+                schemaName,
+                ifNotExists,
+                columns,
+                pkType,
+                pkColumns,
+                colocationColumns,
+                zoneName,
+                keyClass,
+                valueClass,
+                indexes
+        );
+    }
+
     /**
      * Builder for the table definition.
      */
diff --git 
a/modules/api/src/main/java/org/apache/ignite/catalog/definitions/ZoneDefinition.java
 
b/modules/api/src/main/java/org/apache/ignite/catalog/definitions/ZoneDefinition.java
index ded14aea11..605f4c2918 100644
--- 
a/modules/api/src/main/java/org/apache/ignite/catalog/definitions/ZoneDefinition.java
+++ 
b/modules/api/src/main/java/org/apache/ignite/catalog/definitions/ZoneDefinition.java
@@ -176,6 +176,22 @@ public class ZoneDefinition {
         return new Builder(this);
     }
 
+    @Override
+    public String toString() {
+        return "ZoneDefinition{"
+                + "zoneName='" + zoneName + '\''
+                + ", ifNotExists=" + ifNotExists
+                + ", partitions=" + partitions
+                + ", replicas=" + replicas
+                + ", distributionAlgorithm='" + distributionAlgorithm + '\''
+                + ", dataNodesAutoAdjust=" + dataNodesAutoAdjust
+                + ", dataNodesAutoAdjustScaleUp=" + dataNodesAutoAdjustScaleUp
+                + ", dataNodesAutoAdjustScaleDown=" + 
dataNodesAutoAdjustScaleDown
+                + ", filter='" + filter + '\''
+                + ", storageProfiles='" + storageProfiles + '\''
+                + '}';
+    }
+
     /**
      * Builder for the zone definition.
      */
diff --git 
a/modules/catalog-dsl/src/integrationTest/java/org/apache/ignite/internal/catalog/ItCatalogDslTest.java
 
b/modules/catalog-dsl/src/integrationTest/java/org/apache/ignite/internal/catalog/ItCatalogDslTest.java
index d786d9d680..7d4ecd89e3 100644
--- 
a/modules/catalog-dsl/src/integrationTest/java/org/apache/ignite/internal/catalog/ItCatalogDslTest.java
+++ 
b/modules/catalog-dsl/src/integrationTest/java/org/apache/ignite/internal/catalog/ItCatalogDslTest.java
@@ -31,25 +31,31 @@ import static org.hamcrest.Matchers.nullValue;
 import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
+import org.apache.ignite.catalog.ColumnSorted;
 import org.apache.ignite.catalog.ColumnType;
 import org.apache.ignite.catalog.IgniteCatalog;
+import org.apache.ignite.catalog.IndexType;
+import org.apache.ignite.catalog.definitions.ColumnDefinition;
 import org.apache.ignite.catalog.definitions.TableDefinition;
 import org.apache.ignite.catalog.definitions.ZoneDefinition;
 import org.apache.ignite.internal.ClusterPerClassIntegrationTest;
+import org.apache.ignite.internal.matcher.TableDefinitionMatcher;
+import org.apache.ignite.internal.matcher.ZoneDefinitionMatcher;
 import org.apache.ignite.sql.SqlException;
 import org.apache.ignite.table.KeyValueView;
 import org.apache.ignite.table.RecordView;
+import org.apache.ignite.table.Table;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
 
 @SuppressWarnings("ThrowableNotThrown")
 class ItCatalogDslTest extends ClusterPerClassIntegrationTest {
 
-    static final String POJO_KV_TABLE_NAME = "pojo_kv_test";
+    static final String POJO_KV_TABLE_NAME = "POJO_KV_TEST";
 
     static final String POJO_RECORD_TABLE_NAME = "pojo_record_test";
 
-    static final String ZONE_NAME = "zone_test";
+    static final String ZONE_NAME = "ZONE_TEST";
 
     private static final int KEY = 1;
 
@@ -190,7 +196,7 @@ class ItCatalogDslTest extends 
ClusterPerClassIntegrationTest {
 
     @Test
     void primitiveKeyKvViewFromAnnotation() throws Exception {
-        CompletableFuture<org.apache.ignite.table.Table> tableFuture = 
catalog().createTableAsync(Integer.class, PojoValue.class);
+        CompletableFuture<Table> tableFuture = 
catalog().createTableAsync(Integer.class, PojoValue.class);
         assertThat(tableFuture, will(not(nullValue())));
 
         KeyValueView<Integer, PojoValue> keyValueView = tableFuture.get()
@@ -202,7 +208,7 @@ class ItCatalogDslTest extends 
ClusterPerClassIntegrationTest {
 
     @Test
     void pojoKeyKvViewFromAnnotation() throws Exception {
-        CompletableFuture<org.apache.ignite.table.Table> tableFuture = 
catalog().createTableAsync(PojoKey.class, PojoValue.class);
+        CompletableFuture<Table> tableFuture = 
catalog().createTableAsync(PojoKey.class, PojoValue.class);
         assertThat(tableFuture, will(not(nullValue())));
 
         KeyValueView<PojoKey, PojoValue> keyValueView = tableFuture.get()
@@ -219,7 +225,7 @@ class ItCatalogDslTest extends 
ClusterPerClassIntegrationTest {
                 .value(PojoValue.class)
                 .build();
 
-        CompletableFuture<org.apache.ignite.table.Table> tableFuture = 
catalog().createTableAsync(definition);
+        CompletableFuture<Table> tableFuture = 
catalog().createTableAsync(definition);
         assertThat(tableFuture, will(not(nullValue())));
 
         KeyValueView<Integer, PojoValue> keyValueView = 
tableFuture.get().keyValueView(Integer.class, PojoValue.class);
@@ -235,7 +241,7 @@ class ItCatalogDslTest extends 
ClusterPerClassIntegrationTest {
                 .value(PojoValue.class)
                 .build();
 
-        CompletableFuture<org.apache.ignite.table.Table> tableFuture = 
catalog().createTableAsync(definition);
+        CompletableFuture<Table> tableFuture = 
catalog().createTableAsync(definition);
         assertThat(tableFuture, will(not(nullValue())));
 
         KeyValueView<PojoKey, PojoValue> keyValueView = 
tableFuture.get().keyValueView(PojoKey.class, PojoValue.class);
@@ -246,7 +252,7 @@ class ItCatalogDslTest extends 
ClusterPerClassIntegrationTest {
 
     @Test
     void pojoRecordViewFromAnnotation() throws Exception {
-        CompletableFuture<org.apache.ignite.table.Table> tableFuture = 
catalog().createTableAsync(Pojo.class);
+        CompletableFuture<Table> tableFuture = 
catalog().createTableAsync(Pojo.class);
         assertThat(tableFuture, will(not(nullValue())));
 
         RecordView<Pojo> recordView = tableFuture.get().recordView(Pojo.class);
@@ -259,7 +265,7 @@ class ItCatalogDslTest extends 
ClusterPerClassIntegrationTest {
     void pojoRecordViewFromDefinition() throws Exception {
         TableDefinition definition = 
TableDefinition.builder(POJO_RECORD_TABLE_NAME).record(Pojo.class).build();
 
-        CompletableFuture<org.apache.ignite.table.Table> tableFuture = 
catalog().createTableAsync(definition);
+        CompletableFuture<Table> tableFuture = 
catalog().createTableAsync(definition);
         assertThat(tableFuture, will(not(nullValue())));
 
         RecordView<Pojo> recordView = tableFuture.get().recordView(Pojo.class);
@@ -270,7 +276,7 @@ class ItCatalogDslTest extends 
ClusterPerClassIntegrationTest {
 
     @Test
     void createFromAnnotationAndInsertBySql() throws Exception {
-        CompletableFuture<org.apache.ignite.table.Table> tableFuture = 
catalog().createTableAsync(Pojo.class);
+        CompletableFuture<Table> tableFuture = 
catalog().createTableAsync(Pojo.class);
         assertThat(tableFuture, will(not(nullValue())));
 
         sql("insert into " + POJO_RECORD_TABLE_NAME + " (id, id_str, f_name, 
l_name, str) values (1, '1', 'f', 'l', 's')");
@@ -282,6 +288,66 @@ class ItCatalogDslTest extends 
ClusterPerClassIntegrationTest {
         assertThat(tableFuture.get().recordView(Pojo.class).get(null, pojo), 
is(pojo));
     }
 
+    @Test
+    public void createAndGetDefinitionTest() {
+        ZoneDefinition zoneDefinition = ZoneDefinition
+                .builder(ZONE_NAME)
+                .storageProfiles(DEFAULT_AIPERSIST_PROFILE_NAME)
+                .partitions(3)
+                .replicas(3)
+                .dataNodesAutoAdjustScaleDown(0)
+                .dataNodesAutoAdjustScaleUp(1)
+                .filter("$..*")
+                .distributionAlgorithm("distributionAlgorithm")
+                .build();
+
+        assertThat(catalog().createZoneAsync(zoneDefinition), 
willCompleteSuccessfully());
+
+        ZoneDefinition actual = catalog().zoneDefinition(ZONE_NAME);
+        assertThat(
+                actual,
+                ZoneDefinitionMatcher.isZoneDefinition()
+                        .withZoneName(zoneDefinition.zoneName())
+                        .withPartitions(zoneDefinition.partitions())
+                        .withReplicas(zoneDefinition.replicas())
+                        
.withDataNodesAutoAdjustScaleDown(zoneDefinition.dataNodesAutoAdjustScaleDown())
+                        
.withDataNodesAutoAdjustScaleUp(zoneDefinition.dataNodesAutoAdjustScaleUp())
+                        .withFilter(zoneDefinition.filter())
+        // TODO: https://issues.apache.org/jira/browse/IGNITE-22162
+        // .withDistributionAlgorithm(zoneDefinition.distributionAlgorithm())
+        );
+
+        ColumnDefinition column1 = column("COL1", ColumnType.INT32);
+        ColumnDefinition column2 = column("COL2", ColumnType.INT64);
+        ColumnDefinition column3 = column("COL3", ColumnType.BOOLEAN);
+        ColumnDefinition column4 = column("COL4", ColumnType.VARCHAR);
+        ColumnDefinition column5 = column("COL5", ColumnType.DECIMAL);
+
+
+        TableDefinition definition = 
TableDefinition.builder(POJO_KV_TABLE_NAME)
+                .zone(ZONE_NAME)
+                .columns(List.of(column1, column2, column3, column4, column5))
+                .primaryKey(IndexType.HASH, 
ColumnSorted.column(column1.name()), ColumnSorted.column(column3.name()))
+                .index("INDEX_1", IndexType.HASH, 
ColumnSorted.column(column2.name()), ColumnSorted.column(column5.name()))
+                .colocateBy(column3.name())
+                .build();
+
+        assertThat(catalog().createTableAsync(definition), 
willCompleteSuccessfully());
+
+        TableDefinition actual1 = 
catalog().tableDefinition(POJO_KV_TABLE_NAME);
+        assertThat(
+                actual1,
+                TableDefinitionMatcher.isTableDefinition()
+                        .withTableName(definition.tableName())
+                        .withZoneName(definition.zoneName())
+                        .withColumns(definition.columns())
+                        .withPkType(definition.primaryKeyType())
+                        .withPkColumns(definition.primaryKeyColumns())
+                        .withIndexes(definition.indexes())
+                        .withColocationColumns(definition.colocationColumns())
+        );
+    }
+
     private static IgniteCatalog catalog() {
         return CLUSTER.node(0).catalog();
     }
diff --git 
a/modules/catalog-dsl/src/integrationTest/java/org/apache/ignite/internal/matcher/ColumnDefinitionsMatcher.java
 
b/modules/catalog-dsl/src/integrationTest/java/org/apache/ignite/internal/matcher/ColumnDefinitionsMatcher.java
new file mode 100644
index 0000000000..3819ef80e1
--- /dev/null
+++ 
b/modules/catalog-dsl/src/integrationTest/java/org/apache/ignite/internal/matcher/ColumnDefinitionsMatcher.java
@@ -0,0 +1,62 @@
+/*
+ * 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.matcher;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.apache.ignite.catalog.ColumnType;
+import org.apache.ignite.catalog.definitions.ColumnDefinition;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+
+/**
+ * Matcher implementation of {@link ColumnDefinition}.
+ */
+public class ColumnDefinitionsMatcher extends 
TypeSafeMatcher<List<ColumnDefinition>> {
+
+    private final Map<String, ColumnDefinition> columns;
+
+    public ColumnDefinitionsMatcher(List<ColumnDefinition> columns) {
+        this.columns = 
columns.stream().collect(Collectors.toMap(ColumnDefinition::name, 
Function.identity()));
+    }
+
+    @Override
+    protected boolean matchesSafely(List<ColumnDefinition> item) {
+        for (ColumnDefinition actualCol : item) {
+            ColumnDefinition expectedCol = columns.get(actualCol.name());
+            if (expectedCol == null) {
+                return false;
+            }
+
+            ColumnType<?> actualType = actualCol.type();
+            ColumnType<?> expectedType = expectedCol.type();
+            if (expectedType != null && actualType != null && 
expectedType.type() != actualType.type()) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    public void describeTo(Description description) {
+
+    }
+}
diff --git 
a/modules/catalog-dsl/src/integrationTest/java/org/apache/ignite/internal/matcher/TableDefinitionMatcher.java
 
b/modules/catalog-dsl/src/integrationTest/java/org/apache/ignite/internal/matcher/TableDefinitionMatcher.java
new file mode 100644
index 0000000000..a55d290a6b
--- /dev/null
+++ 
b/modules/catalog-dsl/src/integrationTest/java/org/apache/ignite/internal/matcher/TableDefinitionMatcher.java
@@ -0,0 +1,203 @@
+/*
+ * 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.matcher;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.equalToIgnoringCase;
+
+import java.util.List;
+import org.apache.ignite.catalog.ColumnSorted;
+import org.apache.ignite.catalog.IndexType;
+import org.apache.ignite.catalog.definitions.ColumnDefinition;
+import org.apache.ignite.catalog.definitions.IndexDefinition;
+import org.apache.ignite.catalog.definitions.TableDefinition;
+import org.apache.ignite.internal.testframework.matchers.AnythingMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+/**
+ * Matcher implementation for {@link TableDefinition}.
+ */
+public class TableDefinitionMatcher extends TypeSafeMatcher<TableDefinition> {
+    private Matcher<String> tableNameMatcher = AnythingMatcher.anything();
+
+    private Matcher<String> schemaNameMatcher = AnythingMatcher.anything();
+
+    private Matcher<Boolean> ifNotExistsMatcher = AnythingMatcher.anything();
+
+    private Matcher<List<ColumnDefinition>> columnsMatcher = 
AnythingMatcher.anything();
+
+    private Matcher<IndexType> pkTypeMatcher = AnythingMatcher.anything();
+
+    private Matcher<List<ColumnSorted>> pkColumnsMatcher = 
AnythingMatcher.anything();
+
+    private Matcher<List<String>> colocationColumnsMatcher = 
AnythingMatcher.anything();
+
+    private Matcher<String> zoneNameMatcher = AnythingMatcher.anything();
+
+    private Matcher<Class<?>> keyClassMatcher = AnythingMatcher.anything();
+
+    private Matcher<Class<?>> valueClassMatcher = AnythingMatcher.anything();
+
+    private Matcher<List<IndexDefinition>> indexesMatcher = 
AnythingMatcher.anything();
+
+    public TableDefinitionMatcher withTableNameMatcher(Matcher<String> 
tableNameMatcher) {
+        this.tableNameMatcher = tableNameMatcher;
+        return this;
+    }
+
+    public TableDefinitionMatcher withTableName(String tableName) {
+        return withTableNameMatcher(equalToIgnoringCase(tableName));
+    }
+
+    public TableDefinitionMatcher withSchemaNameMatcher(Matcher<String> 
schemaNameMatcher) {
+        this.schemaNameMatcher = schemaNameMatcher;
+        return this;
+    }
+
+    public TableDefinitionMatcher withSchemaName(String schemaName) {
+        return withSchemaNameMatcher(equalToIgnoringCase(schemaName));
+    }
+
+    public TableDefinitionMatcher withIfNotExistsMatcher(Matcher<Boolean> 
ifNotExists) {
+        this.ifNotExistsMatcher = ifNotExists;
+        return this;
+    }
+
+    public TableDefinitionMatcher withIfNotExists(boolean ifNotExists) {
+        return withIfNotExistsMatcher(equalTo(ifNotExists));
+    }
+
+    public TableDefinitionMatcher 
withColumnsMatcher(Matcher<List<ColumnDefinition>> columns) {
+        this.columnsMatcher = columns;
+        return this;
+    }
+
+    public TableDefinitionMatcher withColumns(List<ColumnDefinition> columns) {
+        return withColumnsMatcher(new ColumnDefinitionsMatcher(columns));
+    }
+
+    public TableDefinitionMatcher withPkTypeMatcher(Matcher<IndexType> pkType) 
{
+        this.pkTypeMatcher = pkType;
+        return this;
+    }
+
+    public TableDefinitionMatcher withPkType(IndexType pkType) {
+        return withPkTypeMatcher(equalTo(pkType));
+    }
+
+    public TableDefinitionMatcher 
withPkColumnsMatcher(Matcher<List<ColumnSorted>> pkColumns) {
+        this.pkColumnsMatcher = pkColumns;
+        return this;
+    }
+
+    public TableDefinitionMatcher withPkColumns(List<ColumnSorted> pkColumns) {
+        return withPkColumnsMatcher(equalTo(pkColumns));
+    }
+
+    public TableDefinitionMatcher 
withColocationColumnsMatcher(Matcher<List<String>> colocationColumns) {
+        this.colocationColumnsMatcher = colocationColumns;
+        return this;
+    }
+
+    public TableDefinitionMatcher withColocationColumns(List<String> 
colocationColumns) {
+        return withColocationColumnsMatcher(equalTo(colocationColumns));
+    }
+
+    public TableDefinitionMatcher withZoneNameMatcher(Matcher<String> 
zoneName) {
+        this.zoneNameMatcher = zoneName;
+        return this;
+    }
+
+    public TableDefinitionMatcher withZoneName(String zoneName) {
+        return withZoneNameMatcher(equalTo(zoneName));
+    }
+
+    public TableDefinitionMatcher withKeyClassMatcher(Matcher<Class<?>> 
keyClass) {
+        this.keyClassMatcher = keyClass;
+        return this;
+    }
+
+    public TableDefinitionMatcher withKeyClass(Class<?> keyClass) {
+        return withKeyClassMatcher(equalTo(keyClass));
+    }
+
+    public TableDefinitionMatcher withValueClassMatcher(Matcher<Class<?>> 
valueClass) {
+        this.valueClassMatcher = valueClass;
+        return this;
+    }
+
+    public TableDefinitionMatcher withValueClass(Class<?> valueClass) {
+        return withValueClassMatcher(equalTo(valueClass));
+    }
+
+    public TableDefinitionMatcher 
withIndexesMatcher(Matcher<List<IndexDefinition>> indexes) {
+        this.indexesMatcher = indexes;
+        return this;
+    }
+
+    public TableDefinitionMatcher withIndexes(List<IndexDefinition> indexes) {
+        return withIndexesMatcher(equalTo(indexes));
+    }
+
+    public static TableDefinitionMatcher isTableDefinition() {
+        return new TableDefinitionMatcher();
+    }
+
+    @Override
+    protected boolean matchesSafely(TableDefinition tableDefinition) {
+        return tableNameMatcher.matches(tableDefinition.tableName())
+                && schemaNameMatcher.matches(tableDefinition.schemaName())
+                && ifNotExistsMatcher.matches(tableDefinition.ifNotExists())
+                && columnsMatcher.matches(tableDefinition.columns())
+                && pkTypeMatcher.matches(tableDefinition.primaryKeyType())
+                && 
pkColumnsMatcher.matches(tableDefinition.primaryKeyColumns())
+                && 
colocationColumnsMatcher.matches(tableDefinition.colocationColumns())
+                && zoneNameMatcher.matches(tableDefinition.zoneName())
+                && keyClassMatcher.matches(tableDefinition.keyClass())
+                && valueClassMatcher.matches(tableDefinition.valueClass())
+                && indexesMatcher.matches(tableDefinition.indexes());
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        description.appendText("Table definition with ")
+                .appendText("table name 
").appendDescriptionOf(tableNameMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("schema name 
").appendDescriptionOf(schemaNameMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("if not exists 
").appendDescriptionOf(ifNotExistsMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("columns ").appendDescriptionOf(columnsMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("pk type ").appendDescriptionOf(pkTypeMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("pk columns 
").appendDescriptionOf(pkColumnsMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("colocation columns 
").appendDescriptionOf(columnsMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("zone name ").appendDescriptionOf(zoneNameMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("key class ").appendDescriptionOf(keyClassMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("value class 
").appendDescriptionOf(valueClassMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("indexes ").appendDescriptionOf(indexesMatcher);
+    }
+}
diff --git 
a/modules/catalog-dsl/src/integrationTest/java/org/apache/ignite/internal/matcher/ZoneDefinitionMatcher.java
 
b/modules/catalog-dsl/src/integrationTest/java/org/apache/ignite/internal/matcher/ZoneDefinitionMatcher.java
new file mode 100644
index 0000000000..d8003438a6
--- /dev/null
+++ 
b/modules/catalog-dsl/src/integrationTest/java/org/apache/ignite/internal/matcher/ZoneDefinitionMatcher.java
@@ -0,0 +1,186 @@
+/*
+ * 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.matcher;
+
+import static org.hamcrest.Matchers.equalTo;
+
+import org.apache.ignite.catalog.definitions.ZoneDefinition;
+import org.apache.ignite.internal.testframework.matchers.AnythingMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+/**
+ * Matcher implementation for {@link ZoneDefinition}.
+ */
+public class ZoneDefinitionMatcher extends TypeSafeMatcher<ZoneDefinition> {
+    private Matcher<String> zoneNameMatcher = AnythingMatcher.anything();
+
+    private Matcher<Boolean> ifNotExistsMatcher = AnythingMatcher.anything();
+
+    private Matcher<Integer> partitionsMatcher = AnythingMatcher.anything();
+
+    private Matcher<Integer> replicasMatcher = AnythingMatcher.anything();
+
+    private Matcher<String> distributionAlgorithmMatcher = 
AnythingMatcher.anything();
+
+    private Matcher<Integer> dataNodesAutoAdjustMatcher = 
AnythingMatcher.anything();
+
+    private Matcher<Integer> dataNodesAutoAdjustScaleUpMatcher = 
AnythingMatcher.anything();
+
+    private Matcher<Integer> dataNodesAutoAdjustScaleDownMatcher = 
AnythingMatcher.anything();
+
+    private Matcher<String> filterMatcher = AnythingMatcher.anything();
+
+    private Matcher<String> storageProfiles = AnythingMatcher.anything();
+
+    public ZoneDefinitionMatcher withZoneNameMatcher(Matcher<String> 
zoneNameMatcher) {
+        this.zoneNameMatcher = zoneNameMatcher;
+        return this;
+    }
+
+    public ZoneDefinitionMatcher withZoneName(String zoneName) {
+        return withZoneNameMatcher(equalTo(zoneName));
+    }
+
+    public ZoneDefinitionMatcher withIfNotExistsMatcher(Matcher<Boolean> 
ifNotExistsMatcher) {
+        this.ifNotExistsMatcher = ifNotExistsMatcher;
+        return this;
+    }
+
+    public ZoneDefinitionMatcher withIfNotExists(boolean ifNotExists) {
+        return withIfNotExistsMatcher(equalTo(ifNotExists));
+    }
+
+    public ZoneDefinitionMatcher withPartitionsMatcher(Matcher<Integer> 
partitionsMatcher) {
+        this.partitionsMatcher = partitionsMatcher;
+        return this;
+    }
+
+    public ZoneDefinitionMatcher withPartitions(int partitions) {
+        return withPartitionsMatcher(equalTo(partitions));
+    }
+
+    public ZoneDefinitionMatcher withReplicasMatcher(Matcher<Integer> 
replicasMatcher) {
+        this.replicasMatcher = replicasMatcher;
+        return this;
+    }
+
+    public ZoneDefinitionMatcher withReplicas(int replicas) {
+        return withReplicasMatcher(equalTo(replicas));
+    }
+
+    public ZoneDefinitionMatcher 
withDistributionAlgorithmMatcher(Matcher<String> 
withDistributionAlgorithmMatcher) {
+        this.distributionAlgorithmMatcher = withDistributionAlgorithmMatcher;
+        return this;
+    }
+
+    public ZoneDefinitionMatcher withDistributionAlgorithm(String 
distributionAlgorithm) {
+        return 
withDistributionAlgorithmMatcher(equalTo(distributionAlgorithm));
+    }
+
+    public ZoneDefinitionMatcher 
withDataNodesAutoAdjustMatcher(Matcher<Integer> dataNodesAutoAdjustMatcher) {
+        this.dataNodesAutoAdjustMatcher = dataNodesAutoAdjustMatcher;
+        return this;
+    }
+
+    public ZoneDefinitionMatcher withDataNodesAutoAdjust(int 
dataNodesAutoAdjust) {
+        return withDataNodesAutoAdjustMatcher(equalTo(dataNodesAutoAdjust));
+    }
+
+    public ZoneDefinitionMatcher withDataNodesAutoAdjustScaleUpMatcher(
+            Matcher<Integer> dataNodesAutoAdjustScaleUpMatcher) {
+        this.dataNodesAutoAdjustScaleUpMatcher = 
dataNodesAutoAdjustScaleUpMatcher;
+        return this;
+    }
+
+    public ZoneDefinitionMatcher withDataNodesAutoAdjustScaleUp(int 
dataNodesAutoAdjustScaleUp) {
+        return 
withDataNodesAutoAdjustScaleUpMatcher(equalTo(dataNodesAutoAdjustScaleUp));
+    }
+
+    public ZoneDefinitionMatcher withDataNodesAutoAdjustScaleDownMatcher(
+            Matcher<Integer> dataNodesAutoAdjustScaleDownMatcher) {
+        this.dataNodesAutoAdjustScaleDownMatcher = 
dataNodesAutoAdjustScaleDownMatcher;
+        return this;
+    }
+
+    public ZoneDefinitionMatcher withDataNodesAutoAdjustScaleDown(int 
dataNodesAutoAdjustScaleDown) {
+        return 
withDataNodesAutoAdjustScaleDownMatcher(equalTo(dataNodesAutoAdjustScaleDown));
+    }
+
+    public ZoneDefinitionMatcher withFilterMatcher(Matcher<String> 
filterMatcher) {
+        this.filterMatcher = filterMatcher;
+        return this;
+    }
+
+    public ZoneDefinitionMatcher withFilter(String filter) {
+        return withFilterMatcher(equalTo(filter));
+    }
+
+    public ZoneDefinitionMatcher withStorageProfilesMatcher(Matcher<String> 
storageProfiles) {
+        this.storageProfiles = storageProfiles;
+        return this;
+    }
+
+    public ZoneDefinitionMatcher withStorageProfiles(String storageProfiles) {
+        return withStorageProfilesMatcher(equalTo(storageProfiles));
+    }
+
+    public static ZoneDefinitionMatcher isZoneDefinition() {
+        return new ZoneDefinitionMatcher();
+    }
+
+    @Override
+    protected boolean matchesSafely(ZoneDefinition zoneDefinition) {
+        return zoneNameMatcher.matches(zoneDefinition.zoneName())
+                && ifNotExistsMatcher.matches(zoneDefinition.ifNotExists())
+                && partitionsMatcher.matches(zoneDefinition.partitions())
+                && replicasMatcher.matches(zoneDefinition.replicas())
+                && 
distributionAlgorithmMatcher.matches(zoneDefinition.distributionAlgorithm())
+                && 
dataNodesAutoAdjustMatcher.matches(zoneDefinition.dataNodesAutoAdjust())
+                && zoneNameMatcher.matches(zoneDefinition.zoneName())
+                && 
dataNodesAutoAdjustScaleUpMatcher.matches(zoneDefinition.dataNodesAutoAdjustScaleUp())
+                && 
dataNodesAutoAdjustScaleDownMatcher.matches(zoneDefinition.dataNodesAutoAdjustScaleDown())
+                && filterMatcher.matches(zoneDefinition.filter())
+                && storageProfiles.matches(zoneDefinition.storageProfiles());
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        description.appendText("Zone definition with ")
+                .appendText("zone name ").appendDescriptionOf(zoneNameMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("if not exists 
").appendDescriptionOf(ifNotExistsMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("partitions 
").appendDescriptionOf(partitionsMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("replicas ").appendDescriptionOf(replicasMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("affinity 
").appendDescriptionOf(distributionAlgorithmMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("data nodes auto adjust 
").appendDescriptionOf(dataNodesAutoAdjustMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("data nodes auto adjust scale up 
").appendDescriptionOf(dataNodesAutoAdjustScaleUpMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("data nodes auto adjust scale down 
").appendDescriptionOf(dataNodesAutoAdjustScaleDownMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("filter ").appendDescriptionOf(filterMatcher)
+                .appendText(System.lineSeparator())
+                .appendText("storage profiles 
").appendDescriptionOf(storageProfiles);
+    }
+}
diff --git 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/CreateFromDefinitionImpl.java
 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/CreateFromDefinitionImpl.java
index c5dc84dc6a..7fb190cbdb 100644
--- 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/CreateFromDefinitionImpl.java
+++ 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/CreateFromDefinitionImpl.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.catalog.sql;
 
 import static 
org.apache.ignite.internal.catalog.sql.CreateFromAnnotationsImpl.processColumns;
+import static 
org.apache.ignite.internal.catalog.sql.QueryUtils.isGreaterThanOrEqualToZero;
 import static 
org.apache.ignite.internal.catalog.sql.QueryUtils.isGreaterThanZero;
 
 import java.util.ArrayList;
@@ -70,20 +71,19 @@ class CreateFromDefinitionImpl extends 
AbstractCatalogQuery<TableZoneId> {
             createZone.distributionAlgorithm(def.distributionAlgorithm());
         }
 
-        if (isGreaterThanZero(def.dataNodesAutoAdjust())) {
+        if (isGreaterThanOrEqualToZero(def.dataNodesAutoAdjust())) {
             createZone.dataNodesAutoAdjust(def.dataNodesAutoAdjust());
         }
-        if (isGreaterThanZero(def.dataNodesAutoAdjustScaleUp())) {
+        if (isGreaterThanOrEqualToZero(def.dataNodesAutoAdjustScaleUp())) {
             
createZone.dataNodesAutoAdjustScaleUp(def.dataNodesAutoAdjustScaleUp());
         }
-        if (isGreaterThanZero(def.dataNodesAutoAdjustScaleDown())) {
+        if (isGreaterThanOrEqualToZero(def.dataNodesAutoAdjustScaleDown())) {
             
createZone.dataNodesAutoAdjustScaleDown(def.dataNodesAutoAdjustScaleDown());
         }
 
         if (!StringUtils.nullOrBlank(def.filter())) {
             createZone.filter(def.filter());
         }
-
         return this;
     }
 
diff --git 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/CreateTableImpl.java
 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/CreateTableImpl.java
index db92258fc1..d29159e8b6 100644
--- 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/CreateTableImpl.java
+++ 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/CreateTableImpl.java
@@ -38,7 +38,7 @@ class CreateTableImpl extends AbstractCatalogQuery<Name> {
 
     private final List<Constraint> constraints = new ArrayList<>();
 
-    private final List<WithOption> withOptions = new ArrayList<>();
+    private final List<Option> withOptions = new ArrayList<>();
 
     private Colocate colocate;
 
@@ -119,7 +119,7 @@ class CreateTableImpl extends AbstractCatalogQuery<Name> {
     CreateTableImpl zone(String zone) {
         Objects.requireNonNull(zone, "Zone name must not be null.");
 
-        withOptions.add(WithOption.primaryZone(zone));
+        withOptions.add(Option.primaryZone(zone));
         return this;
     }
 
diff --git 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/CreateZoneImpl.java
 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/CreateZoneImpl.java
index dc426c4942..1a35774b4b 100644
--- 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/CreateZoneImpl.java
+++ 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/CreateZoneImpl.java
@@ -29,7 +29,7 @@ class CreateZoneImpl extends AbstractCatalogQuery<Name> {
 
     private boolean ifNotExists;
 
-    private final List<WithOption> withOptions = new ArrayList<>();
+    private final List<Option> withOptions = new ArrayList<>();
 
     /**
      * Constructor for internal usage.
@@ -60,21 +60,21 @@ class CreateZoneImpl extends AbstractCatalogQuery<Name> {
     CreateZoneImpl replicas(Integer n) {
         Objects.requireNonNull(n, "Replicas count must not be null.");
 
-        withOptions.add(WithOption.replicas(n));
+        withOptions.add(Option.replicas(n));
         return this;
     }
 
     CreateZoneImpl partitions(Integer n) {
         Objects.requireNonNull(n, "Partitions must not be null.");
 
-        withOptions.add(WithOption.partitions(n));
+        withOptions.add(Option.partitions(n));
         return this;
     }
 
     CreateZoneImpl distributionAlgorithm(String distributionAlgorithm) {
         Objects.requireNonNull(distributionAlgorithm, "Partition distribution 
algorithm must not be null.");
 
-        
withOptions.add(WithOption.distributionAlgorithm(distributionAlgorithm));
+        withOptions.add(Option.distributionAlgorithm(distributionAlgorithm));
         return this;
     }
 
@@ -84,35 +84,35 @@ class CreateZoneImpl extends AbstractCatalogQuery<Name> {
                 "Timeout between node added or node left topology event itself 
and data nodes switch must not be null."
         );
 
-        withOptions.add(WithOption.dataNodesAutoAdjust(adjust));
+        withOptions.add(Option.dataNodesAutoAdjust(adjust));
         return this;
     }
 
     CreateZoneImpl dataNodesAutoAdjustScaleUp(Integer adjust) {
         Objects.requireNonNull(adjust, "Timeout between node added topology 
event itself and data nodes switch must not be null.");
 
-        withOptions.add(WithOption.dataNodesAutoAdjustScaleUp(adjust));
+        withOptions.add(Option.dataNodesAutoAdjustScaleUp(adjust));
         return this;
     }
 
     CreateZoneImpl dataNodesAutoAdjustScaleDown(Integer adjust) {
         Objects.requireNonNull(adjust, "Timeout between node left topology 
event itself and data nodes switch must not be null.");
 
-        withOptions.add(WithOption.dataNodesAutoAdjustScaleDown(adjust));
+        withOptions.add(Option.dataNodesAutoAdjustScaleDown(adjust));
         return this;
     }
 
     CreateZoneImpl filter(String filter) {
         Objects.requireNonNull(filter, "Filter must not be null.");
 
-        withOptions.add(WithOption.filter(filter));
+        withOptions.add(Option.filter(filter));
         return this;
     }
 
     CreateZoneImpl storageProfiles(String storageProfiles) {
         Objects.requireNonNull(storageProfiles, "Storage profiles must not be 
null");
 
-        withOptions.add(WithOption.storageProfiles(storageProfiles));
+        withOptions.add(Option.storageProfiles(storageProfiles));
         return this;
     }
 
diff --git 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/IgniteCatalogSqlImpl.java
 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/IgniteCatalogSqlImpl.java
index 1ee2c4a170..c749203cbc 100644
--- 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/IgniteCatalogSqlImpl.java
+++ 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/IgniteCatalogSqlImpl.java
@@ -17,16 +17,20 @@
 
 package org.apache.ignite.internal.catalog.sql;
 
+import static org.apache.ignite.internal.catalog.sql.Option.name;
 import static 
org.apache.ignite.internal.lang.IgniteExceptionMapperUtil.mapToPublicException;
 import static org.apache.ignite.internal.util.ExceptionUtils.unwrapCause;
 
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionException;
 import org.apache.ignite.catalog.IgniteCatalog;
 import org.apache.ignite.catalog.definitions.TableDefinition;
 import org.apache.ignite.catalog.definitions.ZoneDefinition;
+import org.apache.ignite.internal.util.CompletableFutures;
 import org.apache.ignite.internal.util.ExceptionUtils;
 import org.apache.ignite.sql.IgniteSql;
+import org.apache.ignite.sql.SqlRow;
 import org.apache.ignite.table.IgniteTables;
 import org.apache.ignite.table.Table;
 
@@ -82,12 +86,29 @@ public class IgniteCatalogSqlImpl implements IgniteCatalog {
         return join(createTableAsync(definition));
     }
 
+    @Override
+    public CompletableFuture<TableDefinition> tableDefinitionAsync(String 
tableName) {
+        TableDefinitionCollector collector = new 
TableDefinitionCollector(tableName, sql);
+
+        return collector.collectDefinition().thenApply(builder -> {
+            if (builder != null) {
+                return builder.build();
+            }
+            return null;
+        });
+    }
+
+    @Override
+    public TableDefinition tableDefinition(String tableName) {
+        return join(tableDefinitionAsync(tableName));
+    }
+
     @Override
     public CompletableFuture<Void> createZoneAsync(ZoneDefinition definition) {
         return new CreateFromDefinitionImpl(sql)
                 .from(definition)
                 .executeAsync()
-                .thenRun(() -> {});
+                .thenApply(unused -> null);
     }
 
     @Override
@@ -95,13 +116,52 @@ public class IgniteCatalogSqlImpl implements IgniteCatalog 
{
         join(createZoneAsync(definition));
     }
 
+    @Override
+    public CompletableFuture<ZoneDefinition> zoneDefinitionAsync(String 
zoneName) {
+        List<String> zoneViewColumns = List.of(
+                "PARTITIONS",
+                "REPLICAS",
+                "DATA_NODES_AUTO_ADJUST_SCALE_UP",
+                "DATA_NODES_AUTO_ADJUST_SCALE_DOWN",
+                "DATA_NODES_FILTER"
+        );
+        return new SelectFromView<>(sql, zoneViewColumns, "ZONES", 
name(zoneName), row -> toZoneDefinitionBuilder(zoneName, row))
+                .executeAsync()
+                .thenApply(zoneDefinitions -> {
+                    if (zoneDefinitions.isEmpty()) {
+                        return null;
+                    }
+                    assert zoneDefinitions.size() == 1;
+
+                    return zoneDefinitions.get(0);
+                })
+                .thenCompose(
+                        zoneDefinition -> {
+                            if (zoneDefinition == null) {
+                                return 
CompletableFutures.nullCompletedFuture();
+                            }
+                            return new SelectFromView<>(sql,
+                                    List.of("STORAGE_PROFILE"),
+                                    "ZONE_STORAGE_PROFILES",
+                                    Option.zoneName(zoneName),
+                                    row -> row.stringValue("STORAGE_PROFILE")
+                            ).executeAsync()
+                                    .thenApply(profiles -> 
zoneDefinition.storageProfiles(String.join(", ", profiles)).build());
+                        });
+    }
+
+    @Override
+    public ZoneDefinition zoneDefinition(String zoneName) {
+        return join(zoneDefinitionAsync(zoneName));
+    }
+
     @Override
     public CompletableFuture<Void> dropTableAsync(TableDefinition definition) {
         return new DropTableImpl(sql)
                 .name(definition.schemaName(), definition.tableName())
                 .ifExists()
                 .executeAsync()
-                .thenRun(() -> {});
+                .thenApply(unused -> null);
     }
 
     @Override
@@ -110,7 +170,7 @@ public class IgniteCatalogSqlImpl implements IgniteCatalog {
                 .name(name)
                 .ifExists()
                 .executeAsync()
-                .thenRun(() -> {});
+                .thenApply(unused -> null);
     }
 
     @Override
@@ -129,7 +189,7 @@ public class IgniteCatalogSqlImpl implements IgniteCatalog {
                 .name(definition.zoneName())
                 .ifExists()
                 .executeAsync()
-                .thenRun(() -> {});
+                .thenApply(unused -> null);
     }
 
     @Override
@@ -138,7 +198,7 @@ public class IgniteCatalogSqlImpl implements IgniteCatalog {
                 .name(name)
                 .ifExists()
                 .executeAsync()
-                .thenRun(() -> {});
+                .thenApply(unused -> null);
     }
 
     @Override
@@ -151,6 +211,21 @@ public class IgniteCatalogSqlImpl implements IgniteCatalog 
{
         join(dropZoneAsync(name));
     }
 
+    private static ZoneDefinition.Builder toZoneDefinitionBuilder(String 
zoneName, SqlRow row) {
+        int partitions = row.intValue("PARTITIONS");
+        int replicas = row.intValue("REPLICAS");
+        int dataNodesAutoAdjustScaleUp = 
row.intValue("DATA_NODES_AUTO_ADJUST_SCALE_UP");
+        int dataNodesAutoAdjustScaleDown = 
row.intValue("DATA_NODES_AUTO_ADJUST_SCALE_DOWN");
+        String filter = row.stringValue("DATA_NODES_FILTER");
+
+        return ZoneDefinition.builder(zoneName)
+                .partitions(partitions)
+                .replicas(replicas)
+                .dataNodesAutoAdjustScaleUp(dataNodesAutoAdjustScaleUp)
+                .dataNodesAutoAdjustScaleDown(dataNodesAutoAdjustScaleDown)
+                .filter(filter);
+    }
+
     private static <R> R join(CompletableFuture<R> future) {
         try {
             return future.join();
diff --git 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/Option.java
 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/Option.java
new file mode 100644
index 0000000000..56bdb665f5
--- /dev/null
+++ 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/Option.java
@@ -0,0 +1,100 @@
+/*
+ * 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.catalog.sql;
+
+class Option extends QueryPart {
+    private final String name;
+
+    private final Object value;
+
+    private Option(String name, Object value) {
+        this.name = name;
+        this.value = value;
+    }
+
+    public static Option primaryZone(String zone) {
+        return new Option("PRIMARY_ZONE", zone.toUpperCase());
+    }
+
+    public static Option partitions(Integer partitions) {
+        return new Option("PARTITIONS", partitions);
+    }
+
+    public static Option replicas(Integer replicas) {
+        return new Option("REPLICAS", replicas);
+    }
+
+    public static Option dataNodesAutoAdjust(Integer adjust) {
+        return new Option("DATA_NODES_AUTO_ADJUST", adjust);
+    }
+
+    public static Option dataNodesAutoAdjustScaleUp(Integer adjust) {
+        return new Option("DATA_NODES_AUTO_ADJUST_SCALE_UP", adjust);
+    }
+
+    public static Option dataNodesAutoAdjustScaleDown(Integer adjust) {
+        return new Option("DATA_NODES_AUTO_ADJUST_SCALE_DOWN", adjust);
+    }
+
+    public static Option distributionAlgorithm(String distributionAlgorithm) {
+        return new Option("DISTRIBUTION_ALGORITHM", distributionAlgorithm);
+    }
+
+    public static Option dataRegion(String dataRegion) {
+        return new Option("DATAREGION", dataRegion);
+    }
+
+    public static Option storageProfiles(String storageProfiles) {
+        return new Option("STORAGE_PROFILES", storageProfiles);
+    }
+
+    public static Option name(String name) {
+        return new Option("NAME", name);
+    }
+
+    public static Option tableName(String tableName) {
+        return new Option("TABLE_NAME", tableName);
+    }
+
+    public static Option zoneName(String zoneName) {
+        return new Option("ZONE_NAME", zoneName);
+    }
+
+    public static Option indexId(int indexId) {
+        return new Option("INDEX_ID", indexId);
+    }
+
+    public static Option filter(String filter) {
+        return new Option("DATA_NODES_FILTER", filter);
+    }
+
+    @Override
+    protected void accept(QueryContext ctx) {
+        ctx.sql(name).sql("=");
+        boolean isStringValue = value instanceof String;
+        if (isStringValue) {
+            String strValue = value.toString();
+            char quoteChar = '\'';
+            if (!QueryUtils.isQuoted(strValue, quoteChar)) {
+                ctx.sql(quoteChar).sql(strValue).sql(quoteChar);
+            }
+        } else {
+            ctx.sql(value.toString());
+        }
+    }
+}
diff --git 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/QueryContext.java
 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/QueryContext.java
index d2d23f5699..6cd438e408 100644
--- 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/QueryContext.java
+++ 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/QueryContext.java
@@ -47,6 +47,13 @@ class QueryContext {
         return sql.toString();
     }
 
+    QueryContext sql(char c) {
+        applyNewLine();
+        sql.append(c);
+        resetSeparatorFlags();
+        return this;
+    }
+
     QueryContext sql(String s) {
         applyNewLine();
         sql.append(s);
diff --git 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/QueryUtils.java
 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/QueryUtils.java
index f6d7de9deb..9d98da51f2 100644
--- 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/QueryUtils.java
+++ 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/QueryUtils.java
@@ -53,6 +53,10 @@ class QueryUtils {
         return n != null && n > 0;
     }
 
+    static boolean isGreaterThanOrEqualToZero(Integer n) {
+        return n != null && n >= 0;
+    }
+
     /**
      * Converts comma-separated string to a list of strings, leading and 
trailing spaces are trimmed.
      *
@@ -65,4 +69,8 @@ class QueryUtils {
                 .filter(s -> !s.isEmpty())
                 .collect(Collectors.toList());
     }
+
+    static boolean isQuoted(String string, char quoteChar) {
+        return string.charAt(0) == quoteChar && string.charAt(string.length() 
- 1) == quoteChar;
+    }
 }
diff --git 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/SelectFromView.java
 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/SelectFromView.java
new file mode 100644
index 0000000000..f880d40a1c
--- /dev/null
+++ 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/SelectFromView.java
@@ -0,0 +1,91 @@
+/*
+ * 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.catalog.sql;
+
+import static 
org.apache.ignite.internal.util.CompletableFutures.nullCompletedFuture;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
+import org.apache.ignite.sql.IgniteSql;
+import org.apache.ignite.sql.SqlRow;
+import org.apache.ignite.sql.async.AsyncResultSet;
+
+class SelectFromView<T> extends AbstractCatalogQuery<List<T>> {
+    private final String viewName;
+
+    private final List<String> columns;
+
+    private final List<Option> whereOptions = new ArrayList<>();
+
+    private final Function<SqlRow, T> mapper;
+
+    SelectFromView(IgniteSql sql, List<String> columns, String viewName, 
Option whereOption, Function<SqlRow, T> mapper) {
+        this(sql, columns, viewName, List.of(whereOption), mapper);
+    }
+
+    SelectFromView(IgniteSql sql, List<String> columns, String viewName, 
List<Option> whereOptions, Function<SqlRow, T> mapper) {
+        super(sql);
+        this.viewName = viewName;
+        this.columns = columns;
+        this.whereOptions.addAll(whereOptions);
+        this.mapper = mapper;
+    }
+
+    @Override
+    public CompletableFuture<List<T>> executeAsync() {
+        return sql.executeAsync(null, toString()).thenCompose(resultSet -> {
+            List<T> result = new ArrayList<>();
+            return iterate(resultSet, result).thenApply(unused -> result);
+        });
+    }
+
+    private CompletableFuture<Void> iterate(AsyncResultSet<SqlRow> resultSet, 
List<T> result) {
+        for (SqlRow row : resultSet.currentPage()) {
+            result.add(mapper.apply(row));
+        }
+        if (resultSet.hasMorePages()) {
+            return resultSet.fetchNextPage().thenCompose(nextPage -> 
iterate(nextPage, result));
+        } else {
+            return nullCompletedFuture();
+        }
+    }
+
+    @Override
+    // Noop
+    protected List<T> result() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    protected void accept(QueryContext ctx) {
+        ctx.sql("SELECT " + String.join(", ", columns) + " FROM SYSTEM." + 
viewName + " ");
+
+        if (!whereOptions.isEmpty()) {
+            ctx.sql("WHERE ");
+            for (Option option : whereOptions) {
+                option.accept(ctx);
+            }
+        }
+
+        System.out.println("SELECT");
+        System.out.println(ctx.getSql());
+    }
+}
diff --git 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/TableDefinitionCollector.java
 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/TableDefinitionCollector.java
new file mode 100644
index 0000000000..5102cf5e3d
--- /dev/null
+++ 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/TableDefinitionCollector.java
@@ -0,0 +1,171 @@
+/*
+ * 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.catalog.sql;
+
+import static org.apache.ignite.internal.catalog.sql.Option.name;
+import static org.apache.ignite.internal.catalog.sql.Option.tableName;
+import static org.apache.ignite.internal.catalog.sql.QueryUtils.splitByComma;
+import static 
org.apache.ignite.internal.util.CompletableFutures.nullCompletedFuture;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+import org.apache.ignite.catalog.ColumnSorted;
+import org.apache.ignite.catalog.ColumnType;
+import org.apache.ignite.catalog.IndexType;
+import org.apache.ignite.catalog.definitions.ColumnDefinition;
+import org.apache.ignite.catalog.definitions.TableDefinition;
+import org.apache.ignite.catalog.definitions.TableDefinition.Builder;
+import org.apache.ignite.sql.IgniteSql;
+
+/**
+ * Table definition information collector from system views.
+ */
+public class TableDefinitionCollector {
+    private static final List<String> TABLE_VIEW_COLUMNS = List.of("SCHEMA", 
"PK_INDEX_ID", "ZONE", "COLOCATION_KEY_INDEX");
+
+    private static final List<String> INDEX_VIEW_COLUMNS = List.of("INDEX_ID", 
"INDEX_NAME", "COLUMNS", "TYPE");
+
+    private static final List<String> TABLE_COLUMNS_VIEW_COLUMNS = 
List.of("COLUMN_NAME", "TYPE", "LENGTH", "PREC", "SCALE",
+            "NULLABLE");
+
+    private final String tableName;
+
+    private final IgniteSql sql;
+
+    public TableDefinitionCollector(String tableName, IgniteSql sql) {
+        this.tableName = tableName;
+        this.sql = sql;
+    }
+
+    /**
+     * Collect all table info from corresponding system views.
+     *
+     * @return Future with table definition build or {@code null} if table 
doesn't exist.
+     */
+    public CompletableFuture<TableDefinition.Builder> collectDefinition() {
+        return collectTableInfo()
+                .thenCompose(builder -> {
+                    if (builder == null) {
+                        return nullCompletedFuture();
+                    } else {
+                        return 
collectIndexes(builder).thenCompose(this::collectColumns);
+                    }
+                });
+    }
+
+    private CompletableFuture<TableDefinitionBuilderWithIndexId> 
collectTableInfo() {
+        return new SelectFromView<>(sql, TABLE_VIEW_COLUMNS, "TABLES", 
name(tableName), row -> {
+            String schema = row.stringValue("SCHEMA");
+            int indexId = row.intValue("PK_INDEX_ID");
+            String zone = row.stringValue("ZONE");
+            String colocationColumns = row.stringValue("COLOCATION_KEY_INDEX");
+            Builder builder = TableDefinition.builder(tableName).schema(schema)
+                    .zone(zone)
+                    .colocateBy(splitByComma(colocationColumns));
+            return new TableDefinitionBuilderWithIndexId(builder, indexId);
+        }).executeAsync().thenApply(definitions -> {
+            if (definitions.isEmpty()) {
+                return null;
+            }
+
+            assert definitions.size() == 1;
+
+            return definitions.get(0);
+        });
+    }
+
+    private CompletableFuture<Builder> 
collectIndexes(TableDefinitionBuilderWithIndexId tableDefinitionWithPkIndexId) {
+        return new SelectFromView<>(sql, INDEX_VIEW_COLUMNS, "INDEXES", 
tableName(tableName), row -> {
+            int pkIndexId = tableDefinitionWithPkIndexId.indexId;
+
+            int indexId = row.intValue("INDEX_ID");
+            String indexName = row.stringValue("INDEX_NAME");
+            String columns = row.stringValue("COLUMNS");
+            String type = row.stringValue("TYPE");
+
+            return Index.create(indexName, type, columns, indexId == 
pkIndexId);
+        }).executeAsync().thenApply(indexes -> {
+            Builder builder = tableDefinitionWithPkIndexId.builder;
+            for (Index index : indexes) {
+                if (index.isPkIndex) {
+                    builder.primaryKey(index.type, index.columns);
+                } else {
+                    builder.index(index.name, index.type, index.columns);
+                }
+            }
+            return builder;
+        });
+    }
+
+    private CompletableFuture<TableDefinition.Builder> 
collectColumns(TableDefinition.Builder builder) {
+        return new SelectFromView<>(sql, TABLE_COLUMNS_VIEW_COLUMNS, 
"TABLE_COLUMNS", tableName(tableName),
+                row -> {
+                    String columnName = row.stringValue("COLUMN_NAME");
+                    String type = row.stringValue("TYPE");
+                    int length = row.intValue("LENGTH");
+                    int precision = row.intValue("PREC");
+                    int scale = row.intValue("SCALE");
+                    boolean nullable = row.booleanValue("NULLABLE");
+
+                    Class<?> typeClass = 
org.apache.ignite.sql.ColumnType.valueOf(type).javaClass();
+                    return ColumnDefinition.column(columnName, 
ColumnType.of(typeClass, length, precision, scale, nullable));
+                }).executeAsync().thenApply(builder::columns);
+    }
+
+    private static class Index {
+        private final String name;
+
+        private final IndexType type;
+
+        private final List<ColumnSorted> columns;
+
+        private final boolean isPkIndex;
+
+        private Index(String name, IndexType type, List<ColumnSorted> columns, 
boolean isPkIndex) {
+            this.name = name;
+            this.type = type;
+            this.columns = columns;
+            this.isPkIndex = isPkIndex;
+        }
+
+        private static Index create(String name, String type, String columns, 
boolean isPkIndex) {
+            return new Index(name, IndexType.valueOf(type), fromRaw(columns), 
isPkIndex);
+        }
+    }
+
+    private static List<ColumnSorted> fromRaw(String columns) {
+        return Arrays.stream(columns.split(","))
+                .map(String::trim)
+                .filter(s -> !s.isEmpty())
+                .map(ColumnSorted::column)
+                .collect(Collectors.toList());
+    }
+
+    private static class TableDefinitionBuilderWithIndexId {
+        private final TableDefinition.Builder builder;
+
+        private final int indexId;
+
+        private TableDefinitionBuilderWithIndexId(TableDefinition.Builder 
builder, int indexId) {
+            this.builder = builder;
+            this.indexId = indexId;
+        }
+    }
+}
diff --git 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/WithOption.java
 
b/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/WithOption.java
deleted file mode 100644
index 80397c6994..0000000000
--- 
a/modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/WithOption.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.catalog.sql;
-
-class WithOption extends QueryPart {
-    private final String name;
-
-    private final Object value;
-
-    private WithOption(String name, Object value) {
-        this.name = name;
-        this.value = value;
-    }
-
-    public static WithOption primaryZone(String zone) {
-        return new WithOption("PRIMARY_ZONE", zone.toUpperCase());
-    }
-
-    public static WithOption partitions(Integer partitions) {
-        return new WithOption("PARTITIONS", partitions);
-    }
-
-    public static WithOption replicas(Integer replicas) {
-        return new WithOption("REPLICAS", replicas);
-    }
-
-    public static WithOption distributionAlgorithm(String 
distributionAlgorithm) {
-        return new WithOption("DISTRIBUTION_ALGORITHM", distributionAlgorithm);
-    }
-
-    public static WithOption dataNodesAutoAdjust(Integer adjust) {
-        return new WithOption("DATA_NODES_AUTO_ADJUST", adjust);
-    }
-
-    public static WithOption dataNodesAutoAdjustScaleUp(Integer adjust) {
-        return new WithOption("DATA_NODES_AUTO_ADJUST_SCALE_UP", adjust);
-    }
-
-    public static WithOption dataNodesAutoAdjustScaleDown(Integer adjust) {
-        return new WithOption("DATA_NODES_AUTO_ADJUST_SCALE_DOWN", adjust);
-    }
-
-    public static WithOption filter(String filter) {
-        return new WithOption("DATA_NODES_FILTER", filter);
-    }
-
-    public static WithOption dataRegion(String dataRegion) {
-        return new WithOption("DATAREGION", dataRegion);
-    }
-
-    public static WithOption storageProfiles(String storageProfiles) {
-        return new WithOption("STORAGE_PROFILES", storageProfiles);
-    }
-
-    @Override
-    protected void accept(QueryContext ctx) {
-        ctx.sql(name).sql("=");
-        boolean isNeedsQuotes = value instanceof String;
-        if (isNeedsQuotes) {
-            ctx.sql("'").sql(value.toString()).sql("'");
-        } else {
-            ctx.sql(value.toString());
-        }
-    }
-}
diff --git 
a/modules/catalog-dsl/src/test/java/org/apache/ignite/internal/catalog/sql/QueryPartTest.java
 
b/modules/catalog-dsl/src/test/java/org/apache/ignite/internal/catalog/sql/QueryPartTest.java
index 46e772ad6a..5b0f906108 100644
--- 
a/modules/catalog-dsl/src/test/java/org/apache/ignite/internal/catalog/sql/QueryPartTest.java
+++ 
b/modules/catalog-dsl/src/test/java/org/apache/ignite/internal/catalog/sql/QueryPartTest.java
@@ -138,13 +138,13 @@ class QueryPartTest {
 
     @Test
     void withOptionPart() {
-        WithOption withOption = WithOption.primaryZone("z");
+        Option withOption = Option.primaryZone("z");
         assertThat(sql(withOption), is("PRIMARY_ZONE='Z'"));
 
-        withOption = WithOption.partitions(1);
+        withOption = Option.partitions(1);
         assertThat(sql(withOption), is("PARTITIONS=1"));
 
-        withOption = WithOption.replicas(1);
+        withOption = Option.replicas(1);
         assertThat(sql(withOption), is("REPLICAS=1"));
     }
 
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogSystemViewRegistry.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogSystemViewRegistry.java
index a9b27f1ff4..fb6b8b2e6d 100644
--- 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogSystemViewRegistry.java
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogSystemViewRegistry.java
@@ -22,6 +22,7 @@ import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import org.apache.ignite.internal.catalog.systemviews.IndexSystemViewProvider;
 import org.apache.ignite.internal.catalog.systemviews.SystemViewViewProvider;
+import org.apache.ignite.internal.catalog.systemviews.TablesSystemViewProvider;
 import org.apache.ignite.internal.catalog.systemviews.ZonesSystemViewProvider;
 import org.apache.ignite.internal.systemview.api.SystemView;
 import org.apache.ignite.internal.systemview.api.SystemViewProvider;
@@ -40,7 +41,8 @@ public class CatalogSystemViewRegistry implements 
SystemViewProvider {
         providers = List.of(
                 new SystemViewViewProvider(),
                 new IndexSystemViewProvider(),
-                new ZonesSystemViewProvider()
+                new ZonesSystemViewProvider(),
+                new TablesSystemViewProvider()
         );
     }
 
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/systemviews/TablesSystemViewProvider.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/systemviews/TablesSystemViewProvider.java
new file mode 100644
index 0000000000..8913425a45
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/systemviews/TablesSystemViewProvider.java
@@ -0,0 +1,146 @@
+/*
+ * 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.catalog.systemviews;
+
+import static org.apache.ignite.internal.type.NativeTypes.BOOLEAN;
+import static org.apache.ignite.internal.type.NativeTypes.INT32;
+import static org.apache.ignite.internal.type.NativeTypes.STRING;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Flow.Publisher;
+import java.util.function.Supplier;
+import org.apache.ignite.internal.catalog.Catalog;
+import org.apache.ignite.internal.catalog.CatalogSystemViewProvider;
+import 
org.apache.ignite.internal.catalog.descriptors.CatalogTableColumnDescriptor;
+import org.apache.ignite.internal.catalog.descriptors.CatalogTableDescriptor;
+import org.apache.ignite.internal.systemview.api.SystemView;
+import org.apache.ignite.internal.systemview.api.SystemViews;
+import org.apache.ignite.internal.util.SubscriptionUtils;
+
+/**
+ * Exposes information on tables.
+ *
+ * <ul>
+ *     <li>TABLES - available tables</li>
+ *     <li>TABLE_COLUMNS - columns of available tables.</li>
+ * </ul>
+ */
+public class TablesSystemViewProvider implements CatalogSystemViewProvider {
+    @Override
+    public List<SystemView<?>> getView(Supplier<Catalog> catalogSupplier) {
+        return List.of(
+                getTablesSystemView(catalogSupplier),
+                getTableColumnsSystemView(catalogSupplier)
+        );
+    }
+
+    private static SystemView<?> getTablesSystemView(Supplier<Catalog> 
catalogSupplier) {
+        Iterable<TableWithSchemaAndZoneName> tablesData = () -> {
+            Catalog catalog = catalogSupplier.get();
+
+            return catalog.tables().stream().map(table -> {
+                String schemaName = 
Objects.requireNonNull(catalog.schema(table.schemaId()), "Schema must be not 
null.").name();
+                String zoneName = 
Objects.requireNonNull(catalog.zone(table.zoneId()), "Zone must be not 
null.").name();
+
+                return new TableWithSchemaAndZoneName(table, schemaName, 
zoneName);
+            }).iterator();
+        };
+
+        Publisher<TableWithSchemaAndZoneName> viewDataPublisher = 
SubscriptionUtils.fromIterable(tablesData);
+
+        return SystemViews.<TableWithSchemaAndZoneName>clusterViewBuilder()
+                .name("TABLES")
+                .addColumn("SCHEMA", STRING, entry -> entry.schemaName)
+                .addColumn("NAME", STRING, entry -> entry.table.name())
+                .addColumn("ID", INT32, entry -> entry.table.id())
+                .addColumn("PK_INDEX_ID", INT32, entry -> 
entry.table.primaryKeyIndexId())
+                .addColumn("ZONE", STRING, entry -> entry.zoneName)
+                .addColumn("STORAGE_PROFILE", STRING, entry -> 
entry.table.storageProfile())
+                .addColumn("COLOCATION_KEY_INDEX", STRING, entry -> 
concatColumns(entry.table.colocationColumns()))
+                .dataProvider(viewDataPublisher)
+                .build();
+    }
+
+    private static String concatColumns(List<String> columns) {
+        if (columns == null || columns.isEmpty()) {
+            return "NULL";
+        }
+        return String.join(", ", columns);
+    }
+
+    private static SystemView<?> getTableColumnsSystemView(Supplier<Catalog> 
catalogSupplier) {
+        Iterable<ColumnWithTableId> viewData = () -> {
+            Catalog catalog = catalogSupplier.get();
+
+            return catalog.tables().stream()
+                    .flatMap(table -> table.columns().stream()
+                            .map(columnDescriptor -> new ColumnWithTableId(
+                                    catalog.schema(table.schemaId()).name(),
+                                    table.name(),
+                                    table.id(),
+                                    columnDescriptor
+                                    )
+                            )
+                    )
+                    .iterator();
+        };
+
+        Publisher<ColumnWithTableId> viewDataPublisher = 
SubscriptionUtils.fromIterable(viewData);
+
+        return SystemViews.<ColumnWithTableId>clusterViewBuilder()
+                .name("TABLE_COLUMNS")
+                .addColumn("SCHEMA", STRING, entry -> entry.schema)
+                .addColumn("TABLE_NAME", STRING, entry -> entry.tableName)
+                .addColumn("TABLE_ID", INT32, entry -> entry.tableId)
+                .addColumn("COLUMN_NAME", STRING, entry -> 
entry.descriptor.name())
+                .addColumn("TYPE", STRING, entry -> 
entry.descriptor.type().name())
+                .addColumn("NULLABLE", BOOLEAN, entry -> 
entry.descriptor.nullable())
+                .addColumn("PREC", INT32, entry -> 
entry.descriptor.precision())
+                .addColumn("SCALE", INT32, entry -> entry.descriptor.scale())
+                .addColumn("LENGTH", INT32, entry -> entry.descriptor.length())
+                .dataProvider(viewDataPublisher)
+                .build();
+    }
+
+    private static class ColumnWithTableId {
+        private final CatalogTableColumnDescriptor descriptor;
+        private final String tableName;
+        private final String schema;
+        private final int tableId;
+
+        private ColumnWithTableId(String schema, String tableName, int 
tableId, CatalogTableColumnDescriptor descriptor) {
+            this.schema = schema;
+            this.tableName = tableName;
+            this.descriptor = descriptor;
+            this.tableId = tableId;
+        }
+    }
+
+    private static class TableWithSchemaAndZoneName {
+        private final CatalogTableDescriptor table;
+        private final String schemaName;
+        private final String zoneName;
+
+        private TableWithSchemaAndZoneName(CatalogTableDescriptor table, 
String schemaName, String zoneName) {
+            this.table = table;
+            this.schemaName = schemaName;
+            this.zoneName = zoneName;
+        }
+    }
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/systemviews/ZonesSystemViewProvider.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/systemviews/ZonesSystemViewProvider.java
index 13be1e872e..c5579f2f47 100644
--- 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/systemviews/ZonesSystemViewProvider.java
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/systemviews/ZonesSystemViewProvider.java
@@ -22,9 +22,11 @@ import static 
org.apache.ignite.internal.type.NativeTypes.INT32;
 import static org.apache.ignite.internal.type.NativeTypes.STRING;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.function.Supplier;
 import org.apache.ignite.internal.catalog.Catalog;
 import org.apache.ignite.internal.catalog.CatalogSystemViewProvider;
+import 
org.apache.ignite.internal.catalog.descriptors.CatalogStorageProfileDescriptor;
 import org.apache.ignite.internal.catalog.descriptors.CatalogZoneDescriptor;
 import org.apache.ignite.internal.systemview.api.SystemView;
 import org.apache.ignite.internal.systemview.api.SystemViews;
@@ -43,7 +45,11 @@ public final class ZonesSystemViewProvider implements 
CatalogSystemViewProvider
     /** {@inheritDoc} */
     @Override
     public List<SystemView<?>> getView(Supplier<Catalog> catalogSupplier) {
-        SystemView<?> zoneSystemView = 
SystemViews.<ZoneWithDefaultMarker>clusterViewBuilder()
+        return List.of(getZoneView(catalogSupplier), 
getStorageProfilesView(catalogSupplier));
+    }
+
+    private static SystemView<?> getZoneView(Supplier<Catalog> 
catalogSupplier) {
+        return SystemViews.<ZoneWithDefaultMarker>clusterViewBuilder()
                 .name("ZONES")
                 .addColumn("NAME", STRING, wrapper -> wrapper.zone.name())
                 .addColumn("PARTITIONS", INT32, wrapper -> 
wrapper.zone.partitions())
@@ -60,8 +66,34 @@ public final class ZonesSystemViewProvider implements 
CatalogSystemViewProvider
                         }
                 ))
                 .build();
+    }
+
+    private static SystemView<?> getStorageProfilesView(Supplier<Catalog> 
catalogSupplier) {
+        Iterable<ZoneWithProfile> viewData = () -> {
+            Catalog catalog = catalogSupplier.get();
+
+            return catalog.zones().stream()
+                    .flatMap(zone -> {
+                        List<CatalogStorageProfileDescriptor> profiles = 
zone.storageProfiles().profiles();
+                        CatalogStorageProfileDescriptor defaultProfile = 
zone.storageProfiles().defaultProfile();
+
+                        return profiles.stream().map(profile ->
+                                new ZoneWithProfile(
+                                        zone.name(),
+                                        profile.storageProfile(),
+                                        
Objects.equals(profile.storageProfile(), defaultProfile.storageProfile())
+                                )
+                        );
+                    }).iterator();
+        };
 
-        return List.of(zoneSystemView);
+        return SystemViews.<ZoneWithProfile>clusterViewBuilder()
+                .name("ZONE_STORAGE_PROFILES")
+                .addColumn("ZONE_NAME", STRING, zone -> zone.zoneName)
+                .addColumn("STORAGE_PROFILE", STRING, zone -> zone.profileName)
+                .addColumn("IS_DEFAULT_PROFILE", BOOLEAN, zone -> 
zone.isDefaultProfile)
+                .dataProvider(SubscriptionUtils.fromIterable(viewData))
+                .build();
     }
 
     /** Wraps a CatalogZoneDescriptor and a flag indicating whether this zone 
is the default zone. */
@@ -74,4 +106,19 @@ public final class ZonesSystemViewProvider implements 
CatalogSystemViewProvider
             this.isDefault = isDefault;
         }
     }
+
+    /**
+     * Wraps a zone and a one of storage profile of the zone.
+     */
+    private static class ZoneWithProfile {
+        private final String zoneName;
+        private final String profileName;
+        private final boolean isDefaultProfile;
+
+        private ZoneWithProfile(String zoneName, String profileName, boolean 
defaultProfile) {
+            this.zoneName = zoneName;
+            this.profileName = profileName;
+            this.isDefaultProfile = defaultProfile;
+        }
+    }
 }
diff --git 
a/modules/client/src/main/java/org/apache/ignite/internal/client/TcpIgniteClient.java
 
b/modules/client/src/main/java/org/apache/ignite/internal/client/TcpIgniteClient.java
index 58d991a54b..08568c6d4f 100644
--- 
a/modules/client/src/main/java/org/apache/ignite/internal/client/TcpIgniteClient.java
+++ 
b/modules/client/src/main/java/org/apache/ignite/internal/client/TcpIgniteClient.java
@@ -209,7 +209,7 @@ public class TcpIgniteClient implements IgniteClient {
 
     @Override
     public IgniteCatalog catalog() {
-        return new IgniteCatalogSqlImpl(sql(), tables);
+        return new IgniteCatalogSqlImpl(sql, tables);
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/runner/src/main/java/org/apache/ignite/internal/threading/PublicApiThreadingIgniteCatalog.java
 
b/modules/runner/src/main/java/org/apache/ignite/internal/threading/PublicApiThreadingIgniteCatalog.java
index 0316465336..db1c0e8de6 100644
--- 
a/modules/runner/src/main/java/org/apache/ignite/internal/threading/PublicApiThreadingIgniteCatalog.java
+++ 
b/modules/runner/src/main/java/org/apache/ignite/internal/threading/PublicApiThreadingIgniteCatalog.java
@@ -78,6 +78,16 @@ public class PublicApiThreadingIgniteCatalog implements 
IgniteCatalog, Wrapper {
         return wrapTableForPublicUse(table);
     }
 
+    @Override
+    public CompletableFuture<TableDefinition> tableDefinitionAsync(String 
tableName) {
+        return doAsyncOperation(() -> catalog.tableDefinitionAsync(tableName));
+    }
+
+    @Override
+    public TableDefinition tableDefinition(String tableName) {
+        return execUserSyncOperation(() -> catalog.tableDefinition(tableName));
+    }
+
     @Override
     public CompletableFuture<Void> createZoneAsync(ZoneDefinition definition) {
         return doAsyncOperation(() -> catalog.createZoneAsync(definition));
@@ -88,6 +98,17 @@ public class PublicApiThreadingIgniteCatalog implements 
IgniteCatalog, Wrapper {
         execUserSyncOperation(() -> catalog.createZone(definition));
     }
 
+
+    @Override
+    public CompletableFuture<ZoneDefinition> zoneDefinitionAsync(String 
zoneName) {
+        return execUserSyncOperation(() -> 
catalog.zoneDefinitionAsync(zoneName));
+    }
+
+    @Override
+    public ZoneDefinition zoneDefinition(String zoneName) {
+        return execUserSyncOperation(() -> catalog.zoneDefinition(zoneName));
+    }
+
     @Override
     public CompletableFuture<Void> dropTableAsync(TableDefinition definition) {
         return doAsyncOperation(() -> catalog.dropTableAsync(definition));


Reply via email to