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

ppa 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 a9d4ae29e6 IGNITE-21166 Sql. Provide internal API to get a columns 
metadata for non-executed query (#3037)
a9d4ae29e6 is described below

commit a9d4ae29e64c1282a5af7afc04c1f3d3325d4989
Author: Pavel Pereslegin <xxt...@gmail.com>
AuthorDate: Tue Jan 16 13:30:35 2024 +0300

    IGNITE-21166 Sql. Provide internal API to get a columns metadata for 
non-executed query (#3037)
---
 .../sql/ClientSqlParameterMetadataRequest.java     |  4 +-
 .../client/fakes/FakeIgniteQueryProcessor.java     |  4 +-
 .../sql/engine/ItDynamicParameterTest.java         | 23 +++++----
 .../ignite/internal/sql/engine/QueryProcessor.java |  9 ++--
 .../internal/sql/engine/SqlQueryProcessor.java     | 12 ++---
 .../internal/sql/engine/prepare/QueryMetadata.java | 53 ++++++++++++++++++++
 .../internal/sql/engine/util/QueryCheckerTest.java | 56 ++++++++++++++++++----
 .../internal/sql/engine/util/QueryCheckerImpl.java | 42 +++++++++++-----
 8 files changed, 156 insertions(+), 47 deletions(-)

diff --git 
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlParameterMetadataRequest.java
 
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlParameterMetadataRequest.java
index d4eef1a73f..4eb61cfeca 100644
--- 
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlParameterMetadataRequest.java
+++ 
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlParameterMetadataRequest.java
@@ -25,7 +25,7 @@ import 
org.apache.ignite.internal.client.proto.ClientMessagePacker;
 import org.apache.ignite.internal.client.proto.ClientMessageUnpacker;
 import org.apache.ignite.internal.sql.engine.QueryProcessor;
 import org.apache.ignite.internal.sql.engine.QueryProperty;
-import org.apache.ignite.internal.sql.engine.prepare.ParameterMetadata;
+import org.apache.ignite.internal.sql.engine.prepare.QueryMetadata;
 import org.apache.ignite.internal.sql.engine.property.SqlProperties;
 import org.apache.ignite.internal.sql.engine.property.SqlPropertiesHelper;
 
@@ -57,7 +57,7 @@ public class ClientSqlParameterMetadataRequest {
         return processor.prepareSingleAsync(properties, tx, 
query).thenAccept(meta -> writeMeta(out, meta));
     }
 
-    private static void writeMeta(ClientMessagePacker out, ParameterMetadata 
meta) {
+    private static void writeMeta(ClientMessagePacker out, QueryMetadata meta) 
{
         var types = meta.parameterTypes();
 
         out.packInt(types.size());
diff --git 
a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeIgniteQueryProcessor.java
 
b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeIgniteQueryProcessor.java
index 528ddabd3e..fbdfc5ffb2 100644
--- 
a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeIgniteQueryProcessor.java
+++ 
b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeIgniteQueryProcessor.java
@@ -23,7 +23,7 @@ import java.util.concurrent.CompletableFuture;
 import org.apache.ignite.internal.sql.engine.AsyncSqlCursor;
 import org.apache.ignite.internal.sql.engine.InternalSqlRow;
 import org.apache.ignite.internal.sql.engine.QueryProcessor;
-import org.apache.ignite.internal.sql.engine.prepare.ParameterMetadata;
+import org.apache.ignite.internal.sql.engine.prepare.QueryMetadata;
 import org.apache.ignite.internal.sql.engine.property.SqlProperties;
 import org.apache.ignite.internal.tx.InternalTransaction;
 import org.apache.ignite.tx.IgniteTransactions;
@@ -34,7 +34,7 @@ import org.jetbrains.annotations.Nullable;
  */
 public class FakeIgniteQueryProcessor implements QueryProcessor {
     @Override
-    public CompletableFuture<ParameterMetadata> 
prepareSingleAsync(SqlProperties properties,
+    public CompletableFuture<QueryMetadata> prepareSingleAsync(SqlProperties 
properties,
             @Nullable InternalTransaction transaction, String qry, Object... 
params) {
         throw new UnsupportedOperationException();
     }
diff --git 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDynamicParameterTest.java
 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDynamicParameterTest.java
index 22ebd676f5..ffc6803f57 100644
--- 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDynamicParameterTest.java
+++ 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDynamicParameterTest.java
@@ -33,7 +33,6 @@ import java.util.stream.Stream;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.ignite.internal.sql.BaseSqlIntegrationTest;
-import org.apache.ignite.internal.sql.engine.prepare.ParameterMetadata;
 import org.apache.ignite.internal.sql.engine.prepare.ParameterType;
 import org.apache.ignite.internal.sql.engine.property.SqlProperties;
 import org.apache.ignite.internal.sql.engine.property.SqlPropertiesHelper;
@@ -294,9 +293,9 @@ public class ItDynamicParameterTest extends 
BaseSqlIntegrationTest {
     @ParameterizedTest
     @MethodSource("statementsWithParameters")
     public void testGetParameterTypesSimple(String stmt, List<ColumnType> 
expectedTypes, Object[] params) {
-        ParameterMetadata parameterTypes = getParameterMetadata(stmt, params);
+        List<ParameterType> parameterTypes = getParameterTypes(stmt, params);
 
-        List<ColumnType> columnTypes = parameterTypes.parameterTypes()
+        List<ColumnType> columnTypes = parameterTypes
                 .stream()
                 .map(ParameterType::columnType)
                 .collect(Collectors.toList());
@@ -321,7 +320,7 @@ public class ItDynamicParameterTest extends 
BaseSqlIntegrationTest {
         assertThrowsSqlException(
                 Sql.STMT_VALIDATION_ERR,
                 "Unexpected number of query parameters",
-                () -> getParameterMetadata("SELECT ? + ?", 1, 2, 3));
+                () -> getParameterTypes("SELECT ? + ?", 1, 2, 3));
     }
 
     @Test
@@ -341,9 +340,9 @@ public class ItDynamicParameterTest extends 
BaseSqlIntegrationTest {
 
         log.info("SELECT from column names: {}", stmt);
 
-        ParameterMetadata parameterTypes = 
getParameterMetadata(stmt.toString());
+        List<ParameterType> parameterTypes = 
getParameterTypes(stmt.toString());
 
-        List<NativeType> actualTypes = parameterTypes.parameterTypes().stream()
+        List<NativeType> actualTypes = parameterTypes.stream()
                 .map(p -> TypeUtils.columnType2NativeType(p.columnType(), 
p.precision(), p.scale(), p.precision()))
                 .collect(Collectors.toList());
 
@@ -362,9 +361,9 @@ public class ItDynamicParameterTest extends 
BaseSqlIntegrationTest {
 
         log.info("INSERT from column names: {}", stmt);
 
-        ParameterMetadata parameterTypes = 
getParameterMetadata(stmt.toString());
+        List<ParameterType> parameterTypes = 
getParameterTypes(stmt.toString());
 
-        List<NativeType> actualTypes = parameterTypes.parameterTypes().stream()
+        List<NativeType> actualTypes = parameterTypes.stream()
                 .map(p -> TypeUtils.columnType2NativeType(p.columnType(), 
p.precision(), p.scale(), p.precision()))
                 .collect(Collectors.toList());
 
@@ -389,9 +388,9 @@ public class ItDynamicParameterTest extends 
BaseSqlIntegrationTest {
 
         log.info("UPDATE from column names: {}", stmt);
 
-        ParameterMetadata parameterTypes = 
getParameterMetadata(stmt.toString());
+        List<ParameterType> parameterTypes = 
getParameterTypes(stmt.toString());
 
-        List<NativeType> actualTypes = parameterTypes.parameterTypes().stream()
+        List<NativeType> actualTypes = parameterTypes.stream()
                 .map(p -> TypeUtils.columnType2NativeType(p.columnType(), 
p.precision(), p.scale(), p.precision()))
                 .collect(Collectors.toList());
 
@@ -452,9 +451,9 @@ public class ItDynamicParameterTest extends 
BaseSqlIntegrationTest {
                 () -> assertQuery(query).withParams(params).check());
     }
 
-    private ParameterMetadata getParameterMetadata(String query, Object... 
params) {
+    private List<ParameterType> getParameterTypes(String query, Object... 
params) {
         QueryProcessor qryProc = queryProcessor();
         SqlProperties properties = SqlPropertiesHelper.emptyProperties();
-        return await(qryProc.prepareSingleAsync(properties, null, query, 
params));
+        return await(qryProc.prepareSingleAsync(properties, null, query, 
params)).parameterTypes();
     }
 }
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryProcessor.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryProcessor.java
index 258651d37e..190b3a6a58 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryProcessor.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryProcessor.java
@@ -19,7 +19,7 @@ package org.apache.ignite.internal.sql.engine;
 
 import java.util.concurrent.CompletableFuture;
 import org.apache.ignite.internal.manager.IgniteComponent;
-import org.apache.ignite.internal.sql.engine.prepare.ParameterMetadata;
+import org.apache.ignite.internal.sql.engine.prepare.QueryMetadata;
 import org.apache.ignite.internal.sql.engine.property.SqlProperties;
 import org.apache.ignite.internal.tx.InternalTransaction;
 import org.apache.ignite.lang.IgniteException;
@@ -32,18 +32,19 @@ import org.jetbrains.annotations.Nullable;
 public interface QueryProcessor extends IgniteComponent {
 
     /**
-     * Returns parameter metadata for the given statement. This method uses 
optional array of parameters to assist with type inference.
+     * Returns columns and parameters metadata for the given statement.
+     * This method uses optional array of parameters to assist with type 
inference.
      *
      * @param properties User query properties. See {@link QueryProperty} for 
available properties.
      * @param transaction A transaction to use to resolve a schema.
      * @param qry Single statement SQL query.
      * @param params Query parameters.
-     * @return Parameter metadata.
+     * @return Query metadata.
      *
      * @throws IgniteException in case of an error.
      * @see QueryProperty
      */
-    CompletableFuture<ParameterMetadata> prepareSingleAsync(SqlProperties 
properties,
+    CompletableFuture<QueryMetadata> prepareSingleAsync(SqlProperties 
properties,
             @Nullable InternalTransaction transaction,
             String qry, Object... params);
 
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java
index c660152014..cfc62f603c 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java
@@ -91,9 +91,9 @@ import 
org.apache.ignite.internal.sql.engine.exec.mapping.ExecutionTargetFactory
 import 
org.apache.ignite.internal.sql.engine.exec.mapping.ExecutionTargetProvider;
 import org.apache.ignite.internal.sql.engine.exec.mapping.MappingServiceImpl;
 import org.apache.ignite.internal.sql.engine.message.MessageServiceImpl;
-import org.apache.ignite.internal.sql.engine.prepare.ParameterMetadata;
 import org.apache.ignite.internal.sql.engine.prepare.PrepareService;
 import org.apache.ignite.internal.sql.engine.prepare.PrepareServiceImpl;
+import org.apache.ignite.internal.sql.engine.prepare.QueryMetadata;
 import org.apache.ignite.internal.sql.engine.prepare.QueryPlan;
 import org.apache.ignite.internal.sql.engine.property.SqlProperties;
 import org.apache.ignite.internal.sql.engine.property.SqlPropertiesHelper;
@@ -428,7 +428,7 @@ public class SqlQueryProcessor implements QueryProcessor {
 
     /** {@inheritDoc} */
     @Override
-    public CompletableFuture<ParameterMetadata> 
prepareSingleAsync(SqlProperties properties,
+    public CompletableFuture<QueryMetadata> prepareSingleAsync(SqlProperties 
properties,
             @Nullable InternalTransaction transaction,
             String qry, Object... params) {
 
@@ -489,7 +489,7 @@ public class SqlQueryProcessor implements QueryProcessor {
         return service;
     }
 
-    private CompletableFuture<ParameterMetadata> prepareSingleAsync0(
+    private CompletableFuture<QueryMetadata> prepareSingleAsync0(
             SqlProperties properties,
             @Nullable InternalTransaction explicitTransaction,
             String sql,
@@ -500,9 +500,9 @@ public class SqlQueryProcessor implements QueryProcessor {
 
         QueryCancel queryCancel = new QueryCancel();
 
-        CompletableFuture<ParameterMetadata> start = new CompletableFuture<>();
+        CompletableFuture<QueryMetadata> start = new CompletableFuture<>();
 
-        CompletableFuture<ParameterMetadata> stage = start.thenCompose(ignored 
-> {
+        CompletableFuture<QueryMetadata> stage = start.thenCompose(ignored -> {
             ParsedResult result = parserService.parse(sql);
 
             validateParsedStatement(properties0, result);
@@ -511,7 +511,7 @@ public class SqlQueryProcessor implements QueryProcessor {
             HybridTimestamp timestamp = explicitTransaction != null ? 
explicitTransaction.startTimestamp() : clock.now();
 
             return prepareParsedStatement(schemaName, result, timestamp, 
queryCancel, params)
-                    .thenApply(QueryPlan::parameterMetadata);
+                    .thenApply(plan -> new QueryMetadata(plan.metadata(), 
plan.parameterMetadata()));
         });
 
         // TODO IGNITE-20078 Improve (or remove) CancellationException 
handling.
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/QueryMetadata.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/QueryMetadata.java
new file mode 100644
index 0000000000..dedf6fb423
--- /dev/null
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/QueryMetadata.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.sql.engine.prepare;
+
+import java.util.List;
+import org.apache.ignite.internal.tostring.IgniteToStringInclude;
+import org.apache.ignite.internal.tostring.S;
+import org.apache.ignite.sql.ColumnMetadata;
+import org.apache.ignite.sql.ResultSetMetadata;
+
+/**
+ * Query metadata combines {@link ParameterMetadata dynamic parameters 
metadata} and {@link ColumnMetadata columns metadata}.
+ */
+public class QueryMetadata {
+    @IgniteToStringInclude
+    private final List<ColumnMetadata> columns;
+
+    @IgniteToStringInclude
+    private final List<ParameterType> parameterTypes;
+
+    public QueryMetadata(ResultSetMetadata resultSetMetadata, 
ParameterMetadata parameterMetadata) {
+        this.columns = resultSetMetadata.columns();
+        this.parameterTypes = parameterMetadata.parameterTypes();
+    }
+
+    public List<ColumnMetadata> columns() {
+        return columns;
+    }
+
+    public List<ParameterType> parameterTypes() {
+        return parameterTypes;
+    }
+
+    @Override
+    public String toString() {
+        return S.toString(QueryMetadata.class, this);
+    }
+}
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerTest.java
index caed3ae0bd..a513697824 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.sql.engine.util;
 
+import static 
org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrows;
 import static 
org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
 import static 
org.apache.ignite.internal.util.CompletableFutures.nullCompletedFuture;
 import static org.hamcrest.Matchers.containsString;
@@ -33,7 +34,7 @@ import 
org.apache.ignite.internal.sql.engine.framework.NoOpTransaction;
 import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
 import org.apache.ignite.internal.sql.engine.framework.TestCluster;
 import org.apache.ignite.internal.sql.engine.framework.TestNode;
-import org.apache.ignite.internal.sql.engine.prepare.ParameterMetadata;
+import org.apache.ignite.internal.sql.engine.prepare.QueryMetadata;
 import org.apache.ignite.internal.sql.engine.prepare.QueryPlan;
 import org.apache.ignite.internal.sql.engine.property.SqlProperties;
 import org.apache.ignite.internal.sql.engine.tx.QueryTransactionWrapperImpl;
@@ -216,15 +217,15 @@ public class QueryCheckerTest extends 
BaseIgniteAbstractTest {
 
     @Test
     void testMetadata() {
-        assertQuery("SELECT * FROM t1")
+        assertQueryMeta("SELECT * FROM t1")
                 .columnNames("ID", "VAL")
                 .check();
 
-        assertQuery("SELECT * FROM t1")
+        assertQueryMeta("SELECT * FROM t1")
                 .columnTypes(Integer.class, Integer.class)
                 .check();
 
-        assertQuery("SELECT id, val::DECIMAL(19, 2) as val_dec, 
id::VARCHAR(64) as id_str FROM t1")
+        assertQueryMeta("SELECT id, val::DECIMAL(19, 2) as val_dec, 
id::VARCHAR(64) as id_str FROM t1")
                 .columnMetadata(
                         new MetadataMatcher()
                                 .name("ID")
@@ -248,13 +249,44 @@ public class QueryCheckerTest extends 
BaseIgniteAbstractTest {
                                 .nullable(false)
                 )
                 .check();
+
+        // Test that validates the results cannot be executed correctly 
without actually executing the query.
+        assertThrows(
+                AssertionError.class,
+                () -> assertQueryMeta("SELECT * FROM t1")
+                        .columnTypes(Integer.class, Integer.class)
+                        .returns(1, 1)
+                        .returns(2, 2)
+                        .check(),
+                "Expected that the query will only be prepared, but not 
executed"
+        );
+
+        // Test that only checks metadata should not execute the query.
+        assertThrows(
+                AssertionError.class,
+                () -> assertQuery("SELECT * FROM t1")
+                        .columnTypes(Integer.class, Integer.class)
+                        .check(),
+                "Expected that the query will be executed"
+        );
     }
 
     private static QueryChecker assertQuery(String qry) {
         TestNode testNode = CLUSTER.node(NODE_NAME);
 
         return queryCheckerFactory.create(
-                new TestQueryProcessor(testNode),
+                new TestQueryProcessor(testNode, false),
+                new TestIgniteTransactions(),
+                null,
+                qry
+        );
+    }
+
+    private static QueryChecker assertQueryMeta(String qry) {
+        TestNode testNode = CLUSTER.node(NODE_NAME);
+
+        return queryCheckerFactory.create(
+                new TestQueryProcessor(testNode, true),
                 new TestIgniteTransactions(),
                 null,
                 qry
@@ -263,15 +295,22 @@ public class QueryCheckerTest extends 
BaseIgniteAbstractTest {
 
     private static class TestQueryProcessor implements QueryProcessor {
         private final TestNode node;
+        private final boolean prepareOnly;
 
-        TestQueryProcessor(TestNode node) {
+        TestQueryProcessor(TestNode node, boolean prepareOnly) {
             this.node = node;
+            this.prepareOnly = prepareOnly;
         }
 
         @Override
-        public CompletableFuture<ParameterMetadata> 
prepareSingleAsync(SqlProperties properties,
+        public CompletableFuture<QueryMetadata> 
prepareSingleAsync(SqlProperties properties,
                 @Nullable InternalTransaction transaction, String qry, 
Object... params) {
-            throw new UnsupportedOperationException();
+            assert params == null || params.length == 0 : "params are not 
supported";
+            assert prepareOnly : "Expected that the query will be executed";
+
+            QueryPlan plan = node.prepare(qry);
+
+            return CompletableFuture.completedFuture(new 
QueryMetadata(plan.metadata(), plan.parameterMetadata()));
         }
 
         @Override
@@ -283,6 +322,7 @@ public class QueryCheckerTest extends 
BaseIgniteAbstractTest {
                 Object... params
         ) {
             assert params == null || params.length == 0 : "params are not 
supported";
+            assert !prepareOnly : "Expected that the query will only be 
prepared, but not executed";
 
             QueryPlan plan = node.prepare(qry);
             AsyncCursor<InternalSqlRow> dataCursor = node.executePlan(plan);
diff --git 
a/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerImpl.java
 
b/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerImpl.java
index 1a154cca07..5afdfae3ce 100644
--- 
a/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerImpl.java
+++ 
b/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerImpl.java
@@ -27,6 +27,7 @@ import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.not;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.fail;
 
 import java.lang.reflect.Type;
@@ -48,6 +49,7 @@ import org.apache.ignite.internal.sql.engine.QueryProcessor;
 import org.apache.ignite.internal.sql.engine.QueryProperty;
 import org.apache.ignite.internal.sql.engine.SqlQueryType;
 import org.apache.ignite.internal.sql.engine.hint.IgniteHint;
+import org.apache.ignite.internal.sql.engine.prepare.QueryMetadata;
 import org.apache.ignite.internal.sql.engine.property.SqlProperties;
 import org.apache.ignite.internal.sql.engine.property.SqlPropertiesHelper;
 import org.apache.ignite.internal.tx.InternalTransaction;
@@ -300,6 +302,18 @@ abstract class QueryCheckerImpl implements QueryChecker {
                 }
             }
         }
+
+        // Check column metadata only.
+        if (resultChecker == null && metadataMatchers != null) {
+            QueryMetadata queryMetadata = 
await(qryProc.prepareSingleAsync(PROPERTIES, tx, qry, params));
+
+            assertNotNull(queryMetadata);
+
+            checkColumnsMetadata(queryMetadata.columns());
+
+            return;
+        }
+
         // Check result.
         CompletableFuture<AsyncSqlCursor<InternalSqlRow>> cursors =
                 qryProc.querySingleAsync(PROPERTIES, transactions(), tx, qry, 
params);
@@ -309,19 +323,7 @@ abstract class QueryCheckerImpl implements QueryChecker {
         checkMetadata(cur.metadata());
 
         if (metadataMatchers != null) {
-            List<ColumnMetadata> columnMetadata = cur.metadata().columns();
-
-            Iterator<ColumnMetadata> valueIterator = columnMetadata.iterator();
-            Iterator<ColumnMatcher> matcherIterator = 
metadataMatchers.iterator();
-
-            while (matcherIterator.hasNext() && valueIterator.hasNext()) {
-                ColumnMatcher matcher = matcherIterator.next();
-                ColumnMetadata actualElement = valueIterator.next();
-
-                matcher.check(actualElement);
-            }
-
-            assertEquals(metadataMatchers.size(), columnMetadata.size(), 
"Column metadata doesn't match");
+            checkColumnsMetadata(cur.metadata().columns());
         }
 
         List<InternalSqlRow> rows = Commons.cast(getAllFromCursor(cur));
@@ -332,6 +334,20 @@ abstract class QueryCheckerImpl implements QueryChecker {
         }
     }
 
+    private void checkColumnsMetadata(List<ColumnMetadata> columnsMetadata) {
+        Iterator<ColumnMetadata> valueIterator = columnsMetadata.iterator();
+        Iterator<ColumnMatcher> matcherIterator = metadataMatchers.iterator();
+
+        while (matcherIterator.hasNext() && valueIterator.hasNext()) {
+            ColumnMatcher matcher = matcherIterator.next();
+            ColumnMetadata actualElement = valueIterator.next();
+
+            matcher.check(actualElement);
+        }
+
+        assertEquals(metadataMatchers.size(), columnsMetadata.size(), "Column 
metadata doesn't match");
+    }
+
     @Override
     public String toString() {
         return QueryCheckerImpl.class.getSimpleName() + "[sql=" + 
queryTemplate.originalQueryString() + "]";

Reply via email to