You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ignite.apache.org by GitBox <gi...@apache.org> on 2020/12/30 11:32:15 UTC

[GitHub] [ignite] isapego commented on a change in pull request #8628: IGNITE-9109: Implement SQL API for CPP Thin

isapego commented on a change in pull request #8628:
URL: https://github.com/apache/ignite/pull/8628#discussion_r550106862



##########
File path: modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_fields_row.h
##########
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * Declares ignite::thin::cache::query::QueryFieldsRow class.
+ */
+
+#ifndef _IGNITE_THIN_CACHE_QUERY_QUERY_FIELDS_ROW
+#define _IGNITE_THIN_CACHE_QUERY_QUERY_FIELDS_ROW
+
+#include <ignite/common/concurrent.h>
+#include <ignite/ignite_error.h>
+
+#include <ignite/impl/thin/readable.h>
+
+namespace ignite
+{
+    namespace thin
+    {
+        namespace cache
+        {
+            namespace query
+            {
+                /**
+                 * Query fields row.
+                 *
+                 * This class implemented as a reference to an implementation so copying of this class instance will

Review comment:
       Fixed

##########
File path: modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_fields_row.h
##########
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * Declares ignite::thin::cache::query::QueryFieldsRow class.
+ */
+
+#ifndef _IGNITE_THIN_CACHE_QUERY_QUERY_FIELDS_ROW
+#define _IGNITE_THIN_CACHE_QUERY_QUERY_FIELDS_ROW
+
+#include <ignite/common/concurrent.h>
+#include <ignite/ignite_error.h>
+
+#include <ignite/impl/thin/readable.h>
+
+namespace ignite
+{
+    namespace thin
+    {
+        namespace cache
+        {
+            namespace query
+            {
+                /**
+                 * Query fields row.
+                 *
+                 * This class implemented as a reference to an implementation so copying of this class instance will
+                 * only create another reference to the same underlying object. Underlying object released automatically

Review comment:
       Fixed.

##########
File path: modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_fields_cursor.h
##########
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * Declares ignite::thin::cache::query::QueryFieldsCursor class.
+ */
+
+#ifndef _IGNITE_THIN_CACHE_QUERY_QUERY_FIELDS_CURSOR
+#define _IGNITE_THIN_CACHE_QUERY_QUERY_FIELDS_CURSOR
+
+#include <vector>
+
+#include <ignite/common/concurrent.h>
+
+#include <ignite/ignite_error.h>
+#include <ignite/thin/cache/query/query_fields_row.h>
+
+namespace ignite
+{
+    namespace thin
+    {
+        namespace cache
+        {
+            namespace query
+            {
+                /**
+                 * Query fields cursor.
+                 *
+                 * This class implemented as a reference to an implementation so copying of this class instance will
+                 * only create another reference to the same underlying object. Underlying object released automatically
+                 * once all the instances are destructed.
+                 */
+                class IGNITE_IMPORT_EXPORT QueryFieldsCursor
+                {
+                public:
+                    /**
+                     * Constructor.
+                     *
+                     * Internal method. Should not be used by user.
+                     *
+                     * @param impl Implementation.
+                     */
+                    explicit QueryFieldsCursor(const common::concurrent::SharedPointer<void>& impl);
+
+                    /**
+                     * Check whether next entry exists.
+                     *
+                     * @return True if next entry exists.
+                     *
+                     * @throw IgniteError class instance in case of failure.
+                     */
+                    bool HasNext();
+
+                    /**
+                     * Get next entry.
+                     *
+                     * @return Next entry.
+                     *
+                     * @throw IgniteError class instance in case of failure.
+                     */
+                    QueryFieldsRow GetNext();
+
+                    /**
+                     * Get column names.
+                     *
+                     * @return Column names.
+                     */
+                    const std::vector<std::string>& GetColumnNames() const;
+
+                    /**
+                     * Get name of the specific column.
+                     *
+                     * @param idx Column index.
+                     * @return Column names.
+                     *
+                     * @throw IgniteError class instance in case of invalid index.
+                     */
+                    const std::string& GetColumnName(size_t idx) const;

Review comment:
       I think, you are right. Removed it.

##########
File path: modules/platforms/cpp/thin-client-test/src/sql_fields_query_test.cpp
##########
@@ -0,0 +1,389 @@
+/*
+ * 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.
+ */
+
+#include <boost/test/unit_test.hpp>
+
+#include <ignite/ignition.h>
+
+#include <ignite/thin/ignite_client_configuration.h>
+#include <ignite/thin/ignite_client.h>
+
+#include <ignite/test_type.h>
+#include <test_utils.h>
+
+using namespace ignite::thin;
+using namespace ignite::thin::cache::query;
+using namespace boost::unit_test;
+
+class SqlFieldsQueryTestSuiteFixture
+{
+public:
+    static ignite::Ignite StartNode(const char* name)
+    {
+        return ignite_test::StartCrossPlatformServerNode("sql-query-fields.xml", name);
+    }
+
+    SqlFieldsQueryTestSuiteFixture()
+    {
+        serverNode = StartNode("ServerNode");
+
+        IgniteClientConfiguration cfg;
+
+        cfg.SetEndPoints("127.0.0.1:11110");
+
+        client = IgniteClient::Start(cfg);
+
+        cacheAllFields = client.GetCache<int64_t, ignite::TestType>("cacheAllFields");
+    }
+
+    ~SqlFieldsQueryTestSuiteFixture()
+    {
+        ignite::Ignition::StopAll(false);
+    }
+
+protected:
+    /** Server node. */
+    ignite::Ignite serverNode;
+
+    /** Client. */
+    IgniteClient client;
+
+    /** Cache with TestType. */
+    cache::CacheClient<int64_t, ignite::TestType> cacheAllFields;
+};
+
+BOOST_AUTO_TEST_SUITE(SqlFieldsQueryBasicTestSuite)
+
+BOOST_AUTO_TEST_CASE(SqlFieldsQueryDefaults)
+{
+    std::string sql("select * from TestType");
+
+    SqlFieldsQuery qry(sql);
+
+    BOOST_CHECK_EQUAL(qry.GetSql(), sql);
+    BOOST_CHECK_EQUAL(qry.GetTimeout(), 0);
+    BOOST_CHECK_EQUAL(qry.GetMaxRows(), 0);
+    BOOST_CHECK_EQUAL(qry.GetPageSize(), 1024);
+    BOOST_CHECK_EQUAL(qry.GetSchema(), std::string());
+
+    BOOST_CHECK(!qry.IsLocal());
+    BOOST_CHECK(!qry.IsCollocated());
+    BOOST_CHECK(!qry.IsDistributedJoins());
+    BOOST_CHECK(!qry.IsEnforceJoinOrder());
+    BOOST_CHECK(!qry.IsLazy());
+}
+
+BOOST_AUTO_TEST_CASE(SqlFieldsQuerySetGet)
+{
+    std::string sql("select * from TestType");
+
+    SqlFieldsQuery qry(sql);
+
+    qry.SetTimeout(1000);
+    qry.SetMaxRows(100);
+    qry.SetPageSize(4096);
+    qry.SetSchema("PUBLIC");
+
+    qry.SetLocal(true);
+    qry.SetCollocated(true);
+    qry.SetDistributedJoins(true);
+    qry.SetEnforceJoinOrder(true);
+    qry.SetLazy(true);
+
+    BOOST_CHECK_EQUAL(qry.GetSql(), sql);
+    BOOST_CHECK_EQUAL(qry.GetTimeout(), 1000);
+    BOOST_CHECK_EQUAL(qry.GetMaxRows(), 100);
+    BOOST_CHECK_EQUAL(qry.GetPageSize(), 4096);
+    BOOST_CHECK_EQUAL(qry.GetSchema(), std::string("PUBLIC"));
+
+    BOOST_CHECK(qry.IsLocal());
+    BOOST_CHECK(qry.IsCollocated());
+    BOOST_CHECK(qry.IsDistributedJoins());
+    BOOST_CHECK(qry.IsEnforceJoinOrder());
+    BOOST_CHECK(qry.IsLazy());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+/**
+ * Check that error empty cursor error.
+ *
+ * @param err Error.
+ */
+bool IsCursorEmptyError(const ignite::IgniteError& err)
+{
+    return err.GetCode() == ignite::IgniteError::IGNITE_ERR_GENERIC &&
+        std::string(err.GetText()) == "The cursor is empty";
+}
+
+/**
+ * Check that cursor is empty.
+ *
+ * @param cursor Cursor.
+ */
+void CheckCursorEmpty(QueryFieldsCursor& cursor)
+{
+    BOOST_CHECK(!cursor.HasNext());
+    BOOST_CHECK_EXCEPTION(cursor.GetNext(), ignite::IgniteError, IsCursorEmptyError);
+}
+
+/**
+ * Check that row is empty.
+ *
+ * @param row Row.
+ */
+void CheckRowCursorEmpty(QueryFieldsRow& row)
+{
+    BOOST_CHECK(!row.HasNext());
+    BOOST_CHECK_EXCEPTION(row.GetNext<int8_t>(), ignite::IgniteError, IsCursorEmptyError);
+}
+
+/**
+ * Check that row columns equal value fields.
+ *
+ * @param row Row.
+ * @param val Value.
+ */
+void CheckRowEqualsValue(QueryFieldsRow& row, const ignite::TestType& val)
+{
+    BOOST_CHECK_EQUAL(row.GetNext<int8_t>(), val.i8Field);
+    BOOST_CHECK_EQUAL(row.GetNext<int16_t>(), val.i16Field);
+    BOOST_CHECK_EQUAL(row.GetNext<int32_t>(), val.i32Field);
+    BOOST_CHECK_EQUAL(row.GetNext<int64_t>(), val.i64Field);
+    BOOST_CHECK_EQUAL(row.GetNext<std::string>(), val.strField);
+    BOOST_CHECK_CLOSE(row.GetNext<float>(), val.floatField, 0.0001);
+    BOOST_CHECK_CLOSE(row.GetNext<double>(), val.doubleField, 0.0001);
+    BOOST_CHECK_EQUAL(row.GetNext<bool>(), val.boolField);
+    BOOST_CHECK_EQUAL(row.GetNext<ignite::Guid>(), val.guidField);
+    BOOST_CHECK(row.GetNext<ignite::Date>() == val.dateField);
+    BOOST_CHECK(row.GetNext<ignite::Time>() == val.timeField);
+    BOOST_CHECK(row.GetNext<ignite::Timestamp>() == val.timestampField);
+
+    std::vector<int8_t> resArray(val.i8ArrayField.size());
+
+    row.GetNextInt8Array(&resArray[0], static_cast<int32_t>(resArray.size()));
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(
+            resArray.begin(), resArray.end(),
+            val.i8ArrayField.begin(), val.i8ArrayField.end());
+}
+
+/**
+ * Make custom test value.
+ *
+ * @param seed Seed to generate value.
+ */
+ignite::TestType MakeCustomTestValue(int32_t seed)
+{
+    ignite::TestType val;
+
+    val.i8Field = seed;
+    val.i16Field = 2 * seed;
+    val.i32Field = 4 * seed;
+    val.i64Field = 8 * seed;
+    val.strField = "Lorem ipsum";
+    val.floatField = 16.0f * seed;
+    val.doubleField = 32.0 * seed;
+    val.boolField = ((seed % 2) == 0);
+    val.guidField = ignite::Guid(0x1020304050607080 * seed, 0x9000A0B0C0D0E0F0 * seed);
+    val.dateField = ignite::Date(235682736 * seed);
+    val.timeField = ignite::Time(124523 * seed);
+    val.timestampField = ignite::Timestamp(128341594123 * seed);
+
+    val.i8ArrayField.push_back(9 * seed);
+    val.i8ArrayField.push_back(6 * seed);
+    val.i8ArrayField.push_back(3 * seed);
+    val.i8ArrayField.push_back(42 * seed);
+
+    return val;
+}
+
+
+BOOST_FIXTURE_TEST_SUITE(SqlFieldsQueryTestSuite, SqlFieldsQueryTestSuiteFixture)
+
+BOOST_AUTO_TEST_CASE(SelectEmpty)
+{
+    SqlFieldsQuery qry("select * from TestType");
+
+    QueryFieldsCursor cursor = cacheAllFields.Query(qry);
+
+    CheckCursorEmpty(cursor);
+
+    const std::vector<std::string>& columns = cursor.GetColumnNames();
+
+    BOOST_CHECK_EQUAL(columns.size(), 13);
+
+    BOOST_CHECK_EQUAL(columns.at(0), "I8FIELD");
+    BOOST_CHECK_EQUAL(columns.at(1), "I16FIELD");
+    BOOST_CHECK_EQUAL(columns.at(2), "I32FIELD");
+    BOOST_CHECK_EQUAL(columns.at(3), "I64FIELD");
+    BOOST_CHECK_EQUAL(columns.at(4), "STRFIELD");
+    BOOST_CHECK_EQUAL(columns.at(5), "FLOATFIELD");
+    BOOST_CHECK_EQUAL(columns.at(6), "DOUBLEFIELD");
+    BOOST_CHECK_EQUAL(columns.at(7), "BOOLFIELD");
+    BOOST_CHECK_EQUAL(columns.at(8), "GUIDFIELD");
+    BOOST_CHECK_EQUAL(columns.at(9), "DATEFIELD");
+    BOOST_CHECK_EQUAL(columns.at(10), "TIMEFIELD");
+    BOOST_CHECK_EQUAL(columns.at(11), "TIMESTAMPFIELD");
+    BOOST_CHECK_EQUAL(columns.at(12), "I8ARRAYFIELD");
+
+    BOOST_CHECK_EQUAL(cursor.GetColumnName(0), "I8FIELD");
+    BOOST_CHECK_EQUAL(cursor.GetColumnName(1), "I16FIELD");
+    BOOST_CHECK_EQUAL(cursor.GetColumnName(2), "I32FIELD");
+    BOOST_CHECK_EQUAL(cursor.GetColumnName(3), "I64FIELD");
+    BOOST_CHECK_EQUAL(cursor.GetColumnName(4), "STRFIELD");
+    BOOST_CHECK_EQUAL(cursor.GetColumnName(5), "FLOATFIELD");
+    BOOST_CHECK_EQUAL(cursor.GetColumnName(6), "DOUBLEFIELD");
+    BOOST_CHECK_EQUAL(cursor.GetColumnName(7), "BOOLFIELD");
+    BOOST_CHECK_EQUAL(cursor.GetColumnName(8), "GUIDFIELD");
+    BOOST_CHECK_EQUAL(cursor.GetColumnName(9), "DATEFIELD");
+    BOOST_CHECK_EQUAL(cursor.GetColumnName(10), "TIMEFIELD");
+    BOOST_CHECK_EQUAL(cursor.GetColumnName(11), "TIMESTAMPFIELD");
+    BOOST_CHECK_EQUAL(cursor.GetColumnName(12), "I8ARRAYFIELD");
+}
+
+BOOST_AUTO_TEST_CASE(SelectSingleValue)
+{
+    ignite::TestType val = MakeCustomTestValue(1);
+
+    cacheAllFields.Put(42, val);
+
+    SqlFieldsQuery qry("select i8Field, i16Field, i32Field, i64Field, strField, floatField, "
+        "doubleField, boolField, guidField, dateField, timeField, timestampField, i8ArrayField FROM TestType");
+
+    QueryFieldsCursor cursor = cacheAllFields.Query(qry);
+
+    BOOST_CHECK(cursor.HasNext());
+
+    QueryFieldsRow row = cursor.GetNext();
+
+    BOOST_CHECK(row.HasNext());
+
+    CheckRowEqualsValue(row, val);
+
+    CheckRowCursorEmpty(row);
+    CheckCursorEmpty(cursor);
+}
+
+BOOST_AUTO_TEST_CASE(SelectTwoValues)
+{
+    ignite::TestType val1 = MakeCustomTestValue(1);
+    ignite::TestType val2 = MakeCustomTestValue(2);
+
+    cacheAllFields.Put(1, val1);
+    cacheAllFields.Put(2, val2);
+
+    SqlFieldsQuery qry("select i8Field, i16Field, i32Field, i64Field, strField, floatField, "

Review comment:
       Good point. Added test.

##########
File path: modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_fields_row.h
##########
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * Declares ignite::thin::cache::query::QueryFieldsRow class.
+ */
+
+#ifndef _IGNITE_THIN_CACHE_QUERY_QUERY_FIELDS_ROW
+#define _IGNITE_THIN_CACHE_QUERY_QUERY_FIELDS_ROW
+
+#include <ignite/common/concurrent.h>
+#include <ignite/ignite_error.h>
+
+#include <ignite/impl/thin/readable.h>
+
+namespace ignite
+{
+    namespace thin
+    {
+        namespace cache
+        {
+            namespace query
+            {
+                /**
+                 * Query fields row.
+                 *
+                 * This class implemented as a reference to an implementation so copying of this class instance will
+                 * only create another reference to the same underlying object. Underlying object released automatically
+                 * once all the instances are destructed.
+                 */
+                class IGNITE_IMPORT_EXPORT QueryFieldsRow
+                {
+                public:
+                    /**
+                     * Constructor.
+                     *
+                     * Internal method. Should not be used by user.
+                     *
+                     * @param impl Implementation.
+                     */
+                    explicit QueryFieldsRow(const common::concurrent::SharedPointer<void>& impl);
+
+                    /**
+                     * Check whether next entry exists.
+                     *
+                     * @return True if next entry exists.
+                     */
+                    bool HasNext();
+
+                    /**
+                     * Get next entry.
+                     *
+                     * @tparam T Value type to get. Should be default-constructable, copy-constructable and assignable.
+                     *     Also BinaryType class template should be specialized for this type.
+                     *
+                     * @return Next entry.
+                     *
+                     * @throw IgniteError class instance in case of failure.
+                     */
+                    template<typename T>
+                    T GetNext()
+                    {
+                        T res;
+                        impl::thin::ReadableImpl<T> readable(res);
+
+                        InternalGetNest(readable);
+
+                        return res;
+                    }
+
+                    /**
+                     * Get next entry assuming it's an array of 8-byte signed integers. Maps to "byte[]" type in Java
+                     * and BINARY type in SQL.
+                     *
+                     * @param dst Array to store data to.
+                     * @param len Expected length of array.
+                     * @return Actual amount of elements read. If "len" argument is less than actual array size or
+                     *     resulting array is set to null, nothing will be written to resulting array and returned value
+                     *     will contain required array length.
+                     *     @c -1 will be returned in case array in stream was null.
+                     *
+                     * @throw IgniteError class instance in case of failure.
+                     */
+                    int32_t GetNextInt8Array(int8_t *dst, int32_t len);

Review comment:
       Well, this is an old workaround as we can not get arrays as a single object now. On the second thought, I think I can implement it better.

##########
File path: modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_fields_row.h
##########
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * Declares ignite::thin::cache::query::QueryFieldsRow class.
+ */
+
+#ifndef _IGNITE_THIN_CACHE_QUERY_QUERY_FIELDS_ROW
+#define _IGNITE_THIN_CACHE_QUERY_QUERY_FIELDS_ROW
+
+#include <ignite/common/concurrent.h>
+#include <ignite/ignite_error.h>
+
+#include <ignite/impl/thin/readable.h>
+
+namespace ignite
+{
+    namespace thin
+    {
+        namespace cache
+        {
+            namespace query
+            {
+                /**
+                 * Query fields row.
+                 *
+                 * This class implemented as a reference to an implementation so copying of this class instance will
+                 * only create another reference to the same underlying object. Underlying object released automatically
+                 * once all the instances are destructed.
+                 */
+                class IGNITE_IMPORT_EXPORT QueryFieldsRow
+                {
+                public:
+                    /**
+                     * Constructor.
+                     *
+                     * Internal method. Should not be used by user.
+                     *
+                     * @param impl Implementation.
+                     */
+                    explicit QueryFieldsRow(const common::concurrent::SharedPointer<void>& impl);
+
+                    /**
+                     * Check whether next entry exists.
+                     *
+                     * @return True if next entry exists.
+                     */
+                    bool HasNext();
+
+                    /**
+                     * Get next entry.
+                     *
+                     * @tparam T Value type to get. Should be default-constructable, copy-constructable and assignable.
+                     *     Also BinaryType class template should be specialized for this type.
+                     *
+                     * @return Next entry.
+                     *
+                     * @throw IgniteError class instance in case of failure.
+                     */
+                    template<typename T>
+                    T GetNext()
+                    {
+                        T res;
+                        impl::thin::ReadableImpl<T> readable(res);
+
+                        InternalGetNest(readable);
+
+                        return res;
+                    }
+
+                    /**
+                     * Get next entry assuming it's an array of 8-byte signed integers. Maps to "byte[]" type in Java
+                     * and BINARY type in SQL.
+                     *
+                     * @param dst Array to store data to.
+                     * @param len Expected length of array.
+                     * @return Actual amount of elements read. If "len" argument is less than actual array size or
+                     *     resulting array is set to null, nothing will be written to resulting array and returned value
+                     *     will contain required array length.
+                     *     @c -1 will be returned in case array in stream was null.
+                     *
+                     * @throw IgniteError class instance in case of failure.
+                     */
+                    int32_t GetNextInt8Array(int8_t *dst, int32_t len);
+
+                private:
+                    /**
+                     * Get next entry.
+                     *
+                     * @param readable Value to read.
+                     *
+                     * @throw IgniteError class instance in case of failure.
+                     */
+                    void InternalGetNest(impl::thin::Readable& readable);

Review comment:
       Fixed.

##########
File path: modules/platforms/cpp/thin-client/src/impl/cache/query/query_fields_cursor_impl.h
##########
@@ -0,0 +1,228 @@
+/*
+ * 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_IMPL_THIN_CACHE_QUERY_QUERY_FIELDS_CURSOR_IMPL
+#define _IGNITE_IMPL_THIN_CACHE_QUERY_QUERY_FIELDS_CURSOR_IMPL
+
+#include <ignite/common/concurrent.h>
+
+#include <ignite/thin/cache/query/query_fields_row.h>
+
+#include "impl/cache/query/cursor_page.h"
+#include "impl/cache/query/query_fields_row_impl.h"
+#include "impl/data_router.h"
+#include "impl/message.h"
+
+namespace ignite
+{
+    namespace impl
+    {
+        namespace thin
+        {
+            namespace cache
+            {
+                namespace query
+                {
+                    /**
+                     * Query Fields Cursor Implementation.
+                     */
+                    class QueryFieldsCursorImpl
+                    {
+                    public:
+                        /**
+                         * Constructor.
+                         *
+                         * @param id Cursor ID.
+                         * @param columns Column names.
+                         * @param page Cursor page.
+                         * @param channel Data channel. Used to request new page.
+                         * @param timeout Timeout.
+                         */
+                        QueryFieldsCursorImpl(
+                                int64_t id,
+                                const std::vector<std::string>& columns,
+                                const SP_CursorPage &page,
+                                const SP_DataChannel& channel,
+                                int32_t timeout) :
+                            id(id),
+                            columns(columns),
+                            page(page),
+                            channel(channel),
+                            timeout(timeout),
+                            currentRow(0),
+                            stream(this->page.Get()->GetMemory()),
+                            reader(&stream),
+                            endReached(false)
+                        {
+                            stream.Position(page.Get()->GetStartPos());
+
+                            CheckEnd();
+                        }
+
+                        /**
+                         * Destructor.
+                         */
+                        virtual ~QueryFieldsCursorImpl()
+                        {
+                            // No-op.
+                        }
+
+                        /**
+                         * Check whether next entry exists.
+                         *
+                         * @return @c true if next entry exists.
+                         *
+                         * @throw IgniteError class instance in case of failure.
+                         */
+                        bool HasNext()
+                        {
+                            return !endReached;
+                        }
+
+                        /**
+                         * Get next entry.
+                         *
+                         * This method should only be used on the valid instance.
+                         *
+                         * @return Next entry.
+                         *
+                         * @throw IgniteError class instance in case of failure.
+                         */
+                        ignite::thin::cache::query::QueryFieldsRow GetNext()
+                        {
+                            if (!HasNext())
+                                throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, "The cursor is empty");
+
+                            if (IsUpdateNeeded())
+                                Update();
+
+                            SP_QueryFieldsRowImpl rowImpl(
+                                new QueryFieldsRowImpl(
+                                        static_cast<int32_t>(columns.size()),
+                                        page,
+                                        stream.Position()));
+
+                            SkipRow(*rowImpl.Get());
+
+                            return ignite::thin::cache::query::QueryFieldsRow(rowImpl);
+                        }
+
+                        /**
+                         * Get column names.
+                         *
+                         * @return Column names.
+                         */
+                        const std::vector<std::string>& GetColumns() const
+                        {
+                            return columns;
+                        }
+
+                    private:
+                        /**
+                         * Check whether next page should be retrieved from the server.
+                         *
+                         * @return @c true if next page should be fetched.
+                         */
+                        bool IsUpdateNeeded()
+                        {
+                            return !page.IsValid() && !endReached;
+                        }
+
+                        /**
+                         * Fetch next cursor page.
+                         */
+                        void Update()
+                        {
+                            SqlFieldsCursorGetPageRequest req(id);
+                            SqlFieldsCursorGetPageResponse rsp;
+
+                            DataChannel* channel0 = channel.Get();
+
+                            if (!channel0)
+                                throw IgniteError(IgniteError::IGNITE_ERR_GENERIC,"Connection is not established");

Review comment:
       Good catch )




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org