You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ak...@apache.org on 2015/11/02 17:36:56 UTC

[13/33] ignite git commit: IGNITE-1647: Implemented SQL fields query.

IGNITE-1647: Implemented SQL fields query.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/667c2e65
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/667c2e65
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/667c2e65

Branch: refs/heads/ignite-1753-1282
Commit: 667c2e65de65cf6486b7ef56bb03c85b02ebee66
Parents: 09339de
Author: isapego <is...@gridgain.com>
Authored: Fri Oct 30 12:20:54 2015 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
Committed: Fri Oct 30 12:20:54 2015 +0300

----------------------------------------------------------------------
 .../cpp/core-test/src/cache_query_test.cpp      | 214 ++++++++++++++++++-
 modules/platforms/cpp/core/include/Makefile.am  |   4 +
 .../cpp/core/include/ignite/cache/cache.h       |  33 +++
 .../cpp/core/include/ignite/cache/query/query.h |   1 +
 .../include/ignite/cache/query/query_cursor.h   |  11 +-
 .../ignite/cache/query/query_fields_cursor.h    | 153 +++++++++++++
 .../ignite/cache/query/query_fields_row.h       | 154 +++++++++++++
 .../core/include/ignite/cache/query/query_sql.h |  76 +++----
 .../ignite/cache/query/query_sql_fields.h       | 210 ++++++++++++++++++
 .../core/include/ignite/impl/cache/cache_impl.h |  10 +
 .../impl/cache/query/query_fields_row_impl.h    | 174 +++++++++++++++
 .../ignite/impl/cache/query/query_impl.h        |  10 +
 .../platforms/cpp/core/project/vs/core.vcxproj  |   4 +
 .../cpp/core/project/vs/core.vcxproj.filters    |  12 ++
 .../cpp/core/src/impl/cache/cache_impl.cpp      |   5 +
 .../core/src/impl/cache/query/query_impl.cpp    |  39 +++-
 16 files changed, 1048 insertions(+), 62 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core-test/src/cache_query_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core-test/src/cache_query_test.cpp b/modules/platforms/cpp/core-test/src/cache_query_test.cpp
index 1605d74..8625fa1 100644
--- a/modules/platforms/cpp/core-test/src/cache_query_test.cpp
+++ b/modules/platforms/cpp/core-test/src/cache_query_test.cpp
@@ -28,6 +28,7 @@
 #include "ignite/cache/query/query_cursor.h"
 #include "ignite/cache/query/query_sql.h"
 #include "ignite/cache/query/query_text.h"
+#include "ignite/cache/query/query_sql_fields.h"
 #include "ignite/ignite.h"
 #include "ignite/ignition.h"
 
@@ -58,7 +59,7 @@ public:
      * @param name Name.
      * @param age Age.
      */
-    QueryPerson(std::string name, int age) : name(CopyChars(name.c_str())), age(age)
+    QueryPerson(const std::string& name, int age) : name(CopyChars(name.c_str())), age(age)
     {
         // No-op.
     }
@@ -230,7 +231,8 @@ struct CacheQueryTestSuiteFixture {
  *
  * @param cur Cursor.
  */
-void CheckHasNextFail(QueryCursor<int, QueryPerson>& cur)
+template<typename Cursor>
+void CheckHasNextFail(Cursor& cur)
 {
     try
     {
@@ -249,7 +251,8 @@ void CheckHasNextFail(QueryCursor<int, QueryPerson>& cur)
  *
  * @param cur Cursor.
  */
-void CheckGetNextFail(QueryCursor<int, QueryPerson>& cur)
+template<typename Cursor>
+void CheckGetNextFail(Cursor& cur)
 {
     try
     {
@@ -268,7 +271,8 @@ void CheckGetNextFail(QueryCursor<int, QueryPerson>& cur)
  *
  * @param cur Cursor.
  */
-void CheckGetAllFail(QueryCursor<int, QueryPerson>& cur)
+template<typename Cursor>
+void CheckGetAllFail(Cursor& cur)
 {
     try 
     {
@@ -298,11 +302,24 @@ void CheckEmpty(QueryCursor<int, QueryPerson>& cur)
 }
 
 /**
+* Check empty result through iteration.
+*
+* @param cur Cursor.
+*/
+void CheckEmpty(QueryFieldsCursor& cur)
+{
+    BOOST_REQUIRE(!cur.HasNext());
+
+    CheckGetNextFail(cur);
+}
+
+/**
  * Check empty result through GetAll().
  *
  * @param cur Cursor.
  */
-void CheckEmptyGetAll(QueryCursor<int, QueryPerson>& cur)
+template<typename Cursor>
+void CheckEmptyGetAll(Cursor& cur)
 {
     std::vector<CacheEntry<int, QueryPerson>> res;
 
@@ -322,7 +339,8 @@ void CheckEmptyGetAll(QueryCursor<int, QueryPerson>& cur)
  * @param name1 Name.
  * @param age1 Age.
  */
-void CheckSingle(QueryCursor<int, QueryPerson>& cur, int key, std::string name, int age)
+template<typename Cursor>
+void CheckSingle(Cursor& cur, int key, const std::string& name, int age)
 {
     BOOST_REQUIRE(cur.HasNext());
 
@@ -350,7 +368,8 @@ void CheckSingle(QueryCursor<int, QueryPerson>& cur, int key, std::string name,
  * @param name1 Name.
  * @param age1 Age.
  */
-void CheckSingleGetAll(QueryCursor<int, QueryPerson>& cur, int key, std::string name, int age)
+template<typename Cursor>
+void CheckSingleGetAll(Cursor& cur, int key, const std::string& name, int age)
 {
     std::vector<CacheEntry<int, QueryPerson>> res;
 
@@ -382,8 +401,9 @@ void CheckSingleGetAll(QueryCursor<int, QueryPerson>& cur, int key, std::string
  * @param name2 Name 2.
  * @param age2 Age 2.
  */
-void CheckMultiple(QueryCursor<int, QueryPerson>& cur, int key1, std::string name1, 
-    int age1, int key2, std::string name2, int age2)
+template<typename Cursor>
+void CheckMultiple(Cursor& cur, int key1, const std::string& name1, 
+    int age1, int key2, const std::string& name2, int age2)
 {
     for (int i = 0; i < 2; i++)
     {
@@ -426,8 +446,9 @@ void CheckMultiple(QueryCursor<int, QueryPerson>& cur, int key1, std::string nam
  * @param name2 Name 2.
  * @param age2 Age 2.
  */
-void CheckMultipleGetAll(QueryCursor<int, QueryPerson>& cur, int key1, std::string name1, int age1, 
-    int key2, std::string name2, int age2)
+template<typename Cursor>
+void CheckMultipleGetAll(Cursor& cur, int key1, const std::string& name1,
+    int age1, int key2, const std::string& name2, int age2)
 {
     std::vector<CacheEntry<int, QueryPerson>> res;
 
@@ -646,4 +667,175 @@ BOOST_AUTO_TEST_CASE(TestScanQueryPartitioned)
     BOOST_REQUIRE(keys.size() == entryCnt);
 }
 
+/**
+ * Test fields query with single entry.
+ */
+BOOST_AUTO_TEST_CASE(TestFieldsQuerySingle)
+{
+    // Test simple query.
+    Cache<int, QueryPerson> cache = GetCache();
+
+    // Test query with two fields of different type.
+    SqlFieldsQuery qry("select age, name from QueryPerson");
+
+    QueryFieldsCursor cursor = cache.Query(qry);
+    CheckEmpty(cursor);
+    
+    // Test simple query.
+    cache.Put(1, QueryPerson("A1", 10));
+
+    cursor = cache.Query(qry);
+
+    IgniteError error;
+
+    BOOST_REQUIRE(cursor.HasNext(error));
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    QueryFieldsRow row = cursor.GetNext(error);
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    BOOST_REQUIRE(row.HasNext(error));
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    int age = row.GetNext<int>(error);
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    BOOST_REQUIRE(age == 10);
+
+    std::string name = row.GetNext<std::string>(error);
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    BOOST_REQUIRE(name == "A1");
+
+    BOOST_REQUIRE(!row.HasNext());
+
+    CheckEmpty(cursor);
+}
+
+/**
+ * Test fields query with two simultaneously handled rows.
+ */
+BOOST_AUTO_TEST_CASE(TestFieldsQueryTwo)
+{
+    // Test simple query.
+    Cache<int, QueryPerson> cache = GetCache();
+
+    // Test query with two fields of different type.
+    SqlFieldsQuery qry("select age, name from QueryPerson");
+
+    QueryFieldsCursor cursor = cache.Query(qry);
+    CheckEmpty(cursor);
+
+    // Test simple query.
+    cache.Put(1, QueryPerson("A1", 10));
+    cache.Put(2, QueryPerson("A2", 20));
+
+    cursor = cache.Query(qry);
+
+    IgniteError error;
+
+    BOOST_REQUIRE(cursor.HasNext(error));
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    QueryFieldsRow row1 = cursor.GetNext(error);
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    QueryFieldsRow row2 = cursor.GetNext(error);
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    BOOST_REQUIRE(row1.HasNext(error));
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    BOOST_REQUIRE(row2.HasNext(error));
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    int age2 = row2.GetNext<int>(error);
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    BOOST_REQUIRE(age2 == 20);
+
+    int age1 = row1.GetNext<int>(error);
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    BOOST_REQUIRE(age1 == 10);
+
+    std::string name1 = row1.GetNext<std::string>(error);
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    BOOST_REQUIRE(name1 == "A1");
+
+    std::string name2 = row2.GetNext<std::string>(error);
+    BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+    BOOST_REQUIRE(name2 == "A2");
+
+    BOOST_REQUIRE(!row1.HasNext());
+    BOOST_REQUIRE(!row2.HasNext());
+
+    CheckEmpty(cursor);
+}
+
+/**
+ * Test fields query with several entries.
+ */
+BOOST_AUTO_TEST_CASE(TestFieldsQuerySeveral)
+{
+    // Test simple query.
+    Cache<int, QueryPerson> cache = GetCache();
+
+    // Test query with two fields of different type.
+    SqlFieldsQuery qry("select name, age from QueryPerson");
+
+    QueryFieldsCursor cursor = cache.Query(qry);
+    CheckEmpty(cursor);
+
+    int32_t entryCnt = 1000; // Number of entries.
+
+    for (int i = 0; i < entryCnt; i++)
+    {
+        std::stringstream stream;
+
+        stream << "A" << i;
+
+        cache.Put(i, QueryPerson(stream.str(), i * 10));
+    }
+
+    cursor = cache.Query(qry);
+
+    IgniteError error;
+
+    for (int i = 0; i < entryCnt; i++)
+    {
+        std::stringstream stream;
+
+        stream << "A" << i;
+
+        std::string expected_name = stream.str();
+        int expected_age = i * 10;
+
+        BOOST_REQUIRE(cursor.HasNext(error));
+        BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+        QueryFieldsRow row = cursor.GetNext(error);
+        BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+        BOOST_REQUIRE(row.HasNext(error));
+        BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+        std::string name = row.GetNext<std::string>(error);
+        BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+        BOOST_REQUIRE(name == expected_name);
+
+        int age = row.GetNext<int>(error);
+        BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
+
+        BOOST_REQUIRE(age == expected_age);
+
+        BOOST_REQUIRE(!row.HasNext());
+    }
+
+    CheckEmpty(cursor);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/include/Makefile.am
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/Makefile.am b/modules/platforms/cpp/core/include/Makefile.am
index da9d95e..b20e2f7 100644
--- a/modules/platforms/cpp/core/include/Makefile.am
+++ b/modules/platforms/cpp/core/include/Makefile.am
@@ -22,12 +22,16 @@ nobase_include_HEADERS = ignite/cache/cache.h \
                          ignite/cache/cache_peek_mode.h \
                          ignite/cache/query/query_argument.h \
                          ignite/cache/query/query_cursor.h \
+                         ignite/cache/query/query_fields_cursor.h \
+                         ignite/cache/query/query_fields_row.h \
                          ignite/cache/query/query_scan.h \
                          ignite/cache/query/query_sql.h \
+                         ignite/cache/query/query_sql_fields.h \
                          ignite/cache/query/query_text.h \
                          ignite/cache/query/query.h \
                          ignite/impl/cache/cache_impl.h \
                          ignite/impl/cache/query/query_impl.h \
+                         ignite/impl/cache/query/query_fields_row_impl.h \
                          ignite/impl/interop/interop.h \
                          ignite/impl/interop/interop_input_stream.h \
                          ignite/impl/interop/interop_memory.h \

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/include/ignite/cache/cache.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/cache/cache.h b/modules/platforms/cpp/core/include/ignite/cache/cache.h
index 6a51a5f..7581d86 100644
--- a/modules/platforms/cpp/core/include/ignite/cache/cache.h
+++ b/modules/platforms/cpp/core/include/ignite/cache/cache.h
@@ -26,9 +26,11 @@
 
 #include "ignite/cache/cache_peek_mode.h"
 #include "ignite/cache/query/query_cursor.h"
+#include "ignite/cache/query/query_fields_cursor.h"
 #include "ignite/cache/query/query_scan.h"
 #include "ignite/cache/query/query_sql.h"
 #include "ignite/cache/query/query_text.h"
+#include "ignite/cache/query/query_sql_fields.h"
 #include "ignite/impl/cache/cache_impl.h"
 #include "ignite/impl/operations.h"
 #include "ignite/ignite_error.h"
@@ -1143,6 +1145,37 @@ namespace ignite
                 return query::QueryCursor<K, V>(cursorImpl);
             }
 
+            /*
+             * Perform sql fields query.
+             *
+             * @param qry Query.
+             * @return Query cursor.
+             */
+            query::QueryFieldsCursor Query(const query::SqlFieldsQuery& qry)
+            {
+                IgniteError err;
+
+                query::QueryFieldsCursor res = Query(qry, err);
+
+                IgniteError::ThrowIfNeeded(err);
+
+                return res;
+            }
+
+            /*
+             * Perform sql fields query.
+             *
+             * @param qry Query.
+             * @param err Error.
+             * @return Query cursor.
+             */
+            query::QueryFieldsCursor Query(const query::SqlFieldsQuery& qry, IgniteError& err)
+            {
+                impl::cache::query::QueryCursorImpl* cursorImpl = impl.Get()->QuerySqlFields(qry, &err);
+
+                return query::QueryFieldsCursor(cursorImpl);
+            }
+
             /**
              * Check if the instance is valid.
              *

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/include/ignite/cache/query/query.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/cache/query/query.h b/modules/platforms/cpp/core/include/ignite/cache/query/query.h
index f2d19cd..c469e85 100644
--- a/modules/platforms/cpp/core/include/ignite/cache/query/query.h
+++ b/modules/platforms/cpp/core/include/ignite/cache/query/query.h
@@ -22,6 +22,7 @@
 #include "ignite/cache/query/query_cursor.h"
 #include "ignite/cache/query/query_scan.h"
 #include "ignite/cache/query/query_sql.h"
+#include "ignite/cache/query/query_sql_fields.h"
 #include "ignite/cache/query/query_text.h"
 
 #endif
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/include/ignite/cache/query/query_cursor.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/cache/query/query_cursor.h b/modules/platforms/cpp/core/include/ignite/cache/query/query_cursor.h
index e3fe99f..4ef2405 100644
--- a/modules/platforms/cpp/core/include/ignite/cache/query/query_cursor.h
+++ b/modules/platforms/cpp/core/include/ignite/cache/query/query_cursor.h
@@ -28,11 +28,11 @@
 #include "ignite/impl/operations.h"
 
 namespace ignite
-{    
+{
     namespace cache
     {
         namespace query
-        {            
+        {
             /**
              * Query cursor.
              */
@@ -53,12 +53,11 @@ namespace ignite
                  *
                  * @param impl Implementation.
                  */
-                QueryCursor(impl::cache::query::QueryCursorImpl* impl) : 
-                    impl(ignite::common::concurrent::SharedPointer<impl::cache::query::QueryCursorImpl>(impl))
+                QueryCursor(impl::cache::query::QueryCursorImpl* impl) : impl(impl)
                 {
                     // No-op.
                 }
-                
+
                 /**
                  * Check whether next entry exists.
                  *
@@ -109,7 +108,7 @@ namespace ignite
 
                     IgniteError::ThrowIfNeeded(err);
 
-                    return res;                        
+                    return res;
                 }
 
                 /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/include/ignite/cache/query/query_fields_cursor.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/cache/query/query_fields_cursor.h b/modules/platforms/cpp/core/include/ignite/cache/query/query_fields_cursor.h
new file mode 100644
index 0000000..8410c81
--- /dev/null
+++ b/modules/platforms/cpp/core/include/ignite/cache/query/query_fields_cursor.h
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+#ifndef _IGNITE_CACHE_QUERY_FIELDS_CURSOR
+#define _IGNITE_CACHE_QUERY_FIELDS_CURSOR
+
+#include <vector>
+
+#include <ignite/common/concurrent.h>
+
+#include "ignite/cache/cache_entry.h"
+#include "ignite/ignite_error.h"
+#include "ignite/cache/query/query_fields_row.h"
+#include "ignite/impl/cache/query/query_impl.h"
+#include "ignite/impl/operations.h"
+
+namespace ignite
+{
+    namespace cache
+    {
+        namespace query
+        {
+            /**
+             * Query fields cursor.
+             */
+            class QueryFieldsCursor
+            {
+            public:
+                /**
+                 * Default constructor.
+                 */
+                QueryFieldsCursor() : impl(NULL)
+                {
+                    // No-op.
+                }
+
+                /**
+                 * Constructor.
+                 *
+                 * @param impl Implementation.
+                 */
+                QueryFieldsCursor(impl::cache::query::QueryCursorImpl* impl) : impl(impl)
+                {
+                    // No-op.
+                }
+                
+                /**
+                 * Check whether next entry exists.
+                 *
+                 * @return True if next entry exists.
+                 */
+                bool HasNext()
+                {
+                    IgniteError err;
+
+                    bool res = HasNext(err);
+
+                    IgniteError::ThrowIfNeeded(err);
+
+                    return res;
+                }
+
+                /**
+                 * Check whether next entry exists.
+                 *
+                 * @param err Error.
+                 * @return True if next entry exists.
+                 */
+                bool HasNext(IgniteError& err)
+                {
+                    impl::cache::query::QueryCursorImpl* impl0 = impl.Get();
+
+                    if (impl0)
+                        return impl0->HasNext(&err);
+                    else
+                    {
+                        err = IgniteError(IgniteError::IGNITE_ERR_GENERIC, 
+                            "Instance is not usable (did you check for error?).");
+
+                        return false;
+                    }
+                }
+
+                /**
+                 * Get next entry.
+                 *
+                 * @return Next entry.
+                 */
+                QueryFieldsRow GetNext()
+                {
+                    IgniteError err;
+
+                    QueryFieldsRow res = GetNext(err);
+
+                    IgniteError::ThrowIfNeeded(err);
+
+                    return res;
+                }
+
+                /**
+                 * Get next entry.
+                 *
+                 * @param err Error.
+                 * @return Next entry.
+                 */
+                QueryFieldsRow GetNext(IgniteError& err)
+                {
+                    impl::cache::query::QueryCursorImpl* impl0 = impl.Get();
+
+                    if (impl0)
+                        return impl0->GetNextRow(&err);
+                    else
+                    {
+                        err = IgniteError(IgniteError::IGNITE_ERR_GENERIC,
+                            "Instance is not usable (did you check for error?).");
+
+                        return QueryFieldsRow();
+                    }
+                }
+
+                /**
+                 * Check if the instance is valid.
+                 *
+                 * @return True if the instance is valid and can be used.
+                 */
+                bool IsValid()
+                {
+                    return impl.IsValid();
+                }
+
+            private:
+                /** Implementation delegate. */
+                ignite::common::concurrent::SharedPointer<impl::cache::query::QueryCursorImpl> impl;
+            };
+        }
+    }    
+}
+
+#endif
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/include/ignite/cache/query/query_fields_row.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/cache/query/query_fields_row.h b/modules/platforms/cpp/core/include/ignite/cache/query/query_fields_row.h
new file mode 100644
index 0000000..1e70a8d
--- /dev/null
+++ b/modules/platforms/cpp/core/include/ignite/cache/query/query_fields_row.h
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+#ifndef _IGNITE_CACHE_QUERY_FIELDS_ROW
+#define _IGNITE_CACHE_QUERY_FIELDS_ROW
+
+#include <vector>
+
+#include <ignite/common/concurrent.h>
+
+#include "ignite/cache/cache_entry.h"
+#include "ignite/ignite_error.h"
+#include "ignite/impl/cache/query/query_fields_row_impl.h"
+#include "ignite/impl/operations.h"
+
+namespace ignite
+{
+    namespace cache
+    {
+        namespace query
+        {
+            /**
+             * Query fields cursor.
+             */
+            class QueryFieldsRow
+            {
+            public:
+                /**
+                 * Default constructor.
+                 */
+                QueryFieldsRow() : impl(NULL)
+                {
+                    // No-op.
+                }
+
+                /**
+                 * Constructor.
+                 *
+                 * @param impl Implementation.
+                 */
+                QueryFieldsRow(impl::cache::query::QueryFieldsRowImpl* impl) : impl(impl)
+                {
+                    // No-op.
+                }
+
+                /**
+                 * Check whether next entry exists.
+                 *
+                 * @return True if next entry exists.
+                 */
+                bool HasNext()
+                {
+                    IgniteError err;
+
+                    bool res = HasNext(err);
+
+                    IgniteError::ThrowIfNeeded(err);
+
+                    return res;
+                }
+
+                /**
+                 * Check whether next entry exists.
+                 *
+                 * @param err Error.
+                 * @return True if next entry exists.
+                 */
+                bool HasNext(IgniteError& err)
+                {
+                    impl::cache::query::QueryFieldsRowImpl* impl0 = impl.Get();
+
+                    if (impl0)
+                        return impl0->HasNext();
+                    else
+                    {
+                        err = IgniteError(IgniteError::IGNITE_ERR_GENERIC, 
+                            "Instance is not usable (did you check for error?).");
+
+                        return false;
+                    }
+                }
+
+                /**
+                 * Get next entry.
+                 *
+                 * @return Next entry.
+                 */
+                template<typename T>
+                T GetNext()
+                {
+                    IgniteError err;
+
+                    QueryFieldsRow res = GetNext<T>(err);
+
+                    IgniteError::ThrowIfNeeded(err);
+
+                    return res;
+                }
+
+                /**
+                 * Get next entry.
+                 *
+                 * @param err Error.
+                 * @return Next entry.
+                 */
+                template<typename T>
+                T GetNext(IgniteError& err)
+                {
+                    impl::cache::query::QueryFieldsRowImpl* impl0 = impl.Get();
+
+                    if (impl0)
+                        return impl0->GetNext<T>(err);
+                    else
+                    {
+                        err = IgniteError(IgniteError::IGNITE_ERR_GENERIC,
+                            "Instance is not usable (did you check for error?).");
+
+                        return T();
+                    }
+                }
+
+                /**
+                 * Check if the instance is valid.
+                 *
+                 * @return True if the instance is valid and can be used.
+                 */
+                bool IsValid()
+                {
+                    return impl.IsValid();
+                }
+
+            private:
+                /** Implementation delegate. */
+                ignite::common::concurrent::SharedPointer<impl::cache::query::QueryFieldsRowImpl> impl;
+            };
+        }
+    }    
+}
+
+#endif
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/include/ignite/cache/query/query_sql.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/cache/query/query_sql.h b/modules/platforms/cpp/core/include/ignite/cache/query/query_sql.h
index 103557e..d623536 100644
--- a/modules/platforms/cpp/core/include/ignite/cache/query/query_sql.h
+++ b/modules/platforms/cpp/core/include/ignite/cache/query/query_sql.h
@@ -54,23 +54,14 @@ namespace ignite
                  *
                  * @param other Other instance.
                  */
-                SqlQuery(const SqlQuery& other)
+                SqlQuery(const SqlQuery& other) : type(other.type), sql(other.sql), pageSize(other.pageSize),
+                    loc(other.loc), args()
                 {
-                    type = other.type;
-                    sql = other.sql;
-                    pageSize = other.pageSize;
-                    loc = other.loc;
+                    args.reserve(other.args.size());
 
-                    if (other.args)
-                    {
-                        args = new std::vector<QueryArgumentBase*>();
-
-                        for (std::vector<QueryArgumentBase*>::iterator it = other.args->begin();
-                            it != other.args->end(); ++it)
-                            args->push_back((*it)->Copy());
-                    }
-                    else
-                        args = NULL;
+                    for (std::vector<QueryArgumentBase*>::const_iterator i = other.args.begin(); 
+                        i != other.args.end(); ++i)
+                        args.push_back((*i)->Copy());
                 }
 
                 /**
@@ -82,18 +73,13 @@ namespace ignite
                 {
                     if (this != &other)
                     {
-                        type = other.type;
-                        sql = other.sql;
-                        pageSize = other.pageSize;
-                        loc = other.loc;
-
                         SqlQuery tmp(other);
 
-                        std::vector<QueryArgumentBase*>* args0 = args;
-
-                        args = tmp.args;
-
-                        tmp.args = args0; 
+                        std::swap(type, tmp.type);
+                        std::swap(sql, tmp.sql);
+                        std::swap(pageSize, tmp.pageSize);
+                        std::swap(loc, tmp.loc);
+                        std::swap(args, tmp.args);
                     }
 
                     return *this;
@@ -104,12 +90,24 @@ namespace ignite
                  */
                 ~SqlQuery()
                 {
-                    if (args) 
-                    {
-                        for (std::vector<QueryArgumentBase*>::iterator it = args->begin(); it != args->end(); ++it)
-                            delete (*it);
+                    for (std::vector<QueryArgumentBase*>::iterator it = args.begin(); it != args.end(); ++it)
+                        delete *it;
+                }
 
-                        delete args;
+                /**
+                 * Efficiently swaps contents with another SqlQuery instance.
+                 *
+                 * @param other Other instance.
+                 */
+                void Swap(SqlQuery& other)
+                {
+                    if (this != &other)
+                    {
+                        std::swap(type, other.type);
+                        std::swap(sql, other.sql);
+                        std::swap(pageSize, other.pageSize);
+                        std::swap(loc, other.loc);
+                        std::swap(args, other.args);
                     }
                 }
 
@@ -201,10 +199,7 @@ namespace ignite
                 template<typename T>
                 void AddArgument(const T& arg)
                 {
-                    if (!args)
-                        args = new std::vector<QueryArgumentBase*>();
-
-                    args->push_back(new QueryArgument<T>(arg));
+                    args.push_back(new QueryArgument<T>(arg));
                 }
 
                 /**
@@ -219,15 +214,10 @@ namespace ignite
                     writer.WriteString(type);
                     writer.WriteInt32(pageSize);
 
-                    if (args)
-                    {
-                        writer.WriteInt32(static_cast<int32_t>(args->size()));
+                    writer.WriteInt32(static_cast<int32_t>(args.size()));
 
-                        for (std::vector<QueryArgumentBase*>::iterator it = args->begin(); it != args->end(); ++it)
-                            (*it)->Write(writer);
-                    }
-                    else
-                        writer.WriteInt32(0);
+                    for (std::vector<QueryArgumentBase*>::const_iterator it = args.begin(); it != args.end(); ++it)
+                        (*it)->Write(writer);
                 }
 
             private:
@@ -244,7 +234,7 @@ namespace ignite
                 bool loc;
 
                 /** Arguments. */
-                std::vector<QueryArgumentBase*>* args;
+                std::vector<QueryArgumentBase*> args;
             };
         }
     }    

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/include/ignite/cache/query/query_sql_fields.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/cache/query/query_sql_fields.h b/modules/platforms/cpp/core/include/ignite/cache/query/query_sql_fields.h
new file mode 100644
index 0000000..945bf71
--- /dev/null
+++ b/modules/platforms/cpp/core/include/ignite/cache/query/query_sql_fields.h
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+#ifndef _IGNITE_CACHE_QUERY_SQL_FIELDS
+#define _IGNITE_CACHE_QUERY_SQL_FIELDS
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "ignite/cache/query/query_argument.h"
+#include "ignite/portable/portable_raw_writer.h"
+
+namespace ignite
+{
+    namespace cache
+    {
+        namespace query
+        {
+            /**
+             * Sql fields query.
+             */
+            class SqlFieldsQuery
+            {
+            public:
+                /**
+                 * Constructor.
+                 *
+                 * @param sql SQL string.
+                 */
+                SqlFieldsQuery(const std::string& sql) : sql(sql), pageSize(1024), loc(false), args()
+                {
+                    // No-op.
+                }
+
+                /**
+                 * Constructor.
+                 *
+                 * @param sql SQL string.
+                 * @param loc Whether query should be executed locally.
+                 */
+                SqlFieldsQuery(const std::string& sql, bool loc) : sql(sql), pageSize(1024), loc(false), args()
+                {
+                    // No-op.
+                }
+
+                /**
+                 * Copy constructor.
+                 *
+                 * @param other Other instance.
+                 */
+                SqlFieldsQuery(const SqlFieldsQuery& other) : sql(other.sql), pageSize(other.pageSize), loc(other.loc),
+                    args()
+                {
+                    args.reserve(other.args.size());
+
+                    for (std::vector<QueryArgumentBase*>::const_iterator i = other.args.begin(); 
+                        i != other.args.end(); ++i)
+                        args.push_back((*i)->Copy());
+                }
+
+                /**
+                 * Assignment operator.
+                 *
+                 * @param other Other instance.
+                 */
+                SqlFieldsQuery& operator=(const SqlFieldsQuery& other) 
+                {
+                    if (this != &other)
+                    {
+                        SqlFieldsQuery tmp(other);
+
+                        std::swap(sql, tmp.sql);
+                        std::swap(pageSize, tmp.pageSize);
+                        std::swap(loc, tmp.loc);
+                        std::swap(args, tmp.args);
+                    }
+
+                    return *this;
+                }
+
+                /**
+                 * Destructor.
+                 */
+                ~SqlFieldsQuery()
+                {
+                    for (std::vector<QueryArgumentBase*>::iterator it = args.begin(); it != args.end(); ++it)
+                        delete *it;
+                }
+                
+                /**
+                 * Get SQL string.
+                 *
+                 * @return SQL string.
+                 */
+                const std::string& GetSql() const
+                {
+                    return sql;
+                }
+
+                /**
+                 * Set SQL string.
+                 *
+                 * @param sql SQL string.
+                 */
+                void SetSql(const std::string& sql)
+                {
+                    this->sql = sql;
+                }
+
+                /**
+                 * Get page size.
+                 *
+                 * @return Page size.
+                 */
+                int32_t GetPageSize() const
+                {
+                    return pageSize;
+                }
+
+                /**
+                 * Set page size.
+                 *
+                 * @param pageSize Page size.
+                 */
+                void SetPageSize(int32_t pageSize)
+                {
+                    this->pageSize = pageSize;
+                }
+
+                /**
+                 * Get local flag.
+                 *
+                 * @return Local flag.
+                 */
+                bool IsLocal() const
+                {
+                    return loc;
+                }
+
+                /**
+                 * Set local flag.
+                 *
+                 * @param loc Local flag.
+                 */
+                void SetLocal(bool loc)
+                {
+                    this->loc = loc;
+                }
+
+                /**
+                 * Add argument.
+                 *
+                 * @param arg Argument.
+                 */
+                template<typename T>
+                void AddArgument(const T& arg)
+                {
+                    args.push_back(new QueryArgument<T>(arg));
+                }
+
+                /**
+                 * Write query info to the stream.
+                 *
+                 * @param writer Writer.
+                 */
+                void Write(portable::PortableRawWriter& writer) const
+                {
+                    writer.WriteBool(loc);
+                    writer.WriteString(sql);
+                    writer.WriteInt32(pageSize);
+
+                    writer.WriteInt32(static_cast<int32_t>(args.size()));
+
+                    for (std::vector<QueryArgumentBase*>::const_iterator it = args.begin(); it != args.end(); ++it)
+                        (*it)->Write(writer);
+                }
+
+            private:
+                /** SQL string. */
+                std::string sql;
+
+                /** Page size. */
+                int32_t pageSize;
+
+                /** Local flag. */
+                bool loc;
+
+                /** Arguments. */
+                std::vector<QueryArgumentBase*> args;
+            };
+        }
+    }    
+}
+
+#endif
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/include/ignite/impl/cache/cache_impl.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/impl/cache/cache_impl.h b/modules/platforms/cpp/core/include/ignite/impl/cache/cache_impl.h
index b7596bf..803ef04 100644
--- a/modules/platforms/cpp/core/include/ignite/impl/cache/cache_impl.h
+++ b/modules/platforms/cpp/core/include/ignite/impl/cache/cache_impl.h
@@ -21,6 +21,7 @@
 #include "ignite/cache/query/query_scan.h"
 #include "ignite/cache/query/query_sql.h"
 #include "ignite/cache/query/query_text.h"
+#include "ignite/cache/query/query_sql_fields.h"
 #include "ignite/impl/ignite_environment.h"
 #include "ignite/impl/cache/query/query_impl.h"
 #include "ignite/impl/operations.h"
@@ -316,6 +317,15 @@ namespace ignite
                  * @return Query cursor.
                  */
                 query::QueryCursorImpl* QueryScan(const ignite::cache::query::ScanQuery& qry, IgniteError* err);
+
+                /*
+                 * Invoke sql fields query.
+                 *
+                 * @param qry Query.
+                 * @param err Error.
+                 * @return Query cursor.
+                 */
+                query::QueryCursorImpl* QuerySqlFields(const ignite::cache::query::SqlFieldsQuery& qry, IgniteError* err);
                 
             private:
                 /** Name. */

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h b/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h
new file mode 100644
index 0000000..ff04c09
--- /dev/null
+++ b/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+#ifndef _IGNITE_CACHE_QUERY_FIELDS_ROW_IMPL
+#define _IGNITE_CACHE_QUERY_FIELDS_ROW_IMPL
+
+#include <vector>
+#include <memory>
+
+#include <ignite/common/concurrent.h>
+
+#include "ignite/cache/cache_entry.h"
+#include "ignite/ignite_error.h"
+#include "ignite/impl/cache/query/query_impl.h"
+#include "ignite/impl/operations.h"
+
+namespace ignite
+{
+    namespace impl
+    {
+        namespace cache
+        {
+            namespace query
+            {
+                /**
+                 * Query fields cursor implementation.
+                 */
+                class QueryFieldsRowImpl
+                {
+                public:
+                    typedef common::concurrent::SharedPointer<interop::InteropMemory> InteropMemorySharedPtr;
+
+                    /**
+                     * Default constructor.
+                     */
+                    QueryFieldsRowImpl() : mem(NULL), stream(NULL), reader(NULL), size(0), 
+                        processed(0)
+                    {
+                        // No-op.
+                    }
+
+                    /**
+                     * Constructor.
+                     *
+                     * @param mem Memory containig row data.
+                     */
+                    QueryFieldsRowImpl(InteropMemorySharedPtr mem) : mem(mem), stream(mem.Get()), 
+                        reader(&stream), size(reader.ReadInt32()), processed(0)
+                    {
+                        // No-op.
+                    }
+
+                    /**
+                     * Check whether next entry exists.
+                     *
+                     * @return True if next entry exists.
+                     */
+                    bool HasNext()
+                    {
+                        IgniteError err;
+
+                        bool res = HasNext(err);
+
+                        IgniteError::ThrowIfNeeded(err);
+
+                        return res;
+                    }
+
+                    /**
+                     * Check whether next entry exists.
+                     *
+                     * @param err Error.
+                     * @return True if next entry exists.
+                     */
+                    bool HasNext(IgniteError& err)
+                    {
+                        if (IsValid())
+                            return processed < size;
+                        else
+                        {
+                            err = IgniteError(IgniteError::IGNITE_ERR_GENERIC,
+                                "Instance is not usable (did you check for error?).");
+
+                            return false;
+                        }
+                    }
+
+                    /**
+                     * Get next entry.
+                     *
+                     * @return Next entry.
+                     */
+                    template<typename T>
+                    T GetNext()
+                    {
+                        IgniteError err;
+
+                        QueryFieldsRowImpl res = GetNext<T>(err);
+
+                        IgniteError::ThrowIfNeeded(err);
+
+                        return res;
+                    }
+
+                    /**
+                     * Get next entry.
+                     *
+                     * @param err Error.
+                     * @return Next entry.
+                     */
+                    template<typename T>
+                    T GetNext(IgniteError& err)
+                    {
+                        if (IsValid()) {
+                            ++processed;
+                            return reader.ReadTopObject<T>();
+                        }
+                        else
+                        {
+                            err = IgniteError(IgniteError::IGNITE_ERR_GENERIC,
+                                "Instance is not usable (did you check for error?).");
+
+                            return T();
+                        }
+                    }
+
+                    /**
+                     * Check if the instance is valid.
+                     *
+                     * @return True if the instance is valid and can be used.
+                     */
+                    bool IsValid()
+                    {
+                        return mem.Get() != NULL;
+                    }
+
+                private:
+                    /** Row memory. */
+                    InteropMemorySharedPtr mem;
+
+                    /** Row data stream. */
+                    interop::InteropInputStream stream;
+
+                    /** Row data reader. */
+                    portable::PortableReaderImpl reader;
+
+                    /** Number of elements in a row. */
+                    int32_t size;
+
+                    /** Number of elements that have been read by now. */
+                    int32_t processed;
+
+                    IGNITE_NO_COPY_ASSIGNMENT(QueryFieldsRowImpl)
+                };
+            }
+        }
+    }
+}
+
+#endif
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_impl.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_impl.h b/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_impl.h
index e65eeb6..e553e24 100644
--- a/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_impl.h
+++ b/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_impl.h
@@ -30,6 +30,8 @@ namespace ignite
         {
             namespace query
             {
+                class QueryFieldsRowImpl;
+
                 /**
                  * Query cursor implementation.
                  */
@@ -66,6 +68,14 @@ namespace ignite
                     void GetNext(OutputOperation& op, IgniteError* err);
 
                     /**
+                     * Get next row.
+                     *
+                     * @param err Error.
+                     * @return Output row.
+                     */
+                    QueryFieldsRowImpl* GetNextRow(IgniteError* err);
+
+                    /**
                      * Get all cursor entries.
                      *
                      * @param op Operation.

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/project/vs/core.vcxproj
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/project/vs/core.vcxproj b/modules/platforms/cpp/core/project/vs/core.vcxproj
index b7e4f7c..dfed87b 100644
--- a/modules/platforms/cpp/core/project/vs/core.vcxproj
+++ b/modules/platforms/cpp/core/project/vs/core.vcxproj
@@ -194,8 +194,11 @@
     <ClInclude Include="..\..\include\ignite\cache\query\query.h" />
     <ClInclude Include="..\..\include\ignite\cache\query\query_argument.h" />
     <ClInclude Include="..\..\include\ignite\cache\query\query_cursor.h" />
+    <ClInclude Include="..\..\include\ignite\cache\query\query_fields_cursor.h" />
+    <ClInclude Include="..\..\include\ignite\cache\query\query_fields_row.h" />
     <ClInclude Include="..\..\include\ignite\cache\query\query_scan.h" />
     <ClInclude Include="..\..\include\ignite\cache\query\query_sql.h" />
+    <ClInclude Include="..\..\include\ignite\cache\query\query_sql_fields.h" />
     <ClInclude Include="..\..\include\ignite\cache\query\query_text.h" />
     <ClInclude Include="..\..\include\ignite\ignite.h" />
     <ClInclude Include="..\..\include\ignite\ignite_configuration.h" />
@@ -203,6 +206,7 @@
     <ClInclude Include="..\..\include\ignite\ignition.h" />
     <ClInclude Include="..\..\include\ignite\guid.h" />
     <ClInclude Include="..\..\include\ignite\impl\cache\cache_impl.h" />
+    <ClInclude Include="..\..\include\ignite\impl\cache\query\query_fields_row_impl.h" />
     <ClInclude Include="..\..\include\ignite\impl\cache\query\query_impl.h" />
     <ClInclude Include="..\..\include\ignite\impl\ignite_environment.h" />
     <ClInclude Include="..\..\include\ignite\impl\ignite_impl.h" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/project/vs/core.vcxproj.filters
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/project/vs/core.vcxproj.filters b/modules/platforms/cpp/core/project/vs/core.vcxproj.filters
index 83f2fc7..67dd455 100644
--- a/modules/platforms/cpp/core/project/vs/core.vcxproj.filters
+++ b/modules/platforms/cpp/core/project/vs/core.vcxproj.filters
@@ -213,6 +213,18 @@
     <ClInclude Include="..\..\include\ignite\cache\query\query_scan.h">
       <Filter>Code\cache\query</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\ignite\cache\query\query_sql_fields.h">
+      <Filter>Code\cache\query</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\ignite\cache\query\query_fields_cursor.h">
+      <Filter>Code\cache\query</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\ignite\cache\query\query_fields_row.h">
+      <Filter>Code\cache\query</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\ignite\impl\cache\query\query_fields_row_impl.h">
+      <Filter>Code\impl\cache\query</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\ignite\impl\interop\interop_stream_position_guard.h">
       <Filter>Code\impl\interop</Filter>
     </ClInclude>

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/src/impl/cache/cache_impl.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/src/impl/cache/cache_impl.cpp b/modules/platforms/cpp/core/src/impl/cache/cache_impl.cpp
index 024e435..05c3e38 100644
--- a/modules/platforms/cpp/core/src/impl/cache/cache_impl.cpp
+++ b/modules/platforms/cpp/core/src/impl/cache/cache_impl.cpp
@@ -294,6 +294,11 @@ namespace ignite
                 return QueryInternal(qry, OP_QRY_SCAN, err);
             }
 
+            QueryCursorImpl* CacheImpl::QuerySqlFields(const SqlFieldsQuery& qry, IgniteError* err)
+            {
+                return QueryInternal(qry, OP_QRY_SQL_FIELDS, err);
+            }
+
             int64_t CacheImpl::WriteTo(InteropMemory* mem, InputOperation& inOp, IgniteError* err)
             {
                 PortableMetadataManager* metaMgr = env.Get()->GetMetadataManager();

http://git-wip-us.apache.org/repos/asf/ignite/blob/667c2e65/modules/platforms/cpp/core/src/impl/cache/query/query_impl.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/src/impl/cache/query/query_impl.cpp b/modules/platforms/cpp/core/src/impl/cache/query/query_impl.cpp
index 7d89321..786779b 100644
--- a/modules/platforms/cpp/core/src/impl/cache/query/query_impl.cpp
+++ b/modules/platforms/cpp/core/src/impl/cache/query/query_impl.cpp
@@ -16,6 +16,7 @@
  */
 
 #include "ignite/impl/cache/query/query_impl.h"
+#include "ignite/impl/cache/query/query_fields_row_impl.h"
 
 using namespace ignite::common::concurrent;
 using namespace ignite::common::java;
@@ -89,8 +90,9 @@ namespace ignite
                         JniErrorInfo jniErr;
 
                         SharedPointer<InteropMemory> inMem = env.Get()->AllocateMemory();
-
-                        env.Get()->Context()->TargetOutStream(javaRef, OP_GET_SINGLE, inMem.Get()->PointerLong(), &jniErr);
+                        
+                        env.Get()->Context()->TargetOutStream(
+                            javaRef, OP_GET_SINGLE, inMem.Get()->PointerLong(), &jniErr);
 
                         IgniteError::SetError(jniErr.code, jniErr.errCls, jniErr.errMsg, err);
 
@@ -113,6 +115,39 @@ namespace ignite
                     }
                 }
 
+                QueryFieldsRowImpl* QueryCursorImpl::GetNextRow(IgniteError* err)
+                {
+                    // Create iterator in Java if needed.
+                    if (!CreateIteratorIfNeeded(err))
+                        return NULL;
+
+                    if (hasNext)
+                    {
+                        JniErrorInfo jniErr;
+
+                        SharedPointer<InteropMemory> inMem = env.Get()->AllocateMemory();
+
+                        env.Get()->Context()->TargetOutStream(javaRef, OP_GET_SINGLE, inMem.Get()->PointerLong(), &jniErr);
+
+                        IgniteError::SetError(jniErr.code, jniErr.errCls, jniErr.errMsg, err);
+
+                        if (jniErr.code == IGNITE_JNI_ERR_SUCCESS)
+                        {
+                            hasNext = IteratorHasNext(err);
+
+                            return new QueryFieldsRowImpl(inMem);
+                        }
+                    }
+                    else
+                    {
+                        // Ensure we do not overwrite possible previous error.
+                        if (err->GetCode() == IgniteError::IGNITE_SUCCESS)
+                            *err = IgniteError(IgniteError::IGNITE_ERR_GENERIC, "No more elements available.");
+                    }
+
+                    return NULL;
+                }
+
                 void QueryCursorImpl::GetAll(OutputOperation& op, IgniteError* err)
                 {
                     // Check whether any of iterator methods were called.