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

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


The following commit(s) were added to refs/heads/main by this push:
     new 2471da3  IGNITE-15187 JDBC driver for 3.0: ResultSet metadata (#345)
2471da3 is described below

commit 2471da39a750537b6b3a1f1ba4273a52bac07245
Author: Vladimir Ermakov <85303706+vladermako...@users.noreply.github.com>
AuthorDate: Mon Sep 20 16:31:53 2021 +0300

    IGNITE-15187 JDBC driver for 3.0: ResultSet metadata (#345)
---
 .../processors/query/calcite/SqlCursor.java        |   6 +
 .../internal/processors/query/calcite/Stubs.java   |   8 +
 .../query/calcite/exec/ExecutionServiceImpl.java   |   4 +-
 .../processors/query/calcite/util/Commons.java     |  15 +-
 .../client/proto/query/JdbcQueryEventHandler.java  |   9 ++
 .../client/proto/query/event/JdbcColumnMeta.java   |  45 +++++-
 .../proto/query/event/JdbcMetaColumnsResult.java   |  10 ++
 ...nsResult.java => JdbcQueryMetadataRequest.java} |  72 +++------
 .../internal/client/proto/ClientDataType.java      |   3 +
 .../internal/client/proto/ClientMessagePacker.java |   8 +
 .../client/proto/ClientMessageUnpacker.java        |   4 +
 .../ignite/internal/client/proto/ClientOp.java     |   3 +
 .../handler/ClientInboundMessageHandler.java       |   4 +
 .../client/handler/JdbcQueryEventHandlerImpl.java  |  64 ++++++++
 .../sql/ClientSqlQueryMetadataRequest.java         |  54 +++++++
 .../client/query/JdbcClientQueryEventHandler.java  |  10 ++
 .../apache/ignite/internal/jdbc/JdbcResultSet.java |  23 ++-
 .../internal/jdbc/JdbcResultSetMetadata.java       | 163 +++++++++++++++++++++
 .../org/apache/ignite/client/fakes/FakeCursor.java |   5 +
 .../runner/app/jdbc/AbstractJdbcSelfTest.java      |   7 +-
 ...st.java => ITJdbcConnectionPropertiesTest.java} |   2 +-
 ...SelfTest.java => ITJdbcConnectionSelfTest.java} |   2 +-
 ...taSelfTest.java => ITJdbcMetadataSelfTest.java} |  63 +-------
 ...tSelfTest.java => ITJdbcResultSetSelfTest.java} |  49 +++----
 ...tSelfTest.java => ITJdbcStatementSelfTest.java} |   8 +-
 25 files changed, 471 insertions(+), 170 deletions(-)

diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/SqlCursor.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/SqlCursor.java
index b5bb641..31007b9 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/SqlCursor.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/SqlCursor.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.processors.query.calcite;
 
+import 
org.apache.ignite.internal.processors.query.calcite.prepare.FieldsMetadata;
 import org.apache.ignite.internal.util.Cursor;
 
 /**
@@ -29,4 +30,9 @@ public interface SqlCursor<T> extends Cursor<T> {
      * @return Query type.
      */
     SqlQueryType getQueryType();
+
+    /**
+     * @return Column metadata.
+     */
+    FieldsMetadata getColumnMetadata();
 }
diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/Stubs.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/Stubs.java
index 6ebc28c..43d371f 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/Stubs.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/Stubs.java
@@ -17,6 +17,8 @@
 package org.apache.ignite.internal.processors.query.calcite;
 
 import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -83,6 +85,12 @@ public class Stubs {
         if (type == String.class)
             return UUID.randomUUID().toString();
 
+        if (type == BigDecimal.class)
+            return 
BigDecimal.valueOf(ThreadLocalRandom.current().nextDouble());
+
+        if (type == BigInteger.class)
+            return 
BigDecimal.valueOf(ThreadLocalRandom.current().nextDouble()).unscaledValue();
+
         throw new IllegalStateException("Can't generate value of type " + 
type.getTypeName());
     }
 }
diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java
index 032b3cd..c99eff6 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java
@@ -522,12 +522,12 @@ public class ExecutionServiceImpl<Row> implements 
ExecutionService {
                 res.add(ectx.rowHandler().get(i, row));
 
             return res;
-        }), plan.type());
+        }), plan);
     }
 
     /** */
     private SqlCursor<List<?>> executeExplain(ExplainPlan plan) {
-        SqlCursor<List<?>> cur = 
Commons.createCursor(singletonList(singletonList(plan.plan())), plan.type());
+        SqlCursor<List<?>> cur = 
Commons.createCursor(singletonList(singletonList(plan.plan())), plan);
         // TODO: fix this
 //        
cur.fieldsMeta(plan.fieldsMeta().queryFieldsMetadata(pctx.typeFactory()));
 
diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/Commons.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/Commons.java
index b60a7a2..a1d363c 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/Commons.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/Commons.java
@@ -65,6 +65,10 @@ import 
org.apache.ignite.internal.processors.query.calcite.SqlCursor;
 import org.apache.ignite.internal.processors.query.calcite.SqlQueryType;
 import 
org.apache.ignite.internal.processors.query.calcite.exec.exp.ExpressionFactoryImpl;
 import 
org.apache.ignite.internal.processors.query.calcite.metadata.cost.IgniteCostFactory;
+import 
org.apache.ignite.internal.processors.query.calcite.prepare.AbstractMultiStepPlan;
+import org.apache.ignite.internal.processors.query.calcite.prepare.ExplainPlan;
+import 
org.apache.ignite.internal.processors.query.calcite.prepare.FieldsMetadata;
+import 
org.apache.ignite.internal.processors.query.calcite.prepare.MultiStepPlan;
 import 
org.apache.ignite.internal.processors.query.calcite.prepare.PlanningContext;
 import org.apache.ignite.internal.processors.query.calcite.prepare.QueryPlan;
 import 
org.apache.ignite.internal.processors.query.calcite.sql.fun.IgniteSqlOperatorTable;
@@ -134,14 +138,19 @@ public final class Commons {
     /** */
     private Commons(){}
 
-    public static <T> SqlCursor<T> createCursor(Iterable<T> iterable, 
QueryPlan.Type plan) {
+    public static <T> SqlCursor<T> createCursor(Iterable<T> iterable, 
QueryPlan plan) {
         return createCursor(iterable.iterator(), plan);
     }
 
-    public static <T> SqlCursor<T> createCursor(Iterator<T> iter, 
QueryPlan.Type type) {
+    public static <T> SqlCursor<T> createCursor(Iterator<T> iter, QueryPlan 
plan) {
         return new SqlCursor<>() {
             @Override public SqlQueryType getQueryType() {
-                return SqlQueryType.mapPlanTypeToSqlType(type);
+                return SqlQueryType.mapPlanTypeToSqlType(plan.type());
+            }
+
+            @Override public FieldsMetadata getColumnMetadata() {
+                return plan instanceof AbstractMultiStepPlan ? 
((MultiStepPlan)plan).fieldsMetadata()
+                    : ((ExplainPlan)plan).fieldsMeta();
             }
 
             @Override public void remove() {
diff --git 
a/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/JdbcQueryEventHandler.java
 
b/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/JdbcQueryEventHandler.java
index f2f1750..c8f5540 100644
--- 
a/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/JdbcQueryEventHandler.java
+++ 
b/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/JdbcQueryEventHandler.java
@@ -27,6 +27,7 @@ import 
org.apache.ignite.client.proto.query.event.JdbcMetaSchemasRequest;
 import org.apache.ignite.client.proto.query.event.JdbcMetaSchemasResult;
 import org.apache.ignite.client.proto.query.event.JdbcMetaTablesRequest;
 import org.apache.ignite.client.proto.query.event.JdbcMetaTablesResult;
+import org.apache.ignite.client.proto.query.event.JdbcQueryMetadataRequest;
 import org.apache.ignite.client.proto.query.event.QueryCloseRequest;
 import org.apache.ignite.client.proto.query.event.QueryCloseResult;
 import org.apache.ignite.client.proto.query.event.QueryExecuteRequest;
@@ -101,4 +102,12 @@ public interface JdbcQueryEventHandler {
      * @return Result.
      */
     JdbcMetaPrimaryKeysResult primaryKeysMeta(JdbcMetaPrimaryKeysRequest req);
+
+    /**
+     * {@link JdbcQueryMetadataRequest} command handler.
+     *
+     * @param req Jdbc query metadata request.
+     * @return Result.
+     */
+    JdbcMetaColumnsResult queryMetadata(JdbcQueryMetadataRequest req);
 }
diff --git 
a/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcColumnMeta.java
 
b/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcColumnMeta.java
index 54ef323..8e62626 100644
--- 
a/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcColumnMeta.java
+++ 
b/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcColumnMeta.java
@@ -70,6 +70,9 @@ public class JdbcColumnMeta extends Response {
     /** Scale. */
     private int scale;
 
+    /** Data type class. */
+    private String dataTypeCls;
+
     /**
      * Default constructor is used for serialization.
      */
@@ -101,13 +104,30 @@ public class JdbcColumnMeta extends Response {
      */
     public JdbcColumnMeta(String schemaName, String tblName, String colName, 
Class<?> cls, int precision, int scale,
         boolean nullable) {
+        this(schemaName, tblName, colName, cls.getName(), precision, scale, 
nullable);
+    }
+
+    /**
+     * Constructor with nullable flag.
+     *
+     * @param schemaName Schema.
+     * @param tblName Table.
+     * @param colName Column.
+     * @param javaTypeName Java type name.
+     * @param nullable Nullable flag.
+     * @param precision Column precision.
+     * @param scale Column scale.
+     */
+    public JdbcColumnMeta(String schemaName, String tblName, String colName, 
String javaTypeName, int precision, int scale,
+        boolean nullable) {
         this.schemaName = schemaName;
         this.tblName = tblName;
         this.colName = colName;
         this.nullable = nullable;
 
-        this.dataType = type(cls.getName());
-        this.dataTypeName = typeName(cls.getName());
+        this.dataType = type(javaTypeName);
+        this.dataTypeName = typeName(javaTypeName);
+        this.dataTypeCls = javaTypeName;
         this.precision = precision;
         this.scale = scale;
 
@@ -195,6 +215,15 @@ public class JdbcColumnMeta extends Response {
         return nullable;
     }
 
+    /**
+     * Gets data type class.
+     *
+     * @return Data type class.
+     */
+    public String dataTypeClass() {
+        return dataTypeCls;
+    }
+
     /** {@inheritDoc} */
     @Override public void writeBinary(ClientMessagePacker packer) {
         super.writeBinary(packer);
@@ -202,12 +231,13 @@ public class JdbcColumnMeta extends Response {
         if (!hasResults)
             return;
 
-        packer.packString(schemaName);
-        packer.packString(tblName);
+        ClientMessageUtils.writeStringNullable(packer, schemaName);
+        ClientMessageUtils.writeStringNullable(packer, tblName);
         packer.packString(colName);
 
         packer.packInt(dataType);
         packer.packString(dataTypeName);
+        packer.packString(dataTypeCls);
         packer.packBoolean(nullable);
         packer.packInt(precision);
         packer.packInt(scale);
@@ -220,12 +250,13 @@ public class JdbcColumnMeta extends Response {
         if (!hasResults)
             return;
 
-        schemaName = unpacker.unpackString();
-        tblName = unpacker.unpackString();
+        schemaName = ClientMessageUtils.readStringNullable(unpacker);
+        tblName = ClientMessageUtils.readStringNullable(unpacker);
         colName = unpacker.unpackString();
 
         dataType = unpacker.unpackInt();
         dataTypeName = unpacker.unpackString();
+        dataTypeCls = unpacker.unpackString();
         nullable = unpacker.unpackBoolean();
         precision = unpacker.unpackInt();
         scale = unpacker.unpackInt();
@@ -247,6 +278,7 @@ public class JdbcColumnMeta extends Response {
             && Objects.equals(schemaName, meta.schemaName)
             && Objects.equals(tblName, meta.tblName)
             && Objects.equals(colName, meta.colName)
+            && Objects.equals(dataTypeCls, meta.dataTypeCls)
             && Objects.equals(dataTypeName, meta.dataTypeName);
     }
 
@@ -256,6 +288,7 @@ public class JdbcColumnMeta extends Response {
         result = 31 * result + (schemaName != null ? schemaName.hashCode() : 
0);
         result = 31 * result + (tblName != null ? tblName.hashCode() : 0);
         result = 31 * result + (colName != null ? colName.hashCode() : 0);
+        result = 31 * result + (dataTypeCls != null ? dataTypeCls.hashCode() : 
0);
         result = 31 * result + dataType;
         result = 31 * result + (dataTypeName != null ? dataTypeName.hashCode() 
: 0);
         result = 31 * result + precision;
diff --git 
a/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcMetaColumnsResult.java
 
b/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcMetaColumnsResult.java
index fed2195..5baabef 100644
--- 
a/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcMetaColumnsResult.java
+++ 
b/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcMetaColumnsResult.java
@@ -43,6 +43,16 @@ public class JdbcMetaColumnsResult extends Response {
     /**
      * Constructor.
      *
+     * @param status Status code.
+     * @param err Error message.
+     */
+    public JdbcMetaColumnsResult(int status, String err) {
+        super(status, err);
+    }
+
+    /**
+     * Constructor.
+     *
      * @param meta Columns metadata.
      */
     public JdbcMetaColumnsResult(Collection<JdbcColumnMeta> meta) {
diff --git 
a/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcMetaColumnsResult.java
 
b/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcQueryMetadataRequest.java
similarity index 50%
copy from 
modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcMetaColumnsResult.java
copy to 
modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcQueryMetadataRequest.java
index fed2195..0aec745 100644
--- 
a/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcMetaColumnsResult.java
+++ 
b/modules/client-common/src/main/java/org/apache/ignite/client/proto/query/event/JdbcQueryMetadataRequest.java
@@ -17,92 +17,54 @@
 
 package org.apache.ignite.client.proto.query.event;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
+import org.apache.ignite.client.proto.query.ClientMessage;
 import org.apache.ignite.internal.client.proto.ClientMessagePacker;
 import org.apache.ignite.internal.client.proto.ClientMessageUnpacker;
 import org.apache.ignite.internal.tostring.S;
 
 /**
- * JDBC columns metadata result.
+ * JDBC query metadata request.
  */
-public class JdbcMetaColumnsResult extends Response {
-    /** Columns metadata. */
-    private List<JdbcColumnMeta> meta;
+public class JdbcQueryMetadataRequest implements ClientMessage {
+    /** Cursor ID. */
+    private long cursorId;
 
     /**
-     * Default constructor is used for deserialization.
+     * Default constructor.
      */
-    public JdbcMetaColumnsResult() {
+    public JdbcQueryMetadataRequest() {
     }
 
     /**
      * Constructor.
      *
-     * @param meta Columns metadata.
+     * @param cursorId Cursor ID.
      */
-    public JdbcMetaColumnsResult(Collection<JdbcColumnMeta> meta) {
-        Objects.requireNonNull(meta);
-
-        this.meta = new ArrayList<>(meta);
-
-        this.hasResults = true;
+    public JdbcQueryMetadataRequest(long cursorId) {
+        this.cursorId = cursorId;
     }
 
     /**
-     * Gets column metadata.
+     * Get the cursor id.
      *
-     * @return Columns metadata.
+     * @return Cursor ID.
      */
-    public List<JdbcColumnMeta> meta() {
-        return meta;
+    public long cursorId() {
+        return cursorId;
     }
 
     /** {@inheritDoc} */
     @Override public void writeBinary(ClientMessagePacker packer) {
-        super.writeBinary(packer);
-
-        if (!hasResults)
-            return;
-
-        packer.packArrayHeader(meta.size());
-
-        for (JdbcColumnMeta m : meta)
-            m.writeBinary(packer);
+        packer.packLong(cursorId);
     }
 
     /** {@inheritDoc} */
     @Override public void readBinary(ClientMessageUnpacker unpacker) {
-        super.readBinary(unpacker);
-
-        if (!hasResults)
-            return;
-
-        int size = unpacker.unpackArrayHeader();
-
-        if (size == 0) {
-            meta = Collections.emptyList();
-
-            return;
-        }
-
-        meta = new ArrayList<>(size);
-
-        for (int i = 0; i < size; ++i) {
-            var m = new JdbcColumnMeta();
-
-            m.readBinary(unpacker);
-
-            meta.add(m);
-        }
+        cursorId = unpacker.unpackLong();
     }
 
     /** {@inheritDoc} */
     @Override public String toString() {
-        return S.toString(JdbcMetaColumnsResult.class, this);
+        return S.toString(JdbcQueryMetadataRequest.class, this);
     }
 }
diff --git 
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientDataType.java
 
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientDataType.java
index 603127e..c9ac4b6 100644
--- 
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientDataType.java
+++ 
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientDataType.java
@@ -71,4 +71,7 @@ public class ClientDataType {
 
     /** Boolean. */
     public static final int BOOLEAN = 17;
+
+    /** Big Integer. */
+    public static final int BIGINTEGER = 18;
 }
diff --git 
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessagePacker.java
 
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessagePacker.java
index ea24276..e0406d3 100644
--- 
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessagePacker.java
+++ 
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessagePacker.java
@@ -701,6 +701,14 @@ public class ClientMessagePacker extends MessagePacker {
                 packInt(ClientDataType.TIMESTAMP);
                 packTimestamp(((java.util.Date)arg).toInstant());
             }
+            else if (cls == BigDecimal.class) {
+                packInt(ClientDataType.DECIMAL);
+                packDecimal(((BigDecimal)arg));
+            }
+            else if (cls == BigInteger.class) {
+                packInt(ClientDataType.BIGINTEGER);
+                packBigInteger(((BigInteger)arg));
+            }
             else
                 throw new UnsupportedOperationException("Custom objects are 
not supported");
         }
diff --git 
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessageUnpacker.java
 
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessageUnpacker.java
index 4474e01..feb848d 100644
--- 
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessageUnpacker.java
+++ 
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessageUnpacker.java
@@ -42,6 +42,7 @@ import org.msgpack.core.MessageUnpacker;
 import org.msgpack.core.buffer.InputStreamBufferInput;
 import org.msgpack.value.ImmutableValue;
 
+import static 
org.apache.ignite.internal.client.proto.ClientDataType.BIGINTEGER;
 import static org.apache.ignite.internal.client.proto.ClientDataType.BITMASK;
 import static org.apache.ignite.internal.client.proto.ClientDataType.BOOLEAN;
 import static org.apache.ignite.internal.client.proto.ClientDataType.BYTES;
@@ -616,6 +617,9 @@ public class ClientMessageUnpacker extends MessageUnpacker {
             case DECIMAL:
                 return unpackDecimal();
 
+            case BIGINTEGER:
+                return unpackBigInteger();
+
             case BITMASK:
                 return unpackBitSet();
 
diff --git 
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientOp.java
 
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientOp.java
index 87b44ad..98ade7f 100644
--- 
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientOp.java
+++ 
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientOp.java
@@ -131,4 +131,7 @@ public class ClientOp {
 
     /** Get primary key metadata. */
     public static final int SQL_PK_META = 41;
+
+    /** Get query metadata. */
+    public static final int SQL_QUERY_META = 42;
 }
diff --git 
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/ClientInboundMessageHandler.java
 
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/ClientInboundMessageHandler.java
index 47173c8..c615e8f 100644
--- 
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/ClientInboundMessageHandler.java
+++ 
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/ClientInboundMessageHandler.java
@@ -30,6 +30,7 @@ import 
org.apache.ignite.client.handler.requests.sql.ClientSqlExecuteBatchReques
 import org.apache.ignite.client.handler.requests.sql.ClientSqlExecuteRequest;
 import org.apache.ignite.client.handler.requests.sql.ClientSqlFetchRequest;
 import 
org.apache.ignite.client.handler.requests.sql.ClientSqlPrimaryKeyMetadataRequest;
+import 
org.apache.ignite.client.handler.requests.sql.ClientSqlQueryMetadataRequest;
 import 
org.apache.ignite.client.handler.requests.sql.ClientSqlSchemasMetadataRequest;
 import 
org.apache.ignite.client.handler.requests.sql.ClientSqlTableMetadataRequest;
 import org.apache.ignite.client.handler.requests.sql.JdbcMetadataCatalog;
@@ -368,6 +369,9 @@ public class ClientInboundMessageHandler extends 
ChannelInboundHandlerAdapter {
             case ClientOp.SQL_PK_META:
                 return ClientSqlPrimaryKeyMetadataRequest.process(in, out, 
handler);
 
+            case ClientOp.SQL_QUERY_META:
+                return ClientSqlQueryMetadataRequest.process(in, out, handler);
+
             default:
                 throw new IgniteException("Unexpected operation code: " + 
opCode);
         }
diff --git 
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/JdbcQueryEventHandlerImpl.java
 
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/JdbcQueryEventHandlerImpl.java
index c6001ea..5befe1b 100644
--- 
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/JdbcQueryEventHandlerImpl.java
+++ 
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/JdbcQueryEventHandlerImpl.java
@@ -24,6 +24,8 @@ import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicLong;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.ignite.client.handler.requests.sql.JdbcMetadataCatalog;
 import org.apache.ignite.client.proto.query.JdbcQueryEventHandler;
 import org.apache.ignite.client.proto.query.event.BatchExecuteRequest;
@@ -38,6 +40,7 @@ import 
org.apache.ignite.client.proto.query.event.JdbcMetaSchemasResult;
 import org.apache.ignite.client.proto.query.event.JdbcMetaTablesRequest;
 import org.apache.ignite.client.proto.query.event.JdbcMetaTablesResult;
 import org.apache.ignite.client.proto.query.event.JdbcPrimaryKeyMeta;
+import org.apache.ignite.client.proto.query.event.JdbcQueryMetadataRequest;
 import org.apache.ignite.client.proto.query.event.JdbcTableMeta;
 import org.apache.ignite.client.proto.query.event.QueryCloseRequest;
 import org.apache.ignite.client.proto.query.event.QueryCloseResult;
@@ -49,6 +52,8 @@ import 
org.apache.ignite.client.proto.query.event.QuerySingleResult;
 import org.apache.ignite.client.proto.query.event.Response;
 import org.apache.ignite.internal.processors.query.calcite.QueryProcessor;
 import org.apache.ignite.internal.processors.query.calcite.SqlCursor;
+import 
org.apache.ignite.internal.processors.query.calcite.prepare.FieldsMetadata;
+import 
org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
 import org.apache.ignite.internal.util.Cursor;
 
 import static 
org.apache.ignite.client.proto.query.IgniteQueryErrorCode.UNSUPPORTED_OPERATION;
@@ -173,6 +178,65 @@ public class JdbcQueryEventHandlerImpl implements 
JdbcQueryEventHandler {
     }
 
     /** {@inheritDoc} */
+    @Override public JdbcMetaColumnsResult 
queryMetadata(JdbcQueryMetadataRequest req) {
+        SqlCursor<List<?>> cur = openCursors.get(req.cursorId());
+
+        if (cur == null)
+            return new JdbcMetaColumnsResult(Response.STATUS_FAILED,
+                "Failed to find query cursor with ID: " + req.cursorId());
+
+        if (cur.getColumnMetadata() == null)
+            return new JdbcMetaColumnsResult(Response.STATUS_FAILED,
+                "Failed to get query metadata for cursor with ID : " + 
req.cursorId());
+
+        FieldsMetadata metadata = cur.getColumnMetadata();
+
+        List<List<String>> origins = metadata.origins();
+        List<RelDataTypeField> list = metadata.rowType().getFieldList();
+
+        List<JdbcColumnMeta> meta = new ArrayList<>(list.size());
+
+        IgniteTypeFactory factory = new IgniteTypeFactory();
+
+        for (int i = 0; i < list.size(); i++) {
+            RelDataTypeField field = list.get(i);
+            List<String> origin = origins == null ? null : origins.get(i);
+
+            meta.add(createColumnMetadata(origin, field, factory));
+        }
+
+        return new JdbcMetaColumnsResult(meta);
+    }
+
+    /**
+     * Create Jdbc representation of column metadata from given origin and 
RelDataTypeField field.
+     *
+     * @param origin List of column origin. Contains schema name and table 
name. Might be null.
+     * @param field RelDataTypeField field with info about column.
+     * @param factory IgniteTypeFactory.
+     * @return JdbcColumnMeta object.
+     */
+    private JdbcColumnMeta createColumnMetadata(List<String> origin, 
RelDataTypeField field, IgniteTypeFactory factory) {
+        RelDataType val = field.getValue();
+
+        String schemaName = origin == null ? null : origin.get(0);
+        String tblName = origin == null ? null : origin.get(1);
+
+        String colName = field.getKey();
+        boolean isNullable = val.isNullable();
+
+        return new JdbcColumnMeta(
+            schemaName,
+            tblName,
+            colName,
+            factory.getJavaClass(val).getTypeName(),
+            val.getPrecision(),
+            val.getScale(),
+            isNullable
+        );
+    }
+
+    /** {@inheritDoc} */
     @Override public JdbcMetaTablesResult tablesMeta(JdbcMetaTablesRequest 
req) {
         List<JdbcTableMeta> tblsMeta = meta.getTablesMeta(req.schemaName(), 
req.tableName(), req.tableTypes());
 
diff --git 
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlQueryMetadataRequest.java
 
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlQueryMetadataRequest.java
new file mode 100644
index 0000000..ff0c574
--- /dev/null
+++ 
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlQueryMetadataRequest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.client.handler.requests.sql;
+
+import java.util.concurrent.CompletableFuture;
+import org.apache.ignite.client.proto.query.JdbcQueryEventHandler;
+import org.apache.ignite.client.proto.query.event.JdbcMetaColumnsResult;
+import org.apache.ignite.client.proto.query.event.JdbcQueryMetadataRequest;
+import org.apache.ignite.internal.client.proto.ClientMessagePacker;
+import org.apache.ignite.internal.client.proto.ClientMessageUnpacker;
+
+/**
+ * Client sql query metadata request handler.
+ */
+public class ClientSqlQueryMetadataRequest {
+    /**
+     * Processes remote {@code JdbcQueryMetadataRequest}.
+     *
+     * @param in Client message unpacker.
+     * @param out Client message packer.
+     * @param handler Query event handler.
+     * @return null value indicates synchronous operation.
+     */
+    public static CompletableFuture<Void> process(
+        ClientMessageUnpacker in,
+        ClientMessagePacker out,
+        JdbcQueryEventHandler handler
+    ) {
+        var req = new JdbcQueryMetadataRequest();
+
+        req.readBinary(in);
+
+        JdbcMetaColumnsResult res = handler.queryMetadata(req);
+
+        res.writeBinary(out);
+
+        return null;
+    }
+}
diff --git 
a/modules/client/src/main/java/org/apache/ignite/internal/client/query/JdbcClientQueryEventHandler.java
 
b/modules/client/src/main/java/org/apache/ignite/internal/client/query/JdbcClientQueryEventHandler.java
index 441776c..e62deeb 100644
--- 
a/modules/client/src/main/java/org/apache/ignite/internal/client/query/JdbcClientQueryEventHandler.java
+++ 
b/modules/client/src/main/java/org/apache/ignite/internal/client/query/JdbcClientQueryEventHandler.java
@@ -28,6 +28,7 @@ import 
org.apache.ignite.client.proto.query.event.JdbcMetaSchemasRequest;
 import org.apache.ignite.client.proto.query.event.JdbcMetaSchemasResult;
 import org.apache.ignite.client.proto.query.event.JdbcMetaTablesRequest;
 import org.apache.ignite.client.proto.query.event.JdbcMetaTablesResult;
+import org.apache.ignite.client.proto.query.event.JdbcQueryMetadataRequest;
 import org.apache.ignite.client.proto.query.event.QueryCloseRequest;
 import org.apache.ignite.client.proto.query.event.QueryCloseResult;
 import org.apache.ignite.client.proto.query.event.QueryExecuteRequest;
@@ -122,4 +123,13 @@ public class JdbcClientQueryEventHandler implements 
JdbcQueryEventHandler {
 
         return res;
     }
+
+    /** {@inheritDoc} */
+    @Override public JdbcMetaColumnsResult 
queryMetadata(JdbcQueryMetadataRequest req) {
+        JdbcMetaColumnsResult res = new JdbcMetaColumnsResult();
+
+        client.sendRequest(ClientOp.SQL_QUERY_META, req, res);
+
+        return res;
+    }
 }
diff --git 
a/modules/client/src/main/java/org/apache/ignite/internal/jdbc/JdbcResultSet.java
 
b/modules/client/src/main/java/org/apache/ignite/internal/jdbc/JdbcResultSet.java
index 8d4a61a..3c4db6f 100644
--- 
a/modules/client/src/main/java/org/apache/ignite/internal/jdbc/JdbcResultSet.java
+++ 
b/modules/client/src/main/java/org/apache/ignite/internal/jdbc/JdbcResultSet.java
@@ -57,6 +57,8 @@ import 
org.apache.ignite.client.proto.query.IgniteQueryErrorCode;
 import org.apache.ignite.client.proto.query.JdbcQueryEventHandler;
 import org.apache.ignite.client.proto.query.SqlStateCode;
 import org.apache.ignite.client.proto.query.event.JdbcColumnMeta;
+import org.apache.ignite.client.proto.query.event.JdbcMetaColumnsResult;
+import org.apache.ignite.client.proto.query.event.JdbcQueryMetadataRequest;
 import org.apache.ignite.client.proto.query.event.QueryCloseRequest;
 import org.apache.ignite.client.proto.query.event.QueryCloseResult;
 import org.apache.ignite.client.proto.query.event.QueryFetchRequest;
@@ -137,6 +139,9 @@ public class JdbcResultSet implements ResultSet {
     /** Query request handler. */
     private JdbcQueryEventHandler qryHandler;
 
+    /** Jdbc metadata. */
+    private JdbcResultSetMetadata jdbcMeta;
+
     /**
      * Creates new result set.
      *
@@ -721,7 +726,10 @@ public class JdbcResultSet implements ResultSet {
     @Override public ResultSetMetaData getMetaData() throws SQLException {
         ensureNotClosed();
 
-        throw new SQLFeatureNotSupportedException("ResultSetMetaData are not 
supported.");
+        if (jdbcMeta == null)
+            jdbcMeta = new JdbcResultSetMetadata(meta());
+
+        return jdbcMeta;
     }
 
     /** {@inheritDoc} */
@@ -730,9 +738,6 @@ public class JdbcResultSet implements ResultSet {
 
         Objects.requireNonNull(colLb);
 
-        if (!metaInit)
-            throw new SQLFeatureNotSupportedException("FindColumn by column 
label are not supported.");
-
         Integer order = columnOrder().get(colLb.toUpperCase());
 
         if (order == null)
@@ -1971,6 +1976,14 @@ public class JdbcResultSet implements ResultSet {
         if (finished && (!isQuery || autoClose))
             throw new SQLException("Server cursor is already closed.", 
SqlStateCode.INVALID_CURSOR_STATE);
 
-        throw new SQLFeatureNotSupportedException("ResultSetMetaData are not 
supported.");
+        if (!metaInit) {
+            JdbcMetaColumnsResult res = qryHandler.queryMetadata(new 
JdbcQueryMetadataRequest(cursorId));
+
+            meta = res.meta();
+
+            metaInit = true;
+        }
+
+        return meta;
     }
 }
diff --git 
a/modules/client/src/main/java/org/apache/ignite/internal/jdbc/JdbcResultSetMetadata.java
 
b/modules/client/src/main/java/org/apache/ignite/internal/jdbc/JdbcResultSetMetadata.java
new file mode 100644
index 0000000..2feed79
--- /dev/null
+++ 
b/modules/client/src/main/java/org/apache/ignite/internal/jdbc/JdbcResultSetMetadata.java
@@ -0,0 +1,163 @@
+/*
+ * 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.jdbc;
+
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.List;
+import org.apache.ignite.client.proto.query.event.JdbcColumnMeta;
+
+/**
+ * JDBC result set metadata implementation.
+ */
+public class JdbcResultSetMetadata implements ResultSetMetaData {
+    /** Column width. */
+    private static final int COL_WIDTH = 30;
+
+    /** Table names. */
+    private final List<JdbcColumnMeta> meta;
+
+    /**
+     * Constructor.
+     *
+     * @param meta Metadata.
+     */
+    JdbcResultSetMetadata(List<JdbcColumnMeta> meta) {
+        assert meta != null;
+
+        this.meta = meta;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getColumnCount() throws SQLException {
+        return meta.size();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isAutoIncrement(int col) throws SQLException {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isCaseSensitive(int col) throws SQLException {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isSearchable(int col) throws SQLException {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isCurrency(int col) throws SQLException {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int isNullable(int col) throws SQLException {
+        return columnNullable;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isSigned(int col) throws SQLException {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getColumnDisplaySize(int col) throws SQLException {
+        return COL_WIDTH;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getColumnLabel(int col) throws SQLException {
+        return meta.get(col - 1).columnName();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getColumnName(int col) throws SQLException {
+        return meta.get(col - 1).columnName();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getSchemaName(int col) throws SQLException {
+        return meta.get(col - 1).schemaName();
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getPrecision(int col) throws SQLException {
+        return meta.get(col - 1).precision();
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getScale(int col) throws SQLException {
+        return meta.get(col - 1).scale();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getTableName(int col) throws SQLException {
+        return meta.get(col - 1).tableName();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getCatalogName(int col) throws SQLException {
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getColumnType(int col) throws SQLException {
+        return meta.get(col - 1).dataType();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getColumnTypeName(int col) throws SQLException {
+        return meta.get(col - 1).dataTypeName();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isReadOnly(int col) throws SQLException {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isWritable(int col) throws SQLException {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isDefinitelyWritable(int col) throws SQLException 
{
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getColumnClassName(int col) throws SQLException {
+        return meta.get(col - 1).dataTypeClass();
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T unwrap(Class<T> iface) throws SQLException {
+        if (!isWrapperFor(iface))
+            throw new SQLException("Result set meta data is not a wrapper for 
" + iface.getName());
+
+        return (T)this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isWrapperFor(Class<?> iface) throws SQLException {
+        return iface != null && 
iface.isAssignableFrom(JdbcResultSetMetadata.class);
+    }
+}
\ No newline at end of file
diff --git 
a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeCursor.java 
b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeCursor.java
index cd8f5a2..2e50709 100644
--- 
a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeCursor.java
+++ 
b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeCursor.java
@@ -24,6 +24,7 @@ import java.util.Random;
 import java.util.UUID;
 import org.apache.ignite.internal.processors.query.calcite.SqlCursor;
 import org.apache.ignite.internal.processors.query.calcite.SqlQueryType;
+import 
org.apache.ignite.internal.processors.query.calcite.prepare.FieldsMetadata;
 
 public class FakeCursor implements SqlCursor<List<?>> {
 
@@ -60,4 +61,8 @@ public class FakeCursor implements SqlCursor<List<?>> {
     @Override public SqlQueryType getQueryType() {
         return SqlQueryType.QUERY;
     }
+
+    @Override public FieldsMetadata getColumnMetadata() {
+        return null;
+    }
 }
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/AbstractJdbcSelfTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/AbstractJdbcSelfTest.java
index d6b13c7..c74bebf 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/AbstractJdbcSelfTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/AbstractJdbcSelfTest.java
@@ -48,7 +48,7 @@ public class AbstractJdbcSelfTest {
     }};
 
     /** Cluster nodes. */
-    private static final List<Ignite> clusterNodes = new ArrayList<>();
+    protected static final List<Ignite> clusterNodes = new ArrayList<>();
 
     /**
      * Creates a cluster of three nodes.
@@ -71,9 +71,10 @@ public class AbstractJdbcSelfTest {
      */
     @AfterAll
     public static void afterAll() throws Exception {
-        for (Ignite clusterNode : clusterNodes) {
+        for (Ignite clusterNode : clusterNodes)
             clusterNode.close();
-        }
+
+        clusterNodes.clear();
     }
 
     /**
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcConnectionPropertiesTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcConnectionPropertiesTest.java
similarity index 97%
rename from 
modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcConnectionPropertiesTest.java
rename to 
modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcConnectionPropertiesTest.java
index 00f82b7..8b328be 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcConnectionPropertiesTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcConnectionPropertiesTest.java
@@ -27,7 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 /**
  * {@link ConnectionPropertiesImpl} unit tests.
  */
-public class JdbcConnectionPropertiesTest {
+public class ITJdbcConnectionPropertiesTest {
     /**
      * Test check the {@link ConnectionPropertiesImpl#getDriverPropertyInfo()} 
return properties with prefix {@link
      * ConnectionPropertiesImpl#PROP_PREFIX}
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcConnectionSelfTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcConnectionSelfTest.java
similarity index 99%
rename from 
modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcConnectionSelfTest.java
rename to 
modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcConnectionSelfTest.java
index afe3bf2..003d9ae 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcConnectionSelfTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcConnectionSelfTest.java
@@ -59,7 +59,7 @@ import static org.junit.jupiter.api.Assertions.fail;
  * Connection test.
  */
 @SuppressWarnings("ThrowableNotThrown")
-public class JdbcConnectionSelfTest extends AbstractJdbcSelfTest {
+public class ITJdbcConnectionSelfTest extends AbstractJdbcSelfTest {
     /**
      * @throws Exception If failed.
      */
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcMetadataSelfTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcMetadataSelfTest.java
similarity index 92%
rename from 
modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcMetadataSelfTest.java
rename to 
modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcMetadataSelfTest.java
index 7818ec7..395cf26 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcMetadataSelfTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcMetadataSelfTest.java
@@ -18,7 +18,6 @@
 package org.apache.ignite.internal.runner.app.jdbc;
 
 import java.math.BigDecimal;
-import java.nio.file.Path;
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.DriverManager;
@@ -32,26 +31,17 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
 import java.util.Set;
-import org.apache.ignite.app.Ignite;
-import org.apache.ignite.app.IgnitionManager;
 import org.apache.ignite.internal.client.proto.ProtocolVersion;
 import 
org.apache.ignite.internal.schema.configuration.SchemaConfigurationConverter;
-import org.apache.ignite.jdbc.IgniteJdbcDriver;
 import org.apache.ignite.schema.ColumnType;
 import org.apache.ignite.schema.SchemaBuilders;
 import org.apache.ignite.schema.SchemaTable;
 import org.apache.ignite.table.Table;
 import org.apache.ignite.table.Tuple;
-import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
 
 import static java.sql.Types.DATE;
 import static java.sql.Types.DECIMAL;
@@ -66,56 +56,15 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 /**
  * Metadata tests.
  */
-public class JdbcMetadataSelfTest {
+public class ITJdbcMetadataSelfTest extends AbstractJdbcSelfTest {
     /** URL. */
     protected static final String URL = "jdbc:ignite:thin://127.0.1.1:10800";
 
-    /** Nodes bootstrap configuration. */
-    private static final Map<String, String> nodesBootstrapCfg = new 
LinkedHashMap<>() {{
-        put("node2", "{\n" +
-            "  \"node\": {\n" +
-            "    \"metastorageNodes\":[ \"node2\" ]\n" +
-            "  }\n" +
-            "}");
-    }};
-
-    /** Cluster nodes. */
-    protected static final List<Ignite> clusterNodes = new ArrayList<>();
-
-    /**
-     * Creates a cluster of three nodes.
-     *
-     * @param temp Temporal directory.
-     */
+    /** Creates tables. */
     @BeforeAll
-    public static void beforeAll(@TempDir Path temp) {
-        IgniteJdbcDriver.register();
-
-        nodesBootstrapCfg.forEach((nodeName, configStr) ->
-            clusterNodes.add(IgnitionManager.start(nodeName, configStr, 
temp.resolve(nodeName)))
-        );
-    }
-
-    /**
-     * Close all cluster nodes.
-     *
-     * @throws Exception if failed.
-     */
-    @AfterAll
-    public static void afterAll() throws Exception {
-        for (Ignite clusterNode : clusterNodes) {
-            clusterNode.close();
-        }
-    }
+    public static void createTables() {
+        assert !clusterNodes.isEmpty();
 
-    /**
-     * Create the connection ant statement.
-     *
-     * @throws Exception if failed.
-     */
-    @BeforeEach
-    public void beforeTest() {
-        // Create table on node 0.
         SchemaTable perTbl = SchemaBuilders.tableBuilder("PUBLIC", 
"PERSON").columns(
             SchemaBuilders.column("NAME", 
ColumnType.string()).asNullable().build(),
             SchemaBuilders.column("AGE", 
ColumnType.INT32).asNullable().build(),
@@ -128,9 +77,6 @@ public class JdbcMetadataSelfTest {
             SchemaBuilders.column("BIGDATA", ColumnType.decimalOf(20, 
10)).asNullable().build()
         ).withPrimaryKey("ID").build();
 
-        if (clusterNodes.get(0).tables().table(perTbl.canonicalName()) != null)
-            return;
-
         clusterNodes.get(0).tables().createTable(perTbl.canonicalName(), tblCh 
->
             SchemaConfigurationConverter.convert(perTbl, tblCh)
                 .changeReplicas(1)
@@ -154,7 +100,6 @@ public class JdbcMetadataSelfTest {
      * @throws Exception If failed.
      */
     @Test
-    @Disabled("IGNITE-15187")
     public void testResultSetMetaData() throws Exception {
         Statement stmt = DriverManager.getConnection(URL).createStatement();
 
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcResultSetSelfTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcResultSetSelfTest.java
similarity index 95%
rename from 
modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcResultSetSelfTest.java
rename to 
modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcResultSetSelfTest.java
index 7d2a483..e530f62 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcResultSetSelfTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcResultSetSelfTest.java
@@ -49,11 +49,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 /**
  * Result set test.
  */
-public class JdbcResultSetSelfTest extends AbstractJdbcSelfTest {
+public class ITJdbcResultSetSelfTest extends AbstractJdbcSelfTest {
     /** SQL query. */
     private static final String SQL =
-        "SELECT 1::INTEGER, true, 1::TINYINT, 1::SMALLINT, 1::INTEGER, 
1::BIGINT, 1.0::FLOAT, 1.0::DOUBLE, 1.0::DOUBLE, " +
-            "'1', '1', '1901-02-01'::DATE, '01:01:01'::TIME, 1::TIMESTAMP;";
+        "SELECT 1::INTEGER as id, true as boolVal, 1::TINYINT as byteVal, 
1::SMALLINT as shortVal, 1::INTEGER as intVal, 1::BIGINT as longVal, 1.0::FLOAT 
as floatVal, 1.0::DOUBLE as doubleVal, 1.0::DECIMAL as bigVal, " +
+            "'1' as strVal, '1', '1901-02-01'::DATE as dateVal, 
'01:01:01'::TIME as timeVal, 1::TIMESTAMP as tsVal;";
 
     /** Statement. */
     private Statement stmt;
@@ -100,8 +100,7 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
 
         while (rs.next()) {
             if (cnt == 0) {
-                //TODO IGNITE-15187
-//                assert rs.getBoolean("boolVal");
+                assertTrue(rs.getBoolean("boolVal"));
                 assertTrue(rs.getBoolean(2));
                 assertEquals(1, rs.getByte(2));
                 assertEquals(1, rs.getInt(2));
@@ -174,9 +173,7 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
 
         while (rs.next()) {
             if (cnt == 0) {
-                //TODO IGNITE-15187
-//                assert rs.getByte("byteVal") == 1;
-
+                assertEquals(1, rs.getByte("byteVal"));
                 assertTrue(rs.getBoolean(3));
                 assertEquals(1, rs.getByte(3));
                 assertEquals(1, rs.getInt(3));
@@ -216,8 +213,7 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
 
         while (rs.next()) {
             if (cnt == 0) {
-                //TODO IGNITE-15187
-//                assert rs.getShort("shortVal") == 1;
+                assertEquals(1, rs.getShort("shortVal"));
 
                 assertTrue(rs.getBoolean(4));
                 assertEquals(1, rs.getByte(4));
@@ -258,8 +254,7 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
 
         while (rs.next()) {
             if (cnt == 0) {
-                //TODO IGNITE-15187
-//                assert rs.getInt("intVal") == 1;
+                assertEquals(1, rs.getInt("intVal"));
 
                 assertTrue(rs.getBoolean(5));
                 assertEquals(1, rs.getByte(5));
@@ -300,8 +295,7 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
 
         while (rs.next()) {
             if (cnt == 0) {
-                //TODO IGNITE-15187
-//                assert rs.getLong("longVal") == 1;
+                assertEquals(1, rs.getLong("longVal"));
 
                 assertTrue(rs.getBoolean(6));
                 assertEquals(1, rs.getByte(6));
@@ -342,8 +336,7 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
 
         while (rs.next()) {
             if (cnt == 0) {
-                //TODO IGNITE-15187
-//                assert rs.getFloat("floatVal") == 1.0;
+                assertEquals(1.0, rs.getFloat("floatVal"));
 
                 assertTrue(rs.getBoolean(7));
                 assertEquals(1, rs.getByte(7));
@@ -384,8 +377,7 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
 
         while (rs.next()) {
             if (cnt == 0) {
-                //TODO IGNITE-15187
-//                assert rs.getDouble("doubleVal") == 1.0;
+                assertEquals(1.0, rs.getDouble("doubleVal"));
 
                 assertTrue(rs.getBoolean(8));
                 assertEquals(1, rs.getByte(8));
@@ -419,7 +411,6 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
      * @throws Exception If failed.
      */
     @Test
-    @Disabled
     public void testBigDecimal() throws Exception {
         ResultSet rs = stmt.executeQuery(SQL);
 
@@ -436,8 +427,8 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
                 assertEquals(1, rs.getLong(9));
                 assertEquals(1.0, rs.getDouble(9));
                 assertEquals(1.0f, rs.getFloat(9));
-                assertEquals(new BigDecimal(1), rs.getBigDecimal(9));
-                assertEquals(rs.getString(9), "1");
+                assertEquals(new BigDecimal("1.0"), rs.getBigDecimal(9));
+                assertEquals(rs.getString(9), "1.0");
 
                 assertTrue(rs.getObject(9, Boolean.class));
                 assertEquals((byte)1, rs.getObject(9, Byte.class));
@@ -446,8 +437,8 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
                 assertEquals(1, rs.getObject(9, Long.class));
                 assertEquals(1.f, rs.getObject(9, Float.class));
                 assertEquals(1, rs.getObject(9, Double.class));
-                assertEquals(new BigDecimal(1), rs.getObject(9, 
BigDecimal.class));
-                assertEquals(rs.getObject(9, String.class), "1");
+                assertEquals(new BigDecimal("1.0"), rs.getObject(9, 
BigDecimal.class));
+                assertEquals(rs.getObject(9, String.class), "1.0");
             }
 
             cnt++;
@@ -495,8 +486,7 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
 
         while (rs.next()) {
             if (cnt == 0) {
-                //TODO IGNITE-15187
-                //assert "1".equals(rs.getString("strVal"));
+                assert "1".equals(rs.getString("strVal"));
 
                 assertTrue(rs.getBoolean(10));
                 assertEquals(1, rs.getByte(10));
@@ -564,7 +554,7 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
 
         while (rs.next()) {
             if (cnt == 0) {
-//                assert rs.getDate("dateVal").equals(new Date(1, 1, 1));
+                assert rs.getDate("dateVal").equals(new Date(1, 1, 1));
 
                 assertEquals(new Date(1, 1, 1), rs.getDate(12));
                 assertEquals(new Time(new Date(1, 1, 1).getTime()), 
rs.getTime(12));
@@ -595,7 +585,7 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
 
         while (rs.next()) {
             if (cnt == 0) {
-//                assert rs.getTime("timeVal").equals(new Time(1, 1, 1));
+                assert rs.getTime("timeVal").equals(new Time(1, 1, 1));
 
                 assertEquals(new Date(new Time(1, 1, 1).getTime()), 
rs.getDate(13));
                 assertEquals(new Time(1, 1, 1), rs.getTime(13));
@@ -625,7 +615,7 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
 
         while (rs.next()) {
             if (cnt == 0) {
-//                assert rs.getTimestamp("tsVal").getTime() == 1;
+                assertEquals(-10800000, rs.getTimestamp("tsVal").getTime());
                 assertEquals(new Date(new Timestamp(-10800000).getTime()), 
rs.getDate(14));
                 assertEquals(new Time(new Timestamp(-10800000).getTime()), 
rs.getTime(14));
                 assertEquals(new Timestamp(-10800000), rs.getTimestamp(14));
@@ -718,12 +708,9 @@ public class JdbcResultSetSelfTest extends 
AbstractJdbcSelfTest {
     }
 
     /**
-     * TODO IGNITE-15187
-     *
      * @throws Exception If failed.
      */
     @Test
-    @Disabled
     public void testFindColumn() throws Exception {
         final ResultSet rs = stmt.executeQuery(SQL);
 
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcStatementSelfTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcStatementSelfTest.java
similarity index 99%
rename from 
modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcStatementSelfTest.java
rename to 
modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcStatementSelfTest.java
index 1268001..c24e0d6 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/JdbcStatementSelfTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ITJdbcStatementSelfTest.java
@@ -40,7 +40,7 @@ import static org.junit.jupiter.api.Assertions.fail;
  * Statement test.
  */
 @SuppressWarnings({"ThrowableNotThrown"})
-public class JdbcStatementSelfTest extends AbstractJdbcSelfTest {
+public class ITJdbcStatementSelfTest extends AbstractJdbcSelfTest {
     /** SQL query. */
     private static final String SQL =
         "select 1::INTEGER, true, 1::TINYINT, 1::SMALLINT, 1::INTEGER, 
1::BIGINT, 1.0::FLOAT, 1.0::DOUBLE, 1.0::DOUBLE, '1';";
@@ -89,7 +89,7 @@ public class JdbcStatementSelfTest extends 
AbstractJdbcSelfTest {
      * @throws Exception If failed.
      */
     @Test
-    @Disabled("IGNITE-15187 + IGNITE-15108")
+    @Disabled("IGNITE-15108")
     public void testExecuteQuery0() throws Exception {
         ResultSet rs = stmt.executeQuery(SQL);
 
@@ -146,7 +146,7 @@ public class JdbcStatementSelfTest extends 
AbstractJdbcSelfTest {
      * @throws Exception If failed.
      */
     @Test
-    @Disabled("IGNITE-15187 + IGNITE-15108")
+    @Disabled("IGNITE-15108")
     public void testExecute() throws Exception {
         assertTrue(stmt.execute(SQL));
 
@@ -186,7 +186,7 @@ public class JdbcStatementSelfTest extends 
AbstractJdbcSelfTest {
      * @throws Exception If failed.
      */
     @Test
-    @Disabled("IGNITE-15187 + IGNITE-15108")
+    @Disabled("IGNITE-15108")
     public void testMaxRows() throws Exception {
         stmt.setMaxRows(1);
 

Reply via email to