You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by am...@apache.org on 2021/08/02 12:06:01 UTC

[ignite-3] branch ignite-15212 created (now 8612fe8)

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

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


      at 8612fe8  Add transactions. Fix tests.

This branch includes the following new commits:

     new 6a2c7cb  Add module
     new 5797ee3  WIP.
     new 43041d5  Minor. add more todos.
     new a707a38  Minors
     new 8612fe8  Add transactions. Fix tests.

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[ignite-3] 01/05: Add module

Posted by am...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 6a2c7cb6d26d82a041df7ea97e3cd7ee738ba401
Author: Andrew Mashenkov <an...@gmail.com>
AuthorDate: Wed Jul 28 14:26:44 2021 +0300

    Add module
---
 modules/sql/pom.xml | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 parent/pom.xml      |  6 +++++
 pom.xml             |  1 +
 3 files changed, 72 insertions(+)

diff --git a/modules/sql/pom.xml b/modules/sql/pom.xml
new file mode 100644
index 0000000..b849e00
--- /dev/null
+++ b/modules/sql/pom.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ignite</groupId>
+        <artifactId>ignite-parent</artifactId>
+        <version>1</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>ignite-sql</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-calcite</artifactId>
+        </dependency>
+
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-junit-jupiter</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/parent/pom.xml b/parent/pom.xml
index ff9941a..07f258c 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -156,6 +156,12 @@
 
             <dependency>
                 <groupId>org.apache.ignite</groupId>
+                <artifactId>ignite-calcite</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.ignite</groupId>
                 <artifactId>ignite-cli-common</artifactId>
                 <version>${project.version}</version>
             </dependency>
diff --git a/pom.xml b/pom.xml
index 11cdcd5..c2b073a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,6 +61,7 @@
         <module>modules/rest</module>
         <module>modules/runner</module>
         <module>modules/schema</module>
+        <module>modules/sql</module>
         <module>modules/storage-api</module>
         <module>modules/storage-rocksdb</module>
         <module>modules/table</module>

[ignite-3] 03/05: Minor. add more todos.

Posted by am...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 43041d5a0f58a9e91cc319e64b62fea6b6b29bcf
Author: Andrew Mashenkov <an...@gmail.com>
AuthorDate: Thu Jul 29 18:41:54 2021 +0300

    Minor. add more todos.
---
 .../java/org/apache/ignite/query/sql/IgniteSql.java     | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java b/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java
index a44ab14..395100e 100644
--- a/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java
@@ -67,12 +67,6 @@ public interface IgniteSql {
 
     ///////////////// Query monitoring and management.
     /**
-     * Returns SQL views.
-     */
-    Object views(); //TODO: To be described.
-    //TODO: Add view for runnin queries.
-
-    /**
      * Return info of the queries. //TODO: "running on the node locally"? or "started on the node"? or both?
      *
      * @return Running queries infos.
@@ -86,6 +80,15 @@ public interface IgniteSql {
      */
     void killQuery(UUID queryID);
 
+    /**
+     * Returns SQL views.
+     */
+    Object views(); //TODO: TBD.
+
+    //TODO: View for running queries?
+    //TODO: View for memory Management?
+    //TODO: View for QueryMetrics?
+    //TODO: Any other SystemViews from Igntie 2.0?
 
     ////////////// Statistics management.
     Collection<Object> tableStatistics(String table); //TODO: Local or global? Ready or in-progress? TBD.
@@ -105,5 +108,7 @@ public interface IgniteSql {
 
     //TODO: Do we expect any SQL DDL pragrammatical API here? Why we have tables().create(), but not here?
     //TODO: alterTable()?
+
+    //TODO: Custom function registration. Do we need a view and unregister functionality?
 }
 

[ignite-3] 04/05: Minors

Posted by am...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit a707a38482a14f4abb35a7e850d253920642a6ea
Author: Andrew Mashenkov <an...@gmail.com>
AuthorDate: Fri Jul 30 14:18:05 2021 +0300

    Minors
---
 .../org/apache/ignite/query/sql/IgniteSql.java     | 65 +++++++++--------
 .../ignite/query/sql/IgniteTableStatistics.java    | 81 ++++++++++++++++++++++
 .../org/apache/ignite/query/sql/SqlColumnMeta.java |  2 -
 .../org/apache/ignite/query/sql/SqlResultSet.java  |  4 ++
 4 files changed, 117 insertions(+), 35 deletions(-)

diff --git a/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java b/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java
index 395100e..e5a1d3a 100644
--- a/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java
@@ -17,7 +17,6 @@
 
 package org.apache.ignite.query.sql;
 
-import java.util.Collection;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import org.apache.ignite.query.sql.reactive.ReactiveSqlResultSet;
@@ -34,11 +33,11 @@ public interface IgniteSql {
      * Shortcut method for running a query.
      *
      * @param sql SQL query template.
-     * @param args Arguments for template (optional)
+     * @param args Arguments for template (optional).
      * @return SQL query resultset.
      * @throws SQLException If failed.
      */
-    SqlResultSet execute(@NotNull String sql, @Nullable Object... args);
+    SqlResultSet execute(@NotNull String sql, Object... args);
 
     /**
      * Shortcut method for running a query in asynchronously.
@@ -62,16 +61,31 @@ public interface IgniteSql {
      */
     ReactiveSqlResultSet executeReactive(String sql, Object... args);
 
-    //TODO: Do we need a separate methods for DML/DDL that do not return the resultset? or extend a resultset?
+    /**
+     * Shortcut method for running a non-query statement.
+     *
+     * @param sql SQL statement template.
+     * @param args Agruments for template (optional).
+     * @return Number of updated rows.
+     */
+    int executeNonQuery(@NotNull String sql, @Nullable Object... args);
+    //TODO: useful for bulk DML query, when we don't care of results.
+    //TODO: in contrary, execute() method may return inserted rows IDs that looks useful if AutoIncrement ID column is used.
+
     //TODO: same methods for Statement.
 
-    ///////////////// Query monitoring and management.
     /**
-     * Return info of the queries. //TODO: "running on the node locally"? or "started on the node"? or both?
+     * Sets query session parameter.
      *
-     * @return Running queries infos.
+     * @param name Parameter name.
+     * @param value Parameter value.
      */
-    Collection<Object> runningQueries(); //TODO: Is it needed here or to be moved into the Views facade?
+    void setParameter(String name, Object value);
+    //TODO: User can set e.g. queryTimeout or force join order or whatever.
+    //TODO: This is similar to SQL "SET" operator which is used in JDBC/ODBC clients for session state manipulation.
+
+
+    //TODO: Move all of this to Session. Maybe facade instance could incapsulate a session implicitely?
 
     /**
      * Kills query by its' id.
@@ -81,34 +95,19 @@ public interface IgniteSql {
     void killQuery(UUID queryID);
 
     /**
-     * Returns SQL views.
+     * Returns statistics facade for table statistics management.
+     *
+     * Table statistics are used by SQL engine for SQL queries planning.
+     *
+     * @return Statistics facade.
      */
-    Object views(); //TODO: TBD.
-
-    //TODO: View for running queries?
-    //TODO: View for memory Management?
-    //TODO: View for QueryMetrics?
-    //TODO: Any other SystemViews from Igntie 2.0?
-
-    ////////////// Statistics management.
-    Collection<Object> tableStatistics(String table); //TODO: Local or global? Ready or in-progress? TBD.
-
-    CompletableFuture<Void> gatherStatistics(String table, Object statisticsConfiguration);
-    //TODO: Creates new statistics in addition, or drop old and replaces with new?
-    //TODO: Should the existed one be refreshed?
-
-    CompletableFuture<Void> refreshStatistics(String table, @Nullable String... optionalStatisticName);
-
-    void dropStatistics(String table, @Nullable String... optionalStatisticName);
-
-    void refreshLocalStatistics(String table, @Nullable String... optionalStatisticName); //TODO: Actually, drops local statistics to be automatically refreshed.
-
-
-    //////////////////// DDL
+    IgniteTableStatistics statistics();
+    // TODO: Do we need this here or move to Table facade?
 
-    //TODO: Do we expect any SQL DDL pragrammatical API here? Why we have tables().create(), but not here?
-    //TODO: alterTable()?
 
+    void registerUserFunction(Class type, String... methodNames); //TODO: Get function details from method annotations.
+    void registerUserFunction(Class type);
+    void unregistedUserFunction(String functionName);
     //TODO: Custom function registration. Do we need a view and unregister functionality?
 }
 
diff --git a/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteTableStatistics.java b/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteTableStatistics.java
new file mode 100644
index 0000000..d523b7f
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteTableStatistics.java
@@ -0,0 +1,81 @@
+/*
+ * 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.query.sql;
+
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Table statistics facade provides methods for managing table statistics.
+ * <p>
+ * Table statistics are used by SQL engine for SQL queries planning.
+ */
+public interface IgniteTableStatistics {
+    /**
+     * Get statistics info for table.
+     *
+     * @param tableName Table name.
+     * @return Statistics info collection.
+     */
+    Collection<StatisticInfo> statistics(String tableName); //TODO: Local or global? Ready or in-progress? TBD.
+
+    /**
+     * Creates statistics for a table and initiate it gathering on the nodes.
+     *
+     * @param tableName Table name.
+     * @param statisticsConfiguration Statistic configuration.
+     * @return Operation future.
+     */
+    CompletableFuture<Void> gather(String tableName, Object statisticsConfiguration);
+    //TODO: Creates new statistics in addition, or drop old and replaces with new?
+    //TODO: Should the existed one be refreshed? or fail with exception?
+    //TODO: What if existed statistics has different configuration?
+    //TODO: Can future be cancelled?
+
+    /**
+     * Refresh a global statistic by given name or all existed statistics if no statistic name specified.
+     *
+     * @param tableName Table name.
+     * @param statisticNames Statistic names (optional).
+     * @return Operation future.
+     */
+    CompletableFuture<Void> refresh(String tableName, String... statisticNames);
+    //TODO: What if statistics with name is not exists? one of names?
+
+    /**
+     * Drop table statistic.
+     *
+     * @param tableName Table name.
+     * @param statisticNames Statistic names.     //TODO: Can be empty?
+     */
+    void drop(String tableName, String... statisticNames);
+
+    /**
+     * Refresh local statistic.
+     *
+     * @param tableName Table name.
+     * @param statisticNames Statistic names.
+     */
+    void refreshLocal(String tableName, String... statisticNames); //TODO: Actually, drops local statistics to be automatically refreshed.
+
+    //TODO TBD.
+    interface StatisticInfo {
+        String name();
+        Object config();
+    }
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/query/sql/SqlColumnMeta.java b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlColumnMeta.java
index 856c82f..c7250a4 100644
--- a/modules/api/src/main/java/org/apache/ignite/query/sql/SqlColumnMeta.java
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlColumnMeta.java
@@ -48,7 +48,6 @@ public interface SqlColumnMeta {
      * @return Value type.
      */
     Class<?> valueClass();
-    //TODO: this maybe more useful in contraty to the previous one.
 
     /**
      * Row column nullability.
@@ -56,5 +55,4 @@ public interface SqlColumnMeta {
      * @return {@code true} if column is nullable, {@code false} otherwise.
      */
     boolean nullable();
-    //TODO: AFAIK, Calcite can derive column type for us.
 }
diff --git a/modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSet.java b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSet.java
index 174c914..2bbadcf 100644
--- a/modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSet.java
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSet.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.query.sql;
 
+import java.util.UUID;
+
 /**
  * SQL result set provides methods to access SQL query resul represented as collection of {@link SqlRow}.
  *
@@ -30,4 +32,6 @@ public interface SqlResultSet extends Iterable<SqlRow>, AutoCloseable {
      * @return ResultSet metadata.
      */
     SqlResultSetMeta metadata();
+
+    UUID queryId();
 }

[ignite-3] 02/05: WIP.

Posted by am...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 5797ee37dc64d45e103678848c68d1f1d81769ad
Author: Andrew Mashenkov <an...@gmail.com>
AuthorDate: Wed Jul 28 14:27:11 2021 +0300

    WIP.
---
 .../main/java/org/apache/ignite/app/Ignite.java    |   8 +
 .../org/apache/ignite/query/sql/IgniteSql.java     | 109 ++++++++++++
 .../Ignite.java => query/sql/SQLException.java}    |  36 ++--
 .../org/apache/ignite/query/sql/SqlColumnMeta.java |  60 +++++++
 .../Ignite.java => query/sql/SqlResultSet.java}    |  25 +--
 .../apache/ignite/query/sql/SqlResultSetMeta.java  |  63 +++++++
 .../{app/Ignite.java => query/sql/SqlRow.java}     |  26 +--
 .../sql/reactive/ReactiveSqlResultSet.java}        |  30 ++--
 .../org/apache/ignite/internal/app/IgniteImpl.java |  12 +-
 modules/sql/src/test/java/SqlTest.java             | 194 +++++++++++++++++++++
 modules/sql/src/test/java/TestRow.java             | 181 +++++++++++++++++++
 11 files changed, 677 insertions(+), 67 deletions(-)

diff --git a/modules/api/src/main/java/org/apache/ignite/app/Ignite.java b/modules/api/src/main/java/org/apache/ignite/app/Ignite.java
index 87e585a..aa4bd46 100644
--- a/modules/api/src/main/java/org/apache/ignite/app/Ignite.java
+++ b/modules/api/src/main/java/org/apache/ignite/app/Ignite.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.app;
 
+import org.apache.ignite.query.sql.IgniteSql;
 import org.apache.ignite.table.manager.IgniteTables;
 import org.apache.ignite.tx.IgniteTransactions;
 
@@ -37,4 +38,11 @@ public interface Ignite extends AutoCloseable {
      * @return Ignite transactions.
      */
     IgniteTransactions transactions();
+
+    /**
+     * Returns a facade for SQL quering.
+     *
+     * @return Ignite SQL facade.
+     */
+    IgniteSql sql();
 }
diff --git a/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java b/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java
new file mode 100644
index 0000000..a44ab14
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java
@@ -0,0 +1,109 @@
+/*
+ * 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.query.sql;
+
+import java.util.Collection;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import org.apache.ignite.query.sql.reactive.ReactiveSqlResultSet;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Ignite SQL query facade.
+ */
+// TODO: Do we wand a separate IgniteQuery facade for non-sql (index/scan/full-text) queries?
+public interface IgniteSql {
+    ////////////// Query execution.
+    /**
+     * Shortcut method for running a query.
+     *
+     * @param sql SQL query template.
+     * @param args Arguments for template (optional)
+     * @return SQL query resultset.
+     * @throws SQLException If failed.
+     */
+    SqlResultSet execute(@NotNull String sql, @Nullable Object... args);
+
+    /**
+     * Shortcut method for running a query in asynchronously.
+     *
+     * @param sql SQL query template.
+     * @param args Arguments for template (optional)
+     * @return Query future.
+     * @throws SQLException If failed.
+     */
+    CompletableFuture<SqlResultSet> executeAsync(String sql, Object... args);
+    //TODO: May fut.cancel() cancels a query? If so, describe behavior in Javadoc.
+    //TODO: Cassandra API offers pagination API here, for manual fetching control. Is their AsyncResultSet ever usefull?
+
+    /**
+     * Shortcut method for running a query in asynchronously.
+     *
+     * @param sql SQL query template.
+     * @param args Arguments for template (optional)
+     * @return Reactive result.
+     * @throws SQLException If failed.
+     */
+    ReactiveSqlResultSet executeReactive(String sql, Object... args);
+
+    //TODO: Do we need a separate methods for DML/DDL that do not return the resultset? or extend a resultset?
+    //TODO: same methods for Statement.
+
+    ///////////////// Query monitoring and management.
+    /**
+     * Returns SQL views.
+     */
+    Object views(); //TODO: To be described.
+    //TODO: Add view for runnin queries.
+
+    /**
+     * Return info of the queries. //TODO: "running on the node locally"? or "started on the node"? or both?
+     *
+     * @return Running queries infos.
+     */
+    Collection<Object> runningQueries(); //TODO: Is it needed here or to be moved into the Views facade?
+
+    /**
+     * Kills query by its' id.
+     *
+     * @param queryID Query id.
+     */
+    void killQuery(UUID queryID);
+
+
+    ////////////// Statistics management.
+    Collection<Object> tableStatistics(String table); //TODO: Local or global? Ready or in-progress? TBD.
+
+    CompletableFuture<Void> gatherStatistics(String table, Object statisticsConfiguration);
+    //TODO: Creates new statistics in addition, or drop old and replaces with new?
+    //TODO: Should the existed one be refreshed?
+
+    CompletableFuture<Void> refreshStatistics(String table, @Nullable String... optionalStatisticName);
+
+    void dropStatistics(String table, @Nullable String... optionalStatisticName);
+
+    void refreshLocalStatistics(String table, @Nullable String... optionalStatisticName); //TODO: Actually, drops local statistics to be automatically refreshed.
+
+
+    //////////////////// DDL
+
+    //TODO: Do we expect any SQL DDL pragrammatical API here? Why we have tables().create(), but not here?
+    //TODO: alterTable()?
+}
+
diff --git a/modules/api/src/main/java/org/apache/ignite/app/Ignite.java b/modules/api/src/main/java/org/apache/ignite/query/sql/SQLException.java
similarity index 60%
copy from modules/api/src/main/java/org/apache/ignite/app/Ignite.java
copy to modules/api/src/main/java/org/apache/ignite/query/sql/SQLException.java
index 87e585a..3e33d6e 100644
--- a/modules/api/src/main/java/org/apache/ignite/app/Ignite.java
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/SQLException.java
@@ -15,26 +15,28 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.app;
+package org.apache.ignite.query.sql;
 
-import org.apache.ignite.table.manager.IgniteTables;
-import org.apache.ignite.tx.IgniteTransactions;
+import org.apache.ignite.lang.IgniteException;
+import org.jetbrains.annotations.Nullable;
 
 /**
- * Ignite node interface. Main entry-point for all Ignite APIs.
+ * SQL exception base class.
  */
-public interface Ignite extends AutoCloseable {
-    /**
-     * Gets an object for manipulate Ignite tables.
-     *
-     * @return Ignite tables.
-     */
-    IgniteTables tables();
+//TODO: Do we want to use this instead of java.sql.SQLException ?
+public class SQLException extends IgniteException {
+    public SQLException() {
+    }
 
-    /**
-     * Returns a transaction facade.
-     *
-     * @return Ignite transactions.
-     */
-    IgniteTransactions transactions();
+    public SQLException(String msg) {
+        super(msg);
+    }
+
+    public SQLException(Throwable cause) {
+        super(cause);
+    }
+
+    public SQLException(String msg, @Nullable Throwable cause) {
+        super(msg, cause);
+    }
 }
diff --git a/modules/api/src/main/java/org/apache/ignite/query/sql/SqlColumnMeta.java b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlColumnMeta.java
new file mode 100644
index 0000000..856c82f
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlColumnMeta.java
@@ -0,0 +1,60 @@
+/*
+ * 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.query.sql;
+
+import org.apache.ignite.schema.ColumnType;
+
+/**
+ * Column metadata.
+ */
+public interface SqlColumnMeta {
+    /**
+     * Return column name in resultset.
+     *
+     * Note: If row column doess not represents any table column, then generated name will be used.
+     *
+     * @return Column name.
+     */
+    String name();
+    //TODO: do we expect a CanonicalName here?
+    //TODO: do we want a Table name for real column? Is Calcite supports this?
+
+    /**
+     * Returns column type.
+     *
+     * @return Column type.
+     */
+    ColumnType type();
+    //TODO: do ever we want to expose ColumnType (NativeType) here? Is it useful or drop this?
+
+    /**
+     * Returns column value type.
+     *
+     * @return Value type.
+     */
+    Class<?> valueClass();
+    //TODO: this maybe more useful in contraty to the previous one.
+
+    /**
+     * Row column nullability.
+     *
+     * @return {@code true} if column is nullable, {@code false} otherwise.
+     */
+    boolean nullable();
+    //TODO: AFAIK, Calcite can derive column type for us.
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/app/Ignite.java b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSet.java
similarity index 63%
copy from modules/api/src/main/java/org/apache/ignite/app/Ignite.java
copy to modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSet.java
index 87e585a..174c914 100644
--- a/modules/api/src/main/java/org/apache/ignite/app/Ignite.java
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSet.java
@@ -15,26 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.app;
-
-import org.apache.ignite.table.manager.IgniteTables;
-import org.apache.ignite.tx.IgniteTransactions;
+package org.apache.ignite.query.sql;
 
 /**
- * Ignite node interface. Main entry-point for all Ignite APIs.
+ * SQL result set provides methods to access SQL query resul represented as collection of {@link SqlRow}.
+ *
+ * All the rows in result set have the same structure described in {@link SqlResultSetMeta}.
+ * ResultSet must be closed after usage to free resources.
  */
-public interface Ignite extends AutoCloseable {
-    /**
-     * Gets an object for manipulate Ignite tables.
-     *
-     * @return Ignite tables.
-     */
-    IgniteTables tables();
-
+public interface SqlResultSet extends Iterable<SqlRow>, AutoCloseable {
     /**
-     * Returns a transaction facade.
+     * Returns metadata for the results.
      *
-     * @return Ignite transactions.
+     * @return ResultSet metadata.
      */
-    IgniteTransactions transactions();
+    SqlResultSetMeta metadata();
 }
diff --git a/modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSetMeta.java b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSetMeta.java
new file mode 100644
index 0000000..38c4a63
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSetMeta.java
@@ -0,0 +1,63 @@
+/*
+ * 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.query.sql;
+
+import java.util.List;
+
+/**
+ * ResultSet metadata.
+ */
+public interface SqlResultSetMeta {
+    /**
+     * Returns number of column that every row in a ResulSet contains.
+     *
+     * @return Number of columns.
+     */
+    int columnsCount();
+
+    /**
+     * Returns metadata with description for every column in resultset.
+     *
+     * @return Columns metadata.
+     */
+    List<SqlColumnMeta> columns();
+
+    /**
+     * Returns metadata for the requested column.
+     *
+     * @param columnId Column Id.
+     * @return Column metadata.
+     */
+    SqlColumnMeta column(int columnId);
+
+    /**
+     * Returns metadata for the requested column.
+     *
+     * @param columnName Column name.
+     * @return Column metadata.
+     */
+    SqlColumnMeta column(String columnName);
+
+    /**
+     * Returns column id in ResultSet by column name.
+     *
+     * @param columnName Columns name which id is resoliving.
+     * @return Column Id for requested column.
+     */
+    int indexOf(String columnName);
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/app/Ignite.java b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlRow.java
similarity index 61%
copy from modules/api/src/main/java/org/apache/ignite/app/Ignite.java
copy to modules/api/src/main/java/org/apache/ignite/query/sql/SqlRow.java
index 87e585a..1938186 100644
--- a/modules/api/src/main/java/org/apache/ignite/app/Ignite.java
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlRow.java
@@ -15,26 +15,16 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.app;
+package org.apache.ignite.query.sql;
 
-import org.apache.ignite.table.manager.IgniteTables;
-import org.apache.ignite.tx.IgniteTransactions;
+import org.apache.ignite.table.Tuple;
 
 /**
- * Ignite node interface. Main entry-point for all Ignite APIs.
+ * SQL row provides methods to access row data by column name or id.
+ *
+ * Column description can be retrived from {@link SqlResultSet#metadata()}.
+ * @see SqlColumnMeta
  */
-public interface Ignite extends AutoCloseable {
-    /**
-     * Gets an object for manipulate Ignite tables.
-     *
-     * @return Ignite tables.
-     */
-    IgniteTables tables();
-
-    /**
-     * Returns a transaction facade.
-     *
-     * @return Ignite transactions.
-     */
-    IgniteTransactions transactions();
+public interface SqlRow extends Tuple {
+//TODO: We extends Tuple here just for short. Do we need smth else?
 }
diff --git a/modules/api/src/main/java/org/apache/ignite/app/Ignite.java b/modules/api/src/main/java/org/apache/ignite/query/sql/reactive/ReactiveSqlResultSet.java
similarity index 55%
copy from modules/api/src/main/java/org/apache/ignite/app/Ignite.java
copy to modules/api/src/main/java/org/apache/ignite/query/sql/reactive/ReactiveSqlResultSet.java
index 87e585a..fbb66e9 100644
--- a/modules/api/src/main/java/org/apache/ignite/app/Ignite.java
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/reactive/ReactiveSqlResultSet.java
@@ -15,26 +15,26 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.app;
+package org.apache.ignite.query.sql.reactive;
 
-import org.apache.ignite.table.manager.IgniteTables;
-import org.apache.ignite.tx.IgniteTransactions;
+import java.sql.ResultSetMetaData;
+import java.util.concurrent.Flow;
+import org.apache.ignite.query.sql.SqlRow;
 
 /**
- * Ignite node interface. Main entry-point for all Ignite APIs.
+ * Reactive resultset provides methods to subscribe to the query results in reactive way.
+ *
+ * Note: It implies to be used with the reactive framework such as Reactor or R2DBC.
+ *
+ * @see reactor.core.publisher.Flux
+ * @see r2dbc
  */
-public interface Ignite extends AutoCloseable {
-    /**
-     * Gets an object for manipulate Ignite tables.
-     *
-     * @return Ignite tables.
-     */
-    IgniteTables tables();
-
+// TODO: add links to frameworks, code examples. See SqlTest.SqlRowSubsvriber.
+public interface ReactiveSqlResultSet extends Flow.Publisher<SqlRow> {
     /**
-     * Returns a transaction facade.
+     * Return publisher for the ResulSets' metadata.
      *
-     * @return Ignite transactions.
+     * @return Metadata publisher.
      */
-    IgniteTransactions transactions();
+    Flow.Publisher<ResultSetMetaData> metadata();
 }
diff --git a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
index 54a93b9..db88368 100644
--- a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
+++ b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.app;
 import org.apache.ignite.app.Ignite;
 import org.apache.ignite.internal.vault.VaultManager;
 import org.apache.ignite.internal.processors.query.calcite.SqlQueryProcessor;
+import org.apache.ignite.query.sql.IgniteSql;
 import org.apache.ignite.table.manager.IgniteTables;
 import org.apache.ignite.tx.IgniteTransactions;
 
@@ -30,9 +31,10 @@ public class IgniteImpl implements Ignite {
     /** Distributed table manager. */
     private final IgniteTables distributedTableManager;
 
-    /** Vault manager */
+    /** Vault manager. */
     private final VaultManager vaultManager;
 
+    /** Query manager. */
     private final SqlQueryProcessor qryEngine;
 
     /**
@@ -44,6 +46,8 @@ public class IgniteImpl implements Ignite {
         this.distributedTableManager = tableManager;
         this.vaultManager = vaultManager;
         this.qryEngine = qryEngine;
+
+       // qryManager = new IgniteQueriesImpl(qryEngine);
     }
 
     /** {@inheritDoc} */
@@ -51,6 +55,7 @@ public class IgniteImpl implements Ignite {
         return distributedTableManager;
     }
 
+    // TODO: To be replaced with IgniteImpl#sql().
     public SqlQueryProcessor queryEngine() {
         return qryEngine;
     }
@@ -61,6 +66,11 @@ public class IgniteImpl implements Ignite {
     }
 
     /** {@inheritDoc} */
+    @Override public IgniteSql sql() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
     @Override public void close() throws Exception {
         vaultManager.close();
     }
diff --git a/modules/sql/src/test/java/SqlTest.java b/modules/sql/src/test/java/SqlTest.java
new file mode 100644
index 0000000..c49721a
--- /dev/null
+++ b/modules/sql/src/test/java/SqlTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.
+ */
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Flow;
+import java.util.function.Consumer;
+import org.apache.ignite.query.sql.IgniteSql;
+import org.apache.ignite.query.sql.SqlResultSet;
+import org.apache.ignite.query.sql.SqlResultSetMeta;
+import org.apache.ignite.query.sql.SqlRow;
+import org.apache.ignite.query.sql.reactive.ReactiveSqlResultSet;
+import org.apache.ignite.schema.ColumnType;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@Disabled // TODO: create a ticket to fix this.
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+public class SqlTest {
+    @Mock
+    IgniteSql queryMgr;
+
+    @BeforeEach
+    void setUp() {
+        initMock();
+    }
+
+    @Test
+    public void testSynchronousSql() {
+        SqlResultSet rs = queryMgr.execute("SELECT id, val FROM table WHERE id < {} AND val LIKE {};", 10, "str%");
+
+        for (SqlRow r : rs) {
+            assertTrue(10 > r.longValue("id"));
+            assertTrue((r.stringValue("val")).startsWith("str"));
+        }
+    }
+
+    @Test
+    public void testAsyncSql() {
+        queryMgr.executeAsync("SELECT id, val FROM table WHERE id == {};", 10)
+            .thenCompose(rs -> {
+                String str = rs.iterator().next().stringValue("val");
+
+                return queryMgr.executeAsync("SELECT val FROM table where val LIKE {};", str);
+            })
+            .join();
+    }
+
+    @Test
+    public void testReactiveSql() {
+        SqlRowSubscriber subscriber = new SqlRowSubscriber(row -> {
+            assertTrue(10 > row.longValue("id"));
+            assertTrue(row.stringValue("val").startsWith("str"));
+        });
+
+        queryMgr.executeReactive("SELECT id, val FROM table WHERE id < {} AND val LIKE {};", 10, "str%")
+            .subscribe(subscriber);
+
+        subscriber.join();
+    }
+
+    @Disabled
+    @Test
+    public void testMetadata() {
+        SqlResultSet rs = queryMgr.execute("SELECT id, val FROM table WHERE id < {} AND val LIKE {}; ", 10, "str%");
+
+        SqlRow row = rs.iterator().next();
+
+        SqlResultSetMeta meta = rs.metadata();
+
+        assertEquals(rs.metadata().columnsCount(), row.columnCount());
+
+        assertEquals(0, meta.indexOf("id"));
+        assertEquals(1, meta.indexOf("val"));
+
+        assertEquals("id", meta.column(0).name());
+        assertEquals("val", meta.column(1).name());
+
+        assertEquals(ColumnType.INT64, meta.column(0).type());
+        assertEquals(ColumnType.string(), meta.column(1).type());
+
+        assertFalse(meta.column(0).nullable());
+        assertTrue(meta.column(1).nullable());
+    }
+
+    private void initMock() {
+        Mockito.when(queryMgr.execute(Mockito.eq("SELECT id, val FROM table WHERE id < {} AND val LIKE {};"), Mockito.any())).
+            thenAnswer(ans -> Mockito.when(Mockito.mock(SqlResultSet.class).iterator())
+                .thenReturn(List.of(
+                    new TestRow().set("id", 1L).set("val", "string 1").build(),
+                    new TestRow().set("id", 2L).set("val", "string 2").build(),
+                    new TestRow().set("id", 5L).set("val", "string 3").build()
+                ).iterator()).getMock());
+
+        Mockito.when(queryMgr.executeAsync(Mockito.eq("SELECT id, val FROM table WHERE id == {};"), Mockito.any()))
+            .thenAnswer(ans -> {
+                Object mock = Mockito.when(Mockito.mock(SqlResultSet.class).iterator())
+                    .thenReturn(List.of(new TestRow().set("id", 1L).set("val", "string 1").build()).iterator())
+                    .getMock();
+
+                return CompletableFuture.completedFuture(mock);
+            });
+
+        Mockito.when(queryMgr.executeAsync(Mockito.eq("SELECT val FROM table where val LIKE {};"), Mockito.any()))
+            .thenAnswer(ans -> {
+                Object mock = Mockito.when(Mockito.mock(SqlResultSet.class).iterator())
+                    .thenReturn(List.of(new TestRow().set("id", 10L).set("val", "string 10").build()).iterator())
+                    .getMock();
+
+                return CompletableFuture.completedFuture(mock);
+            });
+
+        Mockito.when(queryMgr.executeReactive(Mockito.startsWith("SELECT id, val FROM table WHERE id < {} AND val LIKE {};"), Mockito.any()))
+            .thenAnswer(invocation -> {
+                ReactiveSqlResultSet mock = Mockito.mock(ReactiveSqlResultSet.class);
+
+                Mockito.doAnswer(ans -> {
+                    Flow.Subscriber subscrber = ans.getArgument(0);
+
+                    subscrber.onSubscribe(Mockito.mock(Flow.Subscription.class));
+
+                    List.of(
+                        new TestRow().set("id", 1L).set("val", "string 1").build(),
+                        new TestRow().set("id", 2L).set("val", "string 2").build(),
+                        new TestRow().set("id", 5L).set("val", "string 3").build()
+                    ).forEach(i -> subscrber.onNext(i));
+
+                    subscrber.onComplete();
+
+                    return ans;
+                }).when(mock).subscribe(Mockito.any(Flow.Subscriber.class));
+
+                return mock;
+            });
+    }
+
+    /**
+     * Dummy subsctiber for test purposes.
+     */
+     static class SqlRowSubscriber extends CompletableFuture implements Flow.Subscriber<SqlRow> {
+        private Consumer<SqlRow> rowConsumer;
+
+        SqlRowSubscriber(Consumer<SqlRow> rowConsumer) {
+            this.rowConsumer = rowConsumer;
+        }
+
+        @Override public void onSubscribe(Flow.Subscription subscription) {
+            whenCompleteAsync((res, th) -> {
+                if (th != null)
+                    subscription.cancel();
+            });
+
+            subscription.request(Long.MAX_VALUE); // Unbounded.
+        }
+
+        @Override public void onNext(SqlRow row) {
+            rowConsumer.accept(row);
+        }
+
+        @Override public void onError(Throwable throwable) {
+            completeExceptionally(throwable);
+        }
+
+        @Override public void onComplete() {
+            complete(null);
+        }
+    }
+}
diff --git a/modules/sql/src/test/java/TestRow.java b/modules/sql/src/test/java/TestRow.java
new file mode 100644
index 0000000..2105be9
--- /dev/null
+++ b/modules/sql/src/test/java/TestRow.java
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.binary.BinaryObjects;
+import org.apache.ignite.query.sql.SqlRow;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Dummy table storage implementation.
+ */
+public class TestRow implements SqlRow {
+    /** Columns values. */
+    private final Map<String, Object> map = new HashMap<>();
+
+    public TestRow set(String columnName, Object value) {
+        map.put(columnName, value);
+
+        return this;
+    }
+
+    public SqlRow build() {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T valueOrDefault(String columnName, T def) {
+        return (T)map.getOrDefault(columnName, def);
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T value(String columnName) {
+        return (T)map.get(columnName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T value(int columnIndex) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@inheritDoc} */
+    @Override public int columnCount() {
+        return map.size();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String columnName(int columnIndex) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@inheritDoc} */
+    @Override public Integer columnIndex(String columnName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@inheritDoc} */
+    @Override public BinaryObject binaryObjectValue(String columnName) {
+        byte[] data = value(columnName);
+
+        return BinaryObjects.wrap(data);
+    }
+
+    /** {@inheritDoc} */
+    @Override public BinaryObject binaryObjectValue(int columnIndex) {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte byteValue(String columnName) {
+        return value(columnName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte byteValue(int columnIndex) {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public short shortValue(String columnName) {
+        return value(columnName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public short shortValue(int columnIndex) {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int intValue(String columnName) {
+        return value(columnName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int intValue(int columnIndex) {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long longValue(String columnName) {
+        return value(columnName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long longValue(int columnIndex) {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float floatValue(String columnName) {
+        return value(columnName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public float floatValue(int columnIndex) {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public double doubleValue(String columnName) {
+        return value(columnName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public double doubleValue(int columnIndex) {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String stringValue(String columnName) {
+        return value(columnName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public String stringValue(int columnIndex) {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public UUID uuidValue(String columnName) {
+        return value(columnName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public UUID uuidValue(int columnIndex) {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public BitSet bitmaskValue(String columnName) {
+        return value(columnName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public BitSet bitmaskValue(int columnIndex) {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @NotNull @Override public Iterator<Object> iterator() {
+        throw new UnsupportedOperationException();
+    }
+}

[ignite-3] 05/05: Add transactions. Fix tests.

Posted by am...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 8612fe86381e1e506ef4e39680c862f5e8a0036a
Author: Andrew Mashenkov <an...@gmail.com>
AuthorDate: Mon Aug 2 15:05:27 2021 +0300

    Add transactions.
    Fix tests.
---
 .../org/apache/ignite/query/sql/IgniteSql.java     | 67 ++--------------
 .../org/apache/ignite/query/sql/SqlColumnMeta.java |  5 +-
 .../org/apache/ignite/query/sql/SqlResultSet.java  |  5 ++
 .../query/sql/{IgniteSql.java => SqlSession.java}  | 42 ++++-------
 modules/sql/src/test/java/SqlTest.java             | 88 ++++++++++++++++------
 5 files changed, 92 insertions(+), 115 deletions(-)

diff --git a/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java b/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java
index e5a1d3a..11c5947 100644
--- a/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java
@@ -18,74 +18,18 @@
 package org.apache.ignite.query.sql;
 
 import java.util.UUID;
-import java.util.concurrent.CompletableFuture;
-import org.apache.ignite.query.sql.reactive.ReactiveSqlResultSet;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 
 /**
  * Ignite SQL query facade.
  */
 // TODO: Do we wand a separate IgniteQuery facade for non-sql (index/scan/full-text) queries?
 public interface IgniteSql {
-    ////////////// Query execution.
     /**
-     * Shortcut method for running a query.
+     * Creates SQL session.
      *
-     * @param sql SQL query template.
-     * @param args Arguments for template (optional).
-     * @return SQL query resultset.
-     * @throws SQLException If failed.
+     * @return Session.
      */
-    SqlResultSet execute(@NotNull String sql, Object... args);
-
-    /**
-     * Shortcut method for running a query in asynchronously.
-     *
-     * @param sql SQL query template.
-     * @param args Arguments for template (optional)
-     * @return Query future.
-     * @throws SQLException If failed.
-     */
-    CompletableFuture<SqlResultSet> executeAsync(String sql, Object... args);
-    //TODO: May fut.cancel() cancels a query? If so, describe behavior in Javadoc.
-    //TODO: Cassandra API offers pagination API here, for manual fetching control. Is their AsyncResultSet ever usefull?
-
-    /**
-     * Shortcut method for running a query in asynchronously.
-     *
-     * @param sql SQL query template.
-     * @param args Arguments for template (optional)
-     * @return Reactive result.
-     * @throws SQLException If failed.
-     */
-    ReactiveSqlResultSet executeReactive(String sql, Object... args);
-
-    /**
-     * Shortcut method for running a non-query statement.
-     *
-     * @param sql SQL statement template.
-     * @param args Agruments for template (optional).
-     * @return Number of updated rows.
-     */
-    int executeNonQuery(@NotNull String sql, @Nullable Object... args);
-    //TODO: useful for bulk DML query, when we don't care of results.
-    //TODO: in contrary, execute() method may return inserted rows IDs that looks useful if AutoIncrement ID column is used.
-
-    //TODO: same methods for Statement.
-
-    /**
-     * Sets query session parameter.
-     *
-     * @param name Parameter name.
-     * @param value Parameter value.
-     */
-    void setParameter(String name, Object value);
-    //TODO: User can set e.g. queryTimeout or force join order or whatever.
-    //TODO: This is similar to SQL "SET" operator which is used in JDBC/ODBC clients for session state manipulation.
-
-
-    //TODO: Move all of this to Session. Maybe facade instance could incapsulate a session implicitely?
+    SqlSession session();
 
     /**
      * Kills query by its' id.
@@ -96,7 +40,7 @@ public interface IgniteSql {
 
     /**
      * Returns statistics facade for table statistics management.
-     *
+     * <p>
      * Table statistics are used by SQL engine for SQL queries planning.
      *
      * @return Statistics facade.
@@ -104,9 +48,10 @@ public interface IgniteSql {
     IgniteTableStatistics statistics();
     // TODO: Do we need this here or move to Table facade?
 
-
     void registerUserFunction(Class type, String... methodNames); //TODO: Get function details from method annotations.
+
     void registerUserFunction(Class type);
+
     void unregistedUserFunction(String functionName);
     //TODO: Custom function registration. Do we need a view and unregister functionality?
 }
diff --git a/modules/api/src/main/java/org/apache/ignite/query/sql/SqlColumnMeta.java b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlColumnMeta.java
index c7250a4..2576936 100644
--- a/modules/api/src/main/java/org/apache/ignite/query/sql/SqlColumnMeta.java
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlColumnMeta.java
@@ -31,16 +31,13 @@ public interface SqlColumnMeta {
      * @return Column name.
      */
     String name();
-    //TODO: do we expect a CanonicalName here?
-    //TODO: do we want a Table name for real column? Is Calcite supports this?
 
     /**
      * Returns column type.
      *
      * @return Column type.
      */
-    ColumnType type();
-    //TODO: do ever we want to expose ColumnType (NativeType) here? Is it useful or drop this?
+    ColumnType columnType();
 
     /**
      * Returns column value type.
diff --git a/modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSet.java b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSet.java
index 2bbadcf..ea8003d 100644
--- a/modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSet.java
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlResultSet.java
@@ -33,5 +33,10 @@ public interface SqlResultSet extends Iterable<SqlRow>, AutoCloseable {
      */
     SqlResultSetMeta metadata();
 
+    /**
+     * Returns query unique id.
+     *
+     * @return Query id.
+     */
     UUID queryId();
 }
diff --git a/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlSession.java
similarity index 73%
copy from modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java
copy to modules/api/src/main/java/org/apache/ignite/query/sql/SqlSession.java
index e5a1d3a..d9795c7 100644
--- a/modules/api/src/main/java/org/apache/ignite/query/sql/IgniteSql.java
+++ b/modules/api/src/main/java/org/apache/ignite/query/sql/SqlSession.java
@@ -17,18 +17,17 @@
 
 package org.apache.ignite.query.sql;
 
-import java.util.UUID;
+import java.sql.PreparedStatement;
 import java.util.concurrent.CompletableFuture;
 import org.apache.ignite.query.sql.reactive.ReactiveSqlResultSet;
+import org.apache.ignite.tx.Transaction;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 /**
- * Ignite SQL query facade.
+ * SQL session.
  */
-// TODO: Do we wand a separate IgniteQuery facade for non-sql (index/scan/full-text) queries?
-public interface IgniteSql {
-    ////////////// Query execution.
+public interface SqlSession {
     /**
      * Shortcut method for running a query.
      *
@@ -72,42 +71,29 @@ public interface IgniteSql {
     //TODO: useful for bulk DML query, when we don't care of results.
     //TODO: in contrary, execute() method may return inserted rows IDs that looks useful if AutoIncrement ID column is used.
 
-    //TODO: same methods for Statement.
+    PreparedStatement preparedStatement(@NotNull String sql);
 
     /**
      * Sets query session parameter.
      *
      * @param name Parameter name.
      * @param value Parameter value.
+     * @return {@code this} for chaining.
      */
-    void setParameter(String name, Object value);
+    SqlSession setParameter(@NotNull String name, Object value);
     //TODO: User can set e.g. queryTimeout or force join order or whatever.
     //TODO: This is similar to SQL "SET" operator which is used in JDBC/ODBC clients for session state manipulation.
 
 
-    //TODO: Move all of this to Session. Maybe facade instance could incapsulate a session implicitely?
+    SqlSession withTransaction(Transaction tx);
+    //TODO: What happens with session if TX will commited/rolledback? Tx link can prevent garbage from being collected by GC.
+    //TODO: Can it be shared?
+    //TODO: Move to PreparedStatement/SqlQuery level?
 
     /**
-     * Kills query by its' id.
+     * Returns current transaction.
      *
-     * @param queryID Query id.
+     * @return Current transaction or null if a table is not enlisted in a transaction.
      */
-    void killQuery(UUID queryID);
-
-    /**
-     * Returns statistics facade for table statistics management.
-     *
-     * Table statistics are used by SQL engine for SQL queries planning.
-     *
-     * @return Statistics facade.
-     */
-    IgniteTableStatistics statistics();
-    // TODO: Do we need this here or move to Table facade?
-
-
-    void registerUserFunction(Class type, String... methodNames); //TODO: Get function details from method annotations.
-    void registerUserFunction(Class type);
-    void unregistedUserFunction(String functionName);
-    //TODO: Custom function registration. Do we need a view and unregister functionality?
+    @Nullable Transaction transaction();
 }
-
diff --git a/modules/sql/src/test/java/SqlTest.java b/modules/sql/src/test/java/SqlTest.java
index c49721a..503b1d8 100644
--- a/modules/sql/src/test/java/SqlTest.java
+++ b/modules/sql/src/test/java/SqlTest.java
@@ -23,8 +23,11 @@ import org.apache.ignite.query.sql.IgniteSql;
 import org.apache.ignite.query.sql.SqlResultSet;
 import org.apache.ignite.query.sql.SqlResultSetMeta;
 import org.apache.ignite.query.sql.SqlRow;
+import org.apache.ignite.query.sql.SqlSession;
 import org.apache.ignite.query.sql.reactive.ReactiveSqlResultSet;
 import org.apache.ignite.schema.ColumnType;
+import org.apache.ignite.tx.IgniteTransactions;
+import org.apache.ignite.tx.Transaction;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
@@ -46,6 +49,12 @@ public class SqlTest {
     @Mock
     IgniteSql queryMgr;
 
+    @Mock
+    private IgniteTransactions igniteTx;
+
+    @Mock
+    private Transaction tx;
+
     @BeforeEach
     void setUp() {
         initMock();
@@ -53,23 +62,35 @@ public class SqlTest {
 
     @Test
     public void testSynchronousSql() {
-        SqlResultSet rs = queryMgr.execute("SELECT id, val FROM table WHERE id < {} AND val LIKE {};", 10, "str%");
+        igniteTx.runInTransaction(tx -> {
+            SqlSession sess = queryMgr.session().withTransaction(tx);
 
-        for (SqlRow r : rs) {
-            assertTrue(10 > r.longValue("id"));
-            assertTrue((r.stringValue("val")).startsWith("str"));
-        }
+            SqlResultSet rs = sess.execute("SELECT id, val FROM table WHERE id < {} AND val LIKE {};", 10, "str%");
+
+            for (SqlRow r : rs) {
+                assertTrue(10 > r.longValue("id"));
+                assertTrue((r.stringValue("val")).startsWith("str"));
+            }
+
+            tx.commit();
+        });
+
+        Mockito.verify(tx).commit();
     }
 
     @Test
     public void testAsyncSql() {
-        queryMgr.executeAsync("SELECT id, val FROM table WHERE id == {};", 10)
-            .thenCompose(rs -> {
-                String str = rs.iterator().next().stringValue("val");
+        igniteTx.beginAsync().thenApply(tx -> queryMgr.session().withTransaction(tx))
+            .thenCompose(sess -> sess.executeAsync("SELECT id, val FROM table WHERE id == {};", 10)
+                .thenCompose(rs -> {
+                    String str = rs.iterator().next().stringValue("val");
 
-                return queryMgr.executeAsync("SELECT val FROM table where val LIKE {};", str);
-            })
-            .join();
+                    return sess.executeAsync("SELECT val FROM table where val LIKE {};", str);
+                })
+                .thenApply(ignore -> sess.transaction())
+            ).thenAccept(Transaction::commitAsync);
+
+        Mockito.verify(tx).commitAsync();
     }
 
     @Test
@@ -79,16 +100,22 @@ public class SqlTest {
             assertTrue(row.stringValue("val").startsWith("str"));
         });
 
-        queryMgr.executeReactive("SELECT id, val FROM table WHERE id < {} AND val LIKE {};", 10, "str%")
-            .subscribe(subscriber);
+        igniteTx.beginAsync().thenApply(tx -> queryMgr.session().withTransaction(tx))
+            .thenApply(session -> {
+                session.executeReactive("SELECT id, val FROM table WHERE id < {} AND val LIKE {};", 10, "str%")
+                    .subscribe(subscriber);
+
+                return session.transaction();
+            })
+            .thenApply(Transaction::commitAsync);
 
-        subscriber.join();
+        Mockito.verify(tx).commitAsync();
     }
 
     @Disabled
     @Test
     public void testMetadata() {
-        SqlResultSet rs = queryMgr.execute("SELECT id, val FROM table WHERE id < {} AND val LIKE {}; ", 10, "str%");
+        SqlResultSet rs = queryMgr.session().execute("SELECT id, val FROM table WHERE id < {} AND val LIKE {}; ", 10, "str%");
 
         SqlRow row = rs.iterator().next();
 
@@ -102,15 +129,22 @@ public class SqlTest {
         assertEquals("id", meta.column(0).name());
         assertEquals("val", meta.column(1).name());
 
-        assertEquals(ColumnType.INT64, meta.column(0).type());
-        assertEquals(ColumnType.string(), meta.column(1).type());
+        assertEquals(ColumnType.INT64, meta.column(0).columnType());
+        assertEquals(ColumnType.string(), meta.column(1).columnType());
 
         assertFalse(meta.column(0).nullable());
         assertTrue(meta.column(1).nullable());
     }
 
     private void initMock() {
-        Mockito.when(queryMgr.execute(Mockito.eq("SELECT id, val FROM table WHERE id < {} AND val LIKE {};"), Mockito.any())).
+        SqlSession session = Mockito.mock(SqlSession.class);
+
+        Mockito.when(queryMgr.session()).thenReturn(session);
+
+        Mockito.when(session.withTransaction(tx)).thenReturn(session);
+        Mockito.when(session.transaction()).thenReturn(tx);
+
+        Mockito.when(session.execute(Mockito.eq("SELECT id, val FROM table WHERE id < {} AND val LIKE {};"), Mockito.any())).
             thenAnswer(ans -> Mockito.when(Mockito.mock(SqlResultSet.class).iterator())
                 .thenReturn(List.of(
                     new TestRow().set("id", 1L).set("val", "string 1").build(),
@@ -118,7 +152,7 @@ public class SqlTest {
                     new TestRow().set("id", 5L).set("val", "string 3").build()
                 ).iterator()).getMock());
 
-        Mockito.when(queryMgr.executeAsync(Mockito.eq("SELECT id, val FROM table WHERE id == {};"), Mockito.any()))
+        Mockito.when(session.executeAsync(Mockito.eq("SELECT id, val FROM table WHERE id == {};"), Mockito.any()))
             .thenAnswer(ans -> {
                 Object mock = Mockito.when(Mockito.mock(SqlResultSet.class).iterator())
                     .thenReturn(List.of(new TestRow().set("id", 1L).set("val", "string 1").build()).iterator())
@@ -127,7 +161,7 @@ public class SqlTest {
                 return CompletableFuture.completedFuture(mock);
             });
 
-        Mockito.when(queryMgr.executeAsync(Mockito.eq("SELECT val FROM table where val LIKE {};"), Mockito.any()))
+        Mockito.when(session.executeAsync(Mockito.eq("SELECT val FROM table where val LIKE {};"), Mockito.any()))
             .thenAnswer(ans -> {
                 Object mock = Mockito.when(Mockito.mock(SqlResultSet.class).iterator())
                     .thenReturn(List.of(new TestRow().set("id", 10L).set("val", "string 10").build()).iterator())
@@ -136,7 +170,7 @@ public class SqlTest {
                 return CompletableFuture.completedFuture(mock);
             });
 
-        Mockito.when(queryMgr.executeReactive(Mockito.startsWith("SELECT id, val FROM table WHERE id < {} AND val LIKE {};"), Mockito.any()))
+        Mockito.when(session.executeReactive(Mockito.startsWith("SELECT id, val FROM table WHERE id < {} AND val LIKE {};"), Mockito.any()))
             .thenAnswer(invocation -> {
                 ReactiveSqlResultSet mock = Mockito.mock(ReactiveSqlResultSet.class);
 
@@ -158,12 +192,22 @@ public class SqlTest {
 
                 return mock;
             });
+
+        Mockito.doAnswer(invocation -> {
+            Consumer<Transaction> argument = invocation.getArgument(0);
+
+            argument.accept(tx);
+
+            return null;
+        }).when(igniteTx).runInTransaction(Mockito.any());
+
+        Mockito.when(igniteTx.beginAsync()).thenReturn(CompletableFuture.completedFuture(tx));
     }
 
     /**
      * Dummy subsctiber for test purposes.
      */
-     static class SqlRowSubscriber extends CompletableFuture implements Flow.Subscriber<SqlRow> {
+    static class SqlRowSubscriber extends CompletableFuture implements Flow.Subscriber<SqlRow> {
         private Consumer<SqlRow> rowConsumer;
 
         SqlRowSubscriber(Consumer<SqlRow> rowConsumer) {