You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by is...@apache.org on 2022/05/24 10:46:14 UTC
[ignite] branch master updated: IGNITE-16877 C++ thin: Implement ScanQuery
This is an automated email from the ASF dual-hosted git repository.
isapego pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new b121a905850 IGNITE-16877 C++ thin: Implement ScanQuery
b121a905850 is described below
commit b121a905850c2398c82706cdcc164bf0bcaa815c
Author: Igor Sapego <is...@apache.org>
AuthorDate: Tue May 24 14:40:59 2022 +0400
IGNITE-16877 C++ thin: Implement ScanQuery
This closes #10033
---
.../core/include/ignite/cache/query/query_scan.h | 4 +-
.../core/include/ignite/cache/query/query_sql.h | 4 +-
.../include/ignite/cache/query/query_sql_fields.h | 4 +-
.../core/include/ignite/cache/query/query_text.h | 4 +-
.../platforms/cpp/thin-client-test/CMakeLists.txt | 1 +
.../config/sql-query-fields-default.xml | 6 +
.../cpp/thin-client-test/src/scan_query_test.cpp | 436 +++++++++++++++++++++
modules/platforms/cpp/thin-client/CMakeLists.txt | 1 +
.../ignite/impl/thin/cache/cache_client_proxy.h | 12 +-
.../impl/thin/cache/query/query_cursor_proxy.h | 88 +++++
.../include/ignite/impl/thin/readable.h | 130 +++++-
.../include/ignite/thin/cache/cache_client.h | 15 +-
.../include/ignite/thin/cache/cache_entry.h | 9 +
.../include/ignite/thin/cache/query/query_cursor.h | 151 +++++++
.../include/ignite/thin/cache/query/query_scan.h | 144 +++++++
.../ignite/thin/cache/query/query_sql_fields.h | 8 +-
.../src/cache/query/query_cursor_proxy.cpp | 67 ++++
.../src/impl/cache/cache_client_impl.cpp | 18 +
.../thin-client/src/impl/cache/cache_client_impl.h | 10 +
.../src/impl/cache/cache_client_proxy.cpp | 17 +-
...ry_fields_cursor_impl.h => query_cursor_impl.h} | 91 ++---
.../impl/cache/query/query_fields_cursor_impl.h | 6 +-
.../platforms/cpp/thin-client/src/impl/message.cpp | 36 +-
.../platforms/cpp/thin-client/src/impl/message.h | 122 +++++-
24 files changed, 1272 insertions(+), 112 deletions(-)
diff --git a/modules/platforms/cpp/core/include/ignite/cache/query/query_scan.h b/modules/platforms/cpp/core/include/ignite/cache/query/query_scan.h
index 4228ba5bc3e..3d931713773 100644
--- a/modules/platforms/cpp/core/include/ignite/cache/query/query_scan.h
+++ b/modules/platforms/cpp/core/include/ignite/cache/query/query_scan.h
@@ -111,7 +111,9 @@ namespace ignite
/**
* Set local flag.
*
- * @param loc Local flag.
+ * @param val Value of the flag. If true, query will be
+ * executed only on local node, so only local entries
+ * will be returned as query result.
*/
void SetLocal(bool loc)
{
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 b896c8aac03..46c0a98a2a0 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
@@ -201,7 +201,9 @@ namespace ignite
/**
* Set local flag.
*
- * @param loc Local flag.
+ * @param val Value of the flag. If true, query will be
+ * executed only on local node, so only local entries
+ * will be returned as query result.
*/
void SetLocal(bool loc)
{
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
index 9c051a3dc89..8da9bedaa7b 100644
--- 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
@@ -205,7 +205,9 @@ namespace ignite
/**
* Set local flag.
*
- * @param loc Local flag.
+ * @param val Value of the flag. If true, query will be
+ * executed only on local node, so only local entries
+ * will be returned as query result.
*/
void SetLocal(bool loc)
{
diff --git a/modules/platforms/cpp/core/include/ignite/cache/query/query_text.h b/modules/platforms/cpp/core/include/ignite/cache/query/query_text.h
index ded8f220263..d73e73c00c6 100644
--- a/modules/platforms/cpp/core/include/ignite/cache/query/query_text.h
+++ b/modules/platforms/cpp/core/include/ignite/cache/query/query_text.h
@@ -125,7 +125,9 @@ namespace ignite
/**
* Set local flag.
*
- * @param loc Local flag.
+ * @param val Value of the flag. If true, query will be
+ * executed only on local node, so only local entries
+ * will be returned as query result.
*/
void SetLocal(bool loc)
{
diff --git a/modules/platforms/cpp/thin-client-test/CMakeLists.txt b/modules/platforms/cpp/thin-client-test/CMakeLists.txt
index 215871f9554..3b2f095a223 100644
--- a/modules/platforms/cpp/thin-client-test/CMakeLists.txt
+++ b/modules/platforms/cpp/thin-client-test/CMakeLists.txt
@@ -38,6 +38,7 @@ set(SOURCES
src/test_utils.cpp
src/ignite_client_test.cpp
src/interop_test.cpp
+ src/scan_query_test.cpp
src/sql_fields_query_test.cpp
src/auth_test.cpp
src/tx_test.cpp
diff --git a/modules/platforms/cpp/thin-client-test/config/sql-query-fields-default.xml b/modules/platforms/cpp/thin-client-test/config/sql-query-fields-default.xml
index 9a716a31721..5a2c6abd0a1 100644
--- a/modules/platforms/cpp/thin-client-test/config/sql-query-fields-default.xml
+++ b/modules/platforms/cpp/thin-client-test/config/sql-query-fields-default.xml
@@ -79,6 +79,12 @@
<property name="cacheMode" value="PARTITIONED"/>
<property name="atomicityMode" value="TRANSACTIONAL"/>
+ <property name="affinity">
+ <bean class="org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction">
+ <property name="partitions" value="256"/>
+ </bean>
+ </property>
+
<!-- Configure type metadata to enable queries. -->
<property name="queryEntities">
<list>
diff --git a/modules/platforms/cpp/thin-client-test/src/scan_query_test.cpp b/modules/platforms/cpp/thin-client-test/src/scan_query_test.cpp
new file mode 100644
index 00000000000..c37c965c21e
--- /dev/null
+++ b/modules/platforms/cpp/thin-client-test/src/scan_query_test.cpp
@@ -0,0 +1,436 @@
+/*
+ * 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/ignite_error.h>
+#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 ScanQueryTestSuiteFixture
+{
+public:
+ static ignite::Ignite StartNode(const char* name)
+ {
+ return ignite_test::StartCrossPlatformServerNode("sql-query-fields.xml", name);
+ }
+
+ ScanQueryTestSuiteFixture()
+ {
+ serverNode = StartNode("ServerNode");
+
+ IgniteClientConfiguration cfg;
+
+ cfg.SetEndPoints("127.0.0.1:11110");
+
+ client = IgniteClient::Start(cfg);
+
+ cacheAllFields = client.GetCache<int64_t, ignite::TestType>("cacheAllFields");
+ }
+
+ ~ScanQueryTestSuiteFixture()
+ {
+ 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(ScanQueryBasicTestSuite)
+
+BOOST_AUTO_TEST_CASE(ScanQueryDefaults)
+{
+ ScanQuery qry;
+
+ BOOST_CHECK_EQUAL(qry.GetPartition(), -1);
+ BOOST_CHECK_EQUAL(qry.GetPageSize(), 1024);
+
+ BOOST_CHECK(!qry.IsLocal());
+}
+
+BOOST_AUTO_TEST_CASE(ScanQuerySetGet)
+{
+ ScanQuery qry;
+
+ qry.SetPageSize(4096);
+ qry.SetPartition(200);
+
+ qry.SetLocal(true);
+
+ BOOST_CHECK_EQUAL(qry.GetPageSize(), 4096);
+ BOOST_CHECK_EQUAL(qry.GetPartition(), 200);
+
+ BOOST_CHECK(qry.IsLocal());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+namespace
+{
+ /**
+ * 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.
+ */
+ template<typename K, typename V>
+ void CheckCursorEmpty(QueryCursor<K, V>& cursor)
+ {
+ BOOST_CHECK(!cursor.HasNext());
+ BOOST_CHECK_EXCEPTION(cursor.GetNext(), ignite::IgniteError, IsCursorEmptyError);
+ }
+ /**
+ * Check empty result through GetAll().
+ *
+ * @param cur Cursor.
+ */
+ template<typename K, typename V>
+ void CheckEmptyGetAll(QueryCursor<K, V>& cur)
+ {
+ std::vector<cache::CacheEntry<K, V> > res;
+
+ cur.GetAll(res);
+
+ BOOST_REQUIRE(res.size() == 0);
+
+ CheckCursorEmpty(cur);
+ }
+
+ /**
+ * Check empty result through iter version of GetAll().
+ *
+ * @param cur Cursor.
+ */
+ template<typename K, typename V>
+ void CheckEmptyGetAllIter(QueryCursor<K, V>& cur)
+ {
+ std::vector<cache::CacheEntry<K, V> > res;
+
+ cur.GetAll(std::back_inserter(res));
+
+ BOOST_REQUIRE(res.size() == 0);
+
+ CheckCursorEmpty(cur);
+ }
+
+ /**
+ * Check single result through iteration.
+ *
+ * @param cur Cursor.
+ * @param key Key.
+ * @param value Value.
+ */
+ template<typename K, typename V>
+ void CheckSingle(QueryCursor<K, V>& cur, const K& key, const V& value)
+ {
+ BOOST_REQUIRE(cur.HasNext());
+
+ cache::CacheEntry<K, V> entry = cur.GetNext();
+
+ BOOST_REQUIRE(entry.GetKey() == key);
+ BOOST_REQUIRE(entry.GetValue() == value);
+
+ CheckCursorEmpty(cur);
+ }
+
+ /**
+ * Check single result through GetAll().
+ *
+ * @param cur Cursor.
+ * @param key Key.
+ * @param value Value.
+ */
+ template<typename K, typename V>
+ void CheckSingleGetAll(QueryCursor<K, V>& cur, const K& key, const V& value)
+ {
+ std::vector< cache::CacheEntry<K, V> > res;
+
+ cur.GetAll(res);
+
+ CheckCursorEmpty(cur);
+
+ BOOST_CHECK_EQUAL(res.size(), 1);
+
+ BOOST_CHECK_EQUAL(res[0].GetKey(), key);
+ BOOST_CHECK(res[0].GetValue() == value);
+ }
+
+ /**
+ * Check single result through iter version of GetAll().
+ *
+ * @param cur Cursor.
+ * @param key Key.
+ * @param value Value.
+ */
+ template<typename K, typename V>
+ void CheckSingleGetAllIter(QueryCursor<K, V>& cur, const K& key, const V& value)
+ {
+ std::vector< cache::CacheEntry<K, V> > res;
+
+ cur.GetAll(std::back_inserter(res));
+
+ CheckCursorEmpty(cur);
+
+ BOOST_CHECK_EQUAL(res.size(), 1);
+
+ BOOST_CHECK_EQUAL(res[0].GetKey(), key);
+ BOOST_CHECK(res[0].GetValue() == value);
+ }
+
+ /**
+ * Check multiple results through iteration.
+ *
+ * @param cur Cursor.
+ * @param key1 Key 1.
+ * @param value1 Value 1.
+ * @param key2 Key 2.
+ * @param value2 Value 2.
+ */
+ template<typename K, typename V>
+ void CheckMultiple(QueryCursor<K, V>& cur, const K& key1, const V& value1, const K& key2, const V& value2)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ BOOST_REQUIRE(cur.HasNext());
+
+ cache::CacheEntry<K, V> entry = cur.GetNext();
+
+ if (entry.GetKey() == key1)
+ BOOST_CHECK(entry.GetValue() == value1);
+ else if (entry.GetKey() == key2)
+ BOOST_CHECK(entry.GetValue() == value2);
+ else
+ BOOST_FAIL("Unexpected entry.");
+ }
+
+ CheckCursorEmpty(cur);
+ }
+
+ /**
+ * Check multiple results through GetAll().
+ *
+ * @param cur Cursor.
+ * @param key1 Key 1.
+ * @param value1 Value 1.
+ * @param key2 Key 2.
+ * @param value2 Value 2.
+ */
+ template<typename K, typename V>
+ void CheckMultipleGetAll(QueryCursor<K, V>& cur, const K& key1, const V& value1, const K& key2, const V& value2)
+ {
+ std::vector< cache::CacheEntry<K, V> > res;
+
+ cur.GetAll(res);
+
+ CheckCursorEmpty(cur);
+
+ BOOST_REQUIRE_EQUAL(res.size(), 2);
+
+ for (int i = 0; i < 2; i++)
+ {
+ cache::CacheEntry<K, V> entry = res[i];
+
+ if (entry.GetKey() == key1)
+ BOOST_CHECK(entry.GetValue() == value1);
+ else if (entry.GetKey() == key2)
+ BOOST_CHECK(entry.GetValue() == value2);
+ else
+ BOOST_FAIL("Unexpected entry.");
+ }
+ }
+
+ /**
+ * Check multiple results through GetAll().
+ *
+ * @param cur Cursor.
+ * @param key1 Key 1.
+ * @param value1 Value 1.
+ * @param key2 Key 2.
+ * @param value2 Value 2.
+ */
+ template<typename K, typename V>
+ void CheckMultipleGetAllIter(QueryCursor<K, V>& cur, const K& key1, const V& value1, const K& key2, const V& value2)
+ {
+ std::vector< cache::CacheEntry<K, V> > res;
+
+ cur.GetAll(std::back_inserter(res));
+
+ CheckCursorEmpty(cur);
+
+ BOOST_REQUIRE_EQUAL(res.size(), 2);
+
+ for (int i = 0; i < 2; i++)
+ {
+ cache::CacheEntry<K, V> entry = res[i];
+
+ if (entry.GetKey() == key1)
+ BOOST_CHECK(entry.GetValue() == value1);
+ else if (entry.GetKey() == key2)
+ BOOST_CHECK(entry.GetValue() == value2);
+ else
+ BOOST_FAIL("Unexpected entry.");
+ }
+ }
+
+ /**
+ * Make custom test value.
+ *
+ * @param seed Seed to generate value.
+ */
+ IGNORE_SIGNED_OVERFLOW
+ ignite::TestType MakeCustomTestValue(int64_t seed)
+ {
+ ignite::TestType val;
+
+ val.i8Field = static_cast<int8_t>(seed);
+ val.i16Field = static_cast<int16_t>(2 * seed);
+ val.i32Field = static_cast<int32_t>(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) % (24 * 60 * 60 * 1000));
+ val.timestampField = ignite::Timestamp(128341594123 * seed);
+
+ val.i8ArrayField.push_back(static_cast<int8_t>(9 * seed));
+ val.i8ArrayField.push_back(static_cast<int8_t>(6 * seed));
+ val.i8ArrayField.push_back(static_cast<int8_t>(3 * seed));
+ val.i8ArrayField.push_back(static_cast<int8_t>(42 * seed));
+
+ return val;
+ }
+
+} // anonymous namespace
+
+BOOST_FIXTURE_TEST_SUITE(ScanQueryTestSuite, ScanQueryTestSuiteFixture)
+
+/**
+ * Test scan query.
+ */
+BOOST_AUTO_TEST_CASE(TestScanQuery)
+{
+ // Test query with no results.
+ ScanQuery qry;
+
+ QueryCursor<int64_t, ignite::TestType> cursor = cacheAllFields.Query(qry);
+ CheckCursorEmpty(cursor);
+
+ cursor = cacheAllFields.Query(qry);
+ CheckEmptyGetAll(cursor);
+
+ cursor = cacheAllFields.Query(qry);
+ CheckEmptyGetAllIter(cursor);
+
+ int64_t key1 = 1;
+ ignite::TestType val1 = MakeCustomTestValue(1);
+
+ // Test simple query.
+ cacheAllFields.Put(key1, val1);
+
+ cursor = cacheAllFields.Query(qry);
+ CheckSingle(cursor, key1, val1);
+
+ cursor = cacheAllFields.Query(qry);
+ CheckSingleGetAll(cursor, key1, val1);
+
+ cursor = cacheAllFields.Query(qry);
+ CheckSingleGetAllIter(cursor, key1, val1);
+
+ int64_t key2 = 2;
+ ignite::TestType val2 = MakeCustomTestValue(2);
+
+ // Test query returning multiple entries.
+ cacheAllFields.Put(key2, val2);
+
+ cursor = cacheAllFields.Query(qry);
+ CheckMultiple(cursor, key1, val1, key2, val2);
+
+ cursor = cacheAllFields.Query(qry);
+ CheckMultipleGetAll(cursor, key1, val1, key2, val2);
+
+ cursor = cacheAllFields.Query(qry);
+ CheckMultipleGetAllIter(cursor, key1, val1, key2, val2);
+}
+
+/**
+ * Test scan query over partitions.
+ */
+BOOST_AUTO_TEST_CASE(TestScanQueryPartitioned)
+{
+ // Populate cache with data.
+ int32_t partCnt = 256; // Defined in configuration explicitly.
+ int64_t entryCnt = 1000; // Should be greater than partCnt.
+
+ for (int64_t i = 0; i < entryCnt; i++)
+ cacheAllFields.Put(i, MakeCustomTestValue(i));
+
+ // Iterate over all partitions and collect data.
+ std::set<int64_t> keys;
+
+ for (int32_t i = 0; i < partCnt; i++)
+ {
+ ScanQuery qry;
+ qry.SetPartition(i);
+
+ QueryCursor<int64_t, ignite::TestType> cur = cacheAllFields.Query(qry);
+
+ while (cur.HasNext())
+ {
+ cache::CacheEntry<int64_t, ignite::TestType> entry = cur.GetNext();
+
+ int64_t key = entry.GetKey();
+ keys.insert(key);
+
+ BOOST_REQUIRE(entry.GetValue() == MakeCustomTestValue(key));
+ }
+ }
+
+ // Ensure that all keys were read.
+ BOOST_CHECK_EQUAL(keys.size(), entryCnt);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/platforms/cpp/thin-client/CMakeLists.txt b/modules/platforms/cpp/thin-client/CMakeLists.txt
index 20d52eca542..f6a742f97e3 100644
--- a/modules/platforms/cpp/thin-client/CMakeLists.txt
+++ b/modules/platforms/cpp/thin-client/CMakeLists.txt
@@ -41,6 +41,7 @@ set(SOURCES src/impl/data_channel.cpp
src/impl/transactions/transactions_proxy.cpp
src/compute/compute_client.cpp
src/ignite_client.cpp
+ src/cache/query/query_cursor_proxy.cpp
src/cache/query/query_fields_cursor.cpp
src/cache/query/query_fields_row.cpp)
diff --git a/modules/platforms/cpp/thin-client/include/ignite/impl/thin/cache/cache_client_proxy.h b/modules/platforms/cpp/thin-client/include/ignite/impl/thin/cache/cache_client_proxy.h
index 01ee3953ae2..83f71023292 100644
--- a/modules/platforms/cpp/thin-client/include/ignite/impl/thin/cache/cache_client_proxy.h
+++ b/modules/platforms/cpp/thin-client/include/ignite/impl/thin/cache/cache_client_proxy.h
@@ -21,9 +21,11 @@
#include <ignite/common/concurrent.h>
#include <ignite/thin/cache/query/query_fields_cursor.h>
+#include <ignite/thin/cache/query/query_scan.h>
#include <ignite/thin/cache/query/query_sql_fields.h>
#include <ignite/impl/thin/cache/continuous/continuous_query_client_holder.h>
+#include <ignite/impl/thin/cache/query/query_cursor_proxy.h>
namespace ignite
{
@@ -59,7 +61,7 @@ namespace ignite
/**
* Constructor.
*/
- CacheClientProxy(const common::concurrent::SharedPointer<void>& impl) :
+ explicit CacheClientProxy(const common::concurrent::SharedPointer<void>& impl) :
impl(impl)
{
// No-op.
@@ -299,6 +301,14 @@ namespace ignite
ignite::thin::cache::query::QueryFieldsCursor Query(
const ignite::thin::cache::query::SqlFieldsQuery& qry);
+ /**
+ * Perform scan query.
+ *
+ * @param qry Query.
+ * @return Query cursor proxy.
+ */
+ query::QueryCursorProxy Query(const ignite::thin::cache::query::ScanQuery& qry);
+
/**
* Starts the continuous query execution
*
diff --git a/modules/platforms/cpp/thin-client/include/ignite/impl/thin/cache/query/query_cursor_proxy.h b/modules/platforms/cpp/thin-client/include/ignite/impl/thin/cache/query/query_cursor_proxy.h
new file mode 100644
index 00000000000..3953bb2b7d3
--- /dev/null
+++ b/modules/platforms/cpp/thin-client/include/ignite/impl/thin/cache/query/query_cursor_proxy.h
@@ -0,0 +1,88 @@
+/*
+ * 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_CURSOR_PROXY
+#define _IGNITE_IMPL_THIN_CACHE_QUERY_QUERY_CURSOR_PROXY
+
+#include <vector>
+
+#include <ignite/common/concurrent.h>
+#include <ignite/ignite_error.h>
+
+#include <ignite/thin/cache/cache_entry.h>
+#include <ignite/impl/thin/readable.h>
+
+namespace ignite
+{
+ namespace impl
+ {
+ namespace thin
+ {
+ namespace cache
+ {
+ namespace query
+ {
+ /**
+ * Query cursor class implementation.
+ */
+ class IGNITE_IMPORT_EXPORT QueryCursorProxy
+ {
+ public:
+ /**
+ * Default constructor.
+ */
+ QueryCursorProxy()
+ {
+ // No-op.
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param impl Implementation.
+ */
+ explicit QueryCursorProxy(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() const;
+
+ /**
+ * Get next entry.
+ *
+ * @param entry Entry.
+ *
+ * @throw IgniteError class instance in case of failure.
+ */
+ void GetNext(Readable& entry);
+
+ private:
+ /** Implementation delegate. */
+ common::concurrent::SharedPointer<void> impl;
+ };
+ }
+ }
+ }
+ }
+}
+
+#endif //_IGNITE_IMPL_THIN_CACHE_QUERY_QUERY_CURSOR_PROXY
diff --git a/modules/platforms/cpp/thin-client/include/ignite/impl/thin/readable.h b/modules/platforms/cpp/thin-client/include/ignite/impl/thin/readable.h
index 2045c447cca..2caac1de839 100644
--- a/modules/platforms/cpp/thin-client/include/ignite/impl/thin/readable.h
+++ b/modules/platforms/cpp/thin-client/include/ignite/impl/thin/readable.h
@@ -18,7 +18,10 @@
#ifndef _IGNITE_IMPL_THIN_READABLE
#define _IGNITE_IMPL_THIN_READABLE
+#include <utility>
+
#include <ignite/binary/binary_raw_reader.h>
+#include <ignite/thin/cache/cache_entry.h>
namespace ignite
{
@@ -88,36 +91,131 @@ namespace ignite
}
private:
- /** Data router. */
+ /** Value reference. */
ValueType& value;
};
+ /**
+ * Implementation of the Readable class for the std::pair type.
+ */
+ template<typename T1, typename T2>
+ class ReadableImpl< std::pair<T1, T2> > : public Readable
+ {
+ public:
+ /** First value type. */
+ typedef T1 ValueType1;
+
+ /** Second value type. */
+ typedef T2 ValueType2;
+
+ /**
+ * Constructor.
+ *
+ * @param value Value.
+ */
+ ReadableImpl(std::pair<ValueType1, ValueType2>& pair) :
+ pair(pair)
+ {
+ // No-op.
+ }
+
+ /**
+ * Destructor.
+ */
+ virtual ~ReadableImpl()
+ {
+ // No-op.
+ }
+
+ /**
+ * Read value using reader.
+ *
+ * @param reader Reader to use.
+ */
+ virtual void Read(binary::BinaryReaderImpl& reader)
+ {
+ reader.ReadTopObject<ValueType1>(pair.first);
+ reader.ReadTopObject<ValueType2>(pair.second);
+ }
+
+ private:
+ /** Pair reference. */
+ std::pair<ValueType1, ValueType2>& pair;
+ };
+
+ /**
+ * Implementation of the Readable class for the CacheEntry type.
+ */
+ template<typename K, typename V>
+ class ReadableImpl< ignite::thin::cache::CacheEntry<K, V> > : public Readable
+ {
+ public:
+ /** Key type. */
+ typedef K KeyType;
+
+ /** Value type. */
+ typedef V ValueType;
+
+ /**
+ * Constructor.
+ *
+ * @param value Value.
+ */
+ ReadableImpl(ignite::thin::cache::CacheEntry<KeyType, ValueType>& entry) :
+ entry(entry)
+ {
+ // No-op.
+ }
+
+ /**
+ * Destructor.
+ */
+ virtual ~ReadableImpl()
+ {
+ // No-op.
+ }
+
+ /**
+ * Read value using reader.
+ *
+ * @param reader Reader to use.
+ */
+ virtual void Read(binary::BinaryReaderImpl& reader)
+ {
+ reader.ReadTopObject<KeyType>(entry.key);
+ reader.ReadTopObject<ValueType>(entry.val);
+ }
+
+ private:
+ /** Entry reference. */
+ ignite::thin::cache::CacheEntry<KeyType, ValueType>& entry;
+ };
+
/**
* Implementation of Readable interface for map.
*
- * @tparam T1 Type of the first element in the pair.
- * @tparam T2 Type of the second element in the pair.
+ * @tparam T Type for the element in the container.
* @tparam I Out iterator.
*/
- template<typename T1, typename T2, typename I>
- class ReadableMapImpl : public Readable
+ template<typename T, typename I>
+ class ReadableContainerImpl : public Readable
{
public:
- /** Type of the first element in the pair. */
- typedef T1 ElementType1;
+ /** Type of the element in the containers. */
+ typedef T ValueType;
- /** Type of the second element in the pair. */
- typedef T2 ElementType2;
-
/** Type of the iterator. */
typedef I IteratorType;
+ /** Readable type for the element in the containers. */
+ typedef ReadableImpl<ValueType> ReadableType;
+
/**
* Constructor.
*
* @param iter Iterator.
*/
- ReadableMapImpl(IteratorType iter) :
+ ReadableContainerImpl(IteratorType iter) :
iter(iter)
{
// No-op.
@@ -126,7 +224,7 @@ namespace ignite
/**
* Destructor.
*/
- virtual ~ReadableMapImpl()
+ virtual ~ReadableContainerImpl()
{
// No-op.
}
@@ -144,13 +242,13 @@ namespace ignite
for (int32_t i = 0; i < cnt; ++i)
{
- std::pair<ElementType1, ElementType2> pair;
+ ValueType value;
- reader.ReadTopObject<ElementType1>(pair.first);
- reader.ReadTopObject<ElementType2>(pair.second);
+ ReadableType readable(value);
- iter = pair;
+ readable.Read(reader);
+ *iter = value;
++iter;
}
}
diff --git a/modules/platforms/cpp/thin-client/include/ignite/thin/cache/cache_client.h b/modules/platforms/cpp/thin-client/include/ignite/thin/cache/cache_client.h
index 544010e4926..3ad14db3145 100644
--- a/modules/platforms/cpp/thin-client/include/ignite/thin/cache/cache_client.h
+++ b/modules/platforms/cpp/thin-client/include/ignite/thin/cache/cache_client.h
@@ -25,7 +25,9 @@
#include <ignite/common/concurrent.h>
+#include <ignite/thin/cache/query/query_cursor.h>
#include <ignite/thin/cache/query/query_fields_cursor.h>
+#include <ignite/thin/cache/query/query_scan.h>
#include <ignite/thin/cache/query/query_sql_fields.h>
#include <ignite/thin/cache/query/continuous/continuous_query_client.h>
#include <ignite/thin/cache/query/continuous/continuous_query_handle.h>
@@ -181,7 +183,7 @@ namespace ignite
void GetAll(InIter begin, InIter end, OutIter dst)
{
impl::thin::WritableSetImpl<K, InIter> wrSeq(begin, end);
- impl::thin::ReadableMapImpl<K, V, OutIter> rdSeq(dst);
+ impl::thin::ReadableContainerImpl< std::pair<K, V>, OutIter> rdSeq(dst);
proxy.GetAll(wrSeq, rdSeq);
}
@@ -599,6 +601,17 @@ namespace ignite
return proxy.Query(qry);
}
+ /**
+ * Perform scan query.
+ *
+ * @param qry Query.
+ * @return Query cursor.
+ */
+ query::QueryCursor<KeyType, ValueType> Query(const query::ScanQuery& qry)
+ {
+ return query::QueryCursor<KeyType, ValueType>(proxy.Query(qry));
+ }
+
/**
* Starts the continuous query execution
*
diff --git a/modules/platforms/cpp/thin-client/include/ignite/thin/cache/cache_entry.h b/modules/platforms/cpp/thin-client/include/ignite/thin/cache/cache_entry.h
index ef52814b5ab..cdaf9cac648 100644
--- a/modules/platforms/cpp/thin-client/include/ignite/thin/cache/cache_entry.h
+++ b/modules/platforms/cpp/thin-client/include/ignite/thin/cache/cache_entry.h
@@ -28,6 +28,14 @@
namespace ignite
{
+ namespace impl
+ {
+ namespace thin
+ {
+ template<typename T>
+ class ReadableImpl;
+ }
+ }
namespace thin
{
namespace cache
@@ -41,6 +49,7 @@ namespace ignite
template<typename K, typename V>
class CacheEntry
{
+ friend class ignite::impl::thin::ReadableImpl< ignite::thin::cache::CacheEntry<K, V> >;
public:
/**
* Default constructor.
diff --git a/modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_cursor.h b/modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_cursor.h
new file mode 100644
index 00000000000..e50cc83e236
--- /dev/null
+++ b/modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_cursor.h
@@ -0,0 +1,151 @@
+/*
+ * 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::QueryCursor class template.
+ */
+
+#ifndef _IGNITE_THIN_CACHE_QUERY_QUERY_CURSOR
+#define _IGNITE_THIN_CACHE_QUERY_QUERY_CURSOR
+
+#include <vector>
+
+#include <ignite/common/concurrent.h>
+#include <ignite/ignite_error.h>
+
+#include <ignite/thin/cache/cache_entry.h>
+
+#include <ignite/impl/thin/readable.h>
+#include <ignite/impl/thin/cache/query/query_cursor_proxy.h>
+
+namespace ignite
+{
+ namespace thin
+ {
+ namespace cache
+ {
+ namespace query
+ {
+ /**
+ * Query cursor class template.
+ *
+ * Both key and value types should be default-constructable, copy-constructable
+ * and assignable. Also BinaryType class template should be specialized for both
+ * types.
+ *
+ * This class is 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 will be released automatically once all
+ * the instances are destructed.
+ */
+ template<typename K, typename V>
+ class QueryCursor
+ {
+ public:
+ /**
+ * Default constructor.
+ */
+ QueryCursor()
+ {
+ // No-op.
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param impl Implementation.
+ */
+ explicit QueryCursor(const impl::thin::cache::query::QueryCursorProxy& impl) :
+ impl(impl)
+ {
+ // No-op.
+ }
+
+ /**
+ * Check whether next entry exists.
+ *
+ * @return True if next entry exists.
+ *
+ * @throw IgniteError class instance in case of failure.
+ */
+ bool HasNext() const
+ {
+ return impl.HasNext();
+ }
+
+ /**
+ * Get next entry.
+ *
+ * @return Next entry.
+ *
+ * @throw IgniteError class instance in case of failure.
+ */
+ CacheEntry<K, V> GetNext()
+ {
+ CacheEntry<K, V> entry;
+ impl::thin::ReadableImpl< CacheEntry<K, V> > readable(entry);
+
+ impl.GetNext(readable);
+
+ return entry;
+ }
+
+ /**
+ * Get all entries.
+ *
+ * @param res Vector where query entries will be stored.
+ *
+ * @throw IgniteError class instance in case of failure.
+ */
+ void GetAll(std::vector<CacheEntry<K, V> >& res)
+ {
+ res.clear();
+ GetAll(std::inserter(res, res.end()));
+ }
+
+ /**
+ * Get all entries.
+ *
+ * @param iter Output iterator.
+ *
+ * @throw IgniteError class instance in case of failure.
+ */
+ template<typename OutIter>
+ void GetAll(OutIter iter)
+ {
+ impl::thin::ReadableContainerImpl< CacheEntry<K, V>, OutIter > collection(iter);
+
+ while (HasNext())
+ {
+ *iter = GetNext();
+ ++iter;
+ }
+ }
+
+ private:
+ /** Implementation delegate. */
+ impl::thin::cache::query::QueryCursorProxy impl;
+ };
+ }
+ }
+
+
+ }
+}
+
+#endif //_IGNITE_THIN_CACHE_QUERY_QUERY_CURSOR
diff --git a/modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_scan.h b/modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_scan.h
new file mode 100644
index 00000000000..1d45806777d
--- /dev/null
+++ b/modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_scan.h
@@ -0,0 +1,144 @@
+/*
+ * 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::ScanQuery class.
+ */
+
+#ifndef _IGNITE_THIN_CACHE_QUERY_QUERY_SCAN
+#define _IGNITE_THIN_CACHE_QUERY_QUERY_SCAN
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include <ignite/impl/thin/copyable_writable.h>
+
+namespace ignite
+{
+ namespace impl
+ {
+ namespace thin
+ {
+ // Forward declaration
+ class ScanQueryRequest;
+ }
+ }
+
+ namespace thin
+ {
+ namespace cache
+ {
+ namespace query
+ {
+ /**
+ * Scan query.
+ */
+ class ScanQuery
+ {
+ public:
+ friend class ScanQueryRequest;
+
+ /**
+ * Default constructor.
+ */
+ ScanQuery() : part(-1), pageSize(1024), loc(false)
+ {
+ // No-op.
+ }
+
+ /**
+ * Get partition to scan.
+ *
+ * @return Partition to scan.
+ */
+ int32_t GetPartition() const
+ {
+ return part;
+ }
+
+ /**
+ * Set partition to scan.
+ *
+ * @param partition Partition to scan.
+ */
+ void SetPartition(int32_t partition)
+ {
+ this->part = partition;
+ }
+
+ /**
+ * Get page size.
+ *
+ * @return Page size.
+ */
+ int32_t GetPageSize() const
+ {
+ return pageSize;
+ }
+
+ /**
+ * Set the size of the result page.
+ *
+ * @param resultPageSize Result page size.
+ */
+ void SetPageSize(int32_t resultPageSize)
+ {
+ this->pageSize = resultPageSize;
+ }
+
+ /**
+ * Get local flag.
+ *
+ * @return Local flag. If true, query will be executed only on the single connected node,
+ * so only local entries will be returned as query result. Should be used with caution because
+ * if the client connected to multiple nodes, a single node will be selected randomly.
+ */
+ bool IsLocal() const
+ {
+ return loc;
+ }
+
+ /**
+ * Set local flag.
+ *
+ * @param localScan Local flag. If true, query will be executed only on the single connected node,
+ * so only local entries will be returned as query result. Should be used with caution because
+ * if the client connected to multiple nodes, a single node will be selected randomly.
+ */
+ void SetLocal(bool localScan)
+ {
+ loc = localScan;
+ }
+
+ private:
+ /** Partition. */
+ int32_t part;
+
+ /** Page size. */
+ int32_t pageSize;
+
+ /** Local flag. */
+ bool loc;
+ };
+ }
+ }
+ }
+}
+
+#endif //_IGNITE_THIN_CACHE_QUERY_QUERY_SCAN
diff --git a/modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_sql_fields.h b/modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_sql_fields.h
index d3501386664..e9e0843a801 100644
--- a/modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_sql_fields.h
+++ b/modules/platforms/cpp/thin-client/include/ignite/thin/cache/query/query_sql_fields.h
@@ -259,7 +259,9 @@ namespace ignite
/**
* Get local flag.
*
- * @return Local flag.
+ * @return Local flag. If true, query will be executed only on the single connected node,
+ * so only local entries will be returned as query result. Should be used with caution because
+ * if the client connected to multiple nodes, a single node will be selected randomly.
*/
bool IsLocal() const
{
@@ -269,7 +271,9 @@ namespace ignite
/**
* Set local flag.
*
- * @param loc Local flag.
+ * @param loc Local flag. If true, query will be executed only on the single connected node,
+ * so only local entries will be returned as query result. Should be used with caution because
+ * if the client connected to multiple nodes, a single node will be selected randomly.
*/
void SetLocal(bool loc)
{
diff --git a/modules/platforms/cpp/thin-client/src/cache/query/query_cursor_proxy.cpp b/modules/platforms/cpp/thin-client/src/cache/query/query_cursor_proxy.cpp
new file mode 100644
index 00000000000..f62af78de99
--- /dev/null
+++ b/modules/platforms/cpp/thin-client/src/cache/query/query_cursor_proxy.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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 <ignite/impl/thin/cache/query/query_cursor_proxy.h>
+
+#include "impl/cache/query/query_cursor_impl.h"
+
+namespace
+{
+ using namespace ignite::common::concurrent;
+ using namespace ignite::impl::thin::cache::query;
+
+ QueryCursorImpl& GetQueryCursorImpl(SharedPointer<void>& ptr)
+ {
+ return *reinterpret_cast<QueryCursorImpl*>(ptr.Get());
+ }
+
+ const QueryCursorImpl& GetQueryCursorImpl(const SharedPointer<void>& ptr)
+ {
+ return *reinterpret_cast<const QueryCursorImpl*>(ptr.Get());
+ }
+}
+
+namespace ignite
+{
+ namespace impl
+ {
+ namespace thin
+ {
+ namespace cache
+ {
+ namespace query
+ {
+ QueryCursorProxy::QueryCursorProxy(const common::concurrent::SharedPointer<void> &impl) :
+ impl(impl)
+ {
+ // No-op.
+ }
+
+ bool QueryCursorProxy::HasNext() const
+ {
+ return GetQueryCursorImpl(impl).HasNext();
+ }
+
+ void QueryCursorProxy::GetNext(Readable& entry)
+ {
+ GetQueryCursorImpl(impl).GetNext(entry);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/modules/platforms/cpp/thin-client/src/impl/cache/cache_client_impl.cpp b/modules/platforms/cpp/thin-client/src/impl/cache/cache_client_impl.cpp
index 100645af911..3340e37d344 100644
--- a/modules/platforms/cpp/thin-client/src/impl/cache/cache_client_impl.cpp
+++ b/modules/platforms/cpp/thin-client/src/impl/cache/cache_client_impl.cpp
@@ -369,6 +369,24 @@ namespace ignite
return cursorImpl;
}
+ query::SP_QueryCursorImpl CacheClientImpl::Query(const ignite::thin::cache::query::ScanQuery& qry)
+ {
+ ScanQueryRequest req(id, qry);
+ ScanQueryResponse rsp;
+
+ SP_DataChannel channel = SyncMessage(req, rsp);
+
+ query::SP_QueryCursorImpl cursor(
+ new query::QueryCursorImpl(
+ rsp.GetCursorId(),
+ rsp.GetCursorPage(),
+ channel,
+ router.Get()->GetIoTimeout()
+ ));
+
+ return cursor;
+ }
+
query::continuous::SP_ContinuousQueryHandleClientImpl CacheClientImpl::QueryContinuous(
const query::continuous::SP_ContinuousQueryClientHolderBase& continuousQuery)
{
diff --git a/modules/platforms/cpp/thin-client/src/impl/cache/cache_client_impl.h b/modules/platforms/cpp/thin-client/src/impl/cache/cache_client_impl.h
index 4c82592a020..5e9b5fb882d 100644
--- a/modules/platforms/cpp/thin-client/src/impl/cache/cache_client_impl.h
+++ b/modules/platforms/cpp/thin-client/src/impl/cache/cache_client_impl.h
@@ -22,11 +22,13 @@
#include <string>
#include <ignite/thin/cache/query/query_sql_fields.h>
+#include <ignite/thin/cache/query/query_scan.h>
#include <ignite/impl/thin/cache/continuous/continuous_query_client_holder.h>
#include "impl/data_router.h"
#include "impl/transactions/transactions_impl.h"
+#include "impl/cache/query/query_cursor_impl.h"
#include "impl/cache/query/query_fields_cursor_impl.h"
#include "impl/cache/query/continuous/continuous_query_handle_impl.h"
@@ -301,6 +303,14 @@ namespace ignite
*/
query::SP_QueryFieldsCursorImpl Query(const ignite::thin::cache::query::SqlFieldsQuery &qry);
+ /**
+ * Perform scan query.
+ *
+ * @param qry Query.
+ * @return Query cursor proxy.
+ */
+ query::SP_QueryCursorImpl Query(const ignite::thin::cache::query::ScanQuery& qry);
+
/**
* Starts the continuous query execution
*
diff --git a/modules/platforms/cpp/thin-client/src/impl/cache/cache_client_proxy.cpp b/modules/platforms/cpp/thin-client/src/impl/cache/cache_client_proxy.cpp
index eab6ba000eb..f97c1072409 100644
--- a/modules/platforms/cpp/thin-client/src/impl/cache/cache_client_proxy.cpp
+++ b/modules/platforms/cpp/thin-client/src/impl/cache/cache_client_proxy.cpp
@@ -21,12 +21,10 @@
#include <impl/cache/cache_client_impl.h>
using namespace ignite::impl::thin;
+using namespace ignite::thin::cache::query;
+using namespace ignite::thin::cache::query::continuous;
using namespace cache;
-using ignite::thin::cache::query::SqlFieldsQuery;
-using ignite::thin::cache::query::QueryFieldsCursor;
-using ignite::thin::cache::query::continuous::ContinuousQueryHandleClient;
-
namespace
{
using namespace ignite::common::concurrent;
@@ -156,11 +154,18 @@ namespace ignite
GetCacheImpl(impl).GetAndPutIfAbsent(key, valIn, valOut);
}
- QueryFieldsCursor CacheClientProxy::Query(const ignite::thin::cache::query::SqlFieldsQuery &qry)
+ QueryFieldsCursor CacheClientProxy::Query(const SqlFieldsQuery &qry)
{
query::SP_QueryFieldsCursorImpl cursorImpl = GetCacheImpl(impl).Query(qry);
- return ignite::thin::cache::query::QueryFieldsCursor(cursorImpl);
+ return QueryFieldsCursor(cursorImpl);
+ }
+
+ query::QueryCursorProxy CacheClientProxy::Query(const ScanQuery& qry)
+ {
+ query::SP_QueryCursorImpl cursorImpl = GetCacheImpl(impl).Query(qry);
+
+ return query::QueryCursorProxy(cursorImpl);
}
ContinuousQueryHandleClient CacheClientProxy::QueryContinuous(
diff --git a/modules/platforms/cpp/thin-client/src/impl/cache/query/query_fields_cursor_impl.h b/modules/platforms/cpp/thin-client/src/impl/cache/query/query_cursor_impl.h
similarity index 65%
copy from modules/platforms/cpp/thin-client/src/impl/cache/query/query_fields_cursor_impl.h
copy to modules/platforms/cpp/thin-client/src/impl/cache/query/query_cursor_impl.h
index 6e03c71a80c..027609f5659 100644
--- a/modules/platforms/cpp/thin-client/src/impl/cache/query/query_fields_cursor_impl.h
+++ b/modules/platforms/cpp/thin-client/src/impl/cache/query/query_cursor_impl.h
@@ -15,15 +15,12 @@
* limitations under the License.
*/
-#ifndef _IGNITE_IMPL_THIN_CACHE_QUERY_QUERY_FIELDS_CURSOR_IMPL
-#define _IGNITE_IMPL_THIN_CACHE_QUERY_QUERY_FIELDS_CURSOR_IMPL
+#ifndef _IGNITE_IMPL_THIN_CACHE_QUERY_QUERY_CURSOR_IMPL
+#define _IGNITE_IMPL_THIN_CACHE_QUERY_QUERY_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"
@@ -38,9 +35,9 @@ namespace ignite
namespace query
{
/**
- * Query Fields Cursor Implementation.
+ * Query Cursor Implementation.
*/
- class QueryFieldsCursorImpl
+ class QueryCursorImpl
{
public:
/**
@@ -52,18 +49,16 @@ namespace ignite
* @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 &cursorPage,
- const SP_DataChannel& channel,
- int32_t timeout) :
+ QueryCursorImpl(
+ int64_t id,
+ const SP_CursorPage &cursorPage,
+ const SP_DataChannel& channel,
+ int32_t timeout) :
id(id),
- columns(columns),
page(cursorPage),
channel(channel),
timeout(timeout),
- currentRow(0),
+ currentElement(0),
stream(page.Get()->GetMemory()),
reader(&stream),
endReached(false)
@@ -76,7 +71,7 @@ namespace ignite
/**
* Destructor.
*/
- virtual ~QueryFieldsCursorImpl()
+ virtual ~QueryCursorImpl()
{
// No-op.
}
@@ -88,7 +83,7 @@ namespace ignite
*
* @throw IgniteError class instance in case of failure.
*/
- bool HasNext()
+ bool HasNext() const
{
return !endReached;
}
@@ -96,13 +91,11 @@ namespace ignite
/**
* Get next entry.
*
- * This method should only be used on the valid instance.
- *
- * @return Next entry.
+ * @param entry Entry.
*
* @throw IgniteError class instance in case of failure.
*/
- ignite::thin::cache::query::QueryFieldsRow GetNext()
+ void GetNext(Readable& entry)
{
if (!HasNext())
throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, "The cursor is empty");
@@ -110,25 +103,11 @@ namespace ignite
if (IsUpdateNeeded())
Update();
- SP_QueryFieldsRowImpl rowImpl(
- new QueryFieldsRowImpl(
- static_cast<int32_t>(columns.size()),
- page,
- stream.Position()));
+ entry.Read(reader);
- SkipRow();
+ ++currentElement;
- return ignite::thin::cache::query::QueryFieldsRow(rowImpl);
- }
-
- /**
- * Get column names.
- *
- * @return Column names.
- */
- const std::vector<std::string>& GetColumns() const
- {
- return columns;
+ CheckEnd();
}
private:
@@ -147,42 +126,30 @@ namespace ignite
*/
void Update()
{
- SqlFieldsCursorGetPageRequest req(id);
- SqlFieldsCursorGetPageResponse rsp;
+ QueryCursorGetPageRequest<MessageType::QUERY_SCAN_CURSOR_GET_PAGE> req(id);
+ QueryCursorGetPageResponse rsp;
DataChannel* channel0 = channel.Get();
if (!channel0)
- throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, "Connection is not established");
+ throw IgniteError(IgniteError::IGNITE_ERR_GENERIC,
+ "Connection is not established");
channel0->SyncMessage(req, rsp, timeout);
page = rsp.GetCursorPage();
- currentRow = 0;
+ currentElement = 0;
stream = interop::InteropInputStream(page.Get()->GetMemory());
stream.Position(page.Get()->GetStartPos());
}
- /**
- * Skip position to the next row.
- */
- void SkipRow()
- {
- for (size_t i = 0; i < columns.size(); ++i)
- reader.Skip();
-
- ++currentRow;
-
- CheckEnd();
- }
-
/**
* Check whether end is reached.
*/
void CheckEnd()
{
- if (currentRow == page.Get()->GetRowNum())
+ if (currentElement == page.Get()->GetRowNum())
{
bool hasNextPage = reader.ReadBool();
endReached = !hasNextPage;
@@ -194,9 +161,6 @@ namespace ignite
/** Cursor ID. */
int64_t id;
- /** Column names. */
- std::vector<std::string> columns;
-
/** Cursor page. */
SP_CursorPage page;
@@ -206,8 +170,8 @@ namespace ignite
/** Timeout in milliseconds. */
int32_t timeout;
- /** Current row in page. */
- int32_t currentRow;
+ /** Current element in page. */
+ int32_t currentElement;
/** Stream. */
interop::InteropInputStream stream;
@@ -219,11 +183,12 @@ namespace ignite
bool endReached;
};
- typedef common::concurrent::SharedPointer<QueryFieldsCursorImpl> SP_QueryFieldsCursorImpl;
+ /** Shared pointer. */
+ typedef common::concurrent::SharedPointer< QueryCursorImpl > SP_QueryCursorImpl;
}
}
}
}
}
-#endif // _IGNITE_IMPL_THIN_CACHE_QUERY_QUERY_FIELDS_CURSOR_IMPL
+#endif // _IGNITE_IMPL_THIN_CACHE_QUERY_QUERY_CURSOR_IMPL
diff --git a/modules/platforms/cpp/thin-client/src/impl/cache/query/query_fields_cursor_impl.h b/modules/platforms/cpp/thin-client/src/impl/cache/query/query_fields_cursor_impl.h
index 6e03c71a80c..a323043bf29 100644
--- a/modules/platforms/cpp/thin-client/src/impl/cache/query/query_fields_cursor_impl.h
+++ b/modules/platforms/cpp/thin-client/src/impl/cache/query/query_fields_cursor_impl.h
@@ -88,7 +88,7 @@ namespace ignite
*
* @throw IgniteError class instance in case of failure.
*/
- bool HasNext()
+ bool HasNext() const
{
return !endReached;
}
@@ -147,8 +147,8 @@ namespace ignite
*/
void Update()
{
- SqlFieldsCursorGetPageRequest req(id);
- SqlFieldsCursorGetPageResponse rsp;
+ QueryCursorGetPageRequest<MessageType::QUERY_SQL_FIELDS_CURSOR_GET_PAGE> req(id);
+ QueryCursorGetPageResponse rsp;
DataChannel* channel0 = channel.Get();
diff --git a/modules/platforms/cpp/thin-client/src/impl/message.cpp b/modules/platforms/cpp/thin-client/src/impl/message.cpp
index 8390e2d94bb..15982b92eaf 100644
--- a/modules/platforms/cpp/thin-client/src/impl/message.cpp
+++ b/modules/platforms/cpp/thin-client/src/impl/message.cpp
@@ -313,6 +313,35 @@ namespace ignite
value = reader.ReadInt32();
}
+
+ void ScanQueryResponse::ReadOnSuccess(binary::BinaryReaderImpl& reader, const ProtocolVersion&)
+ {
+ ignite::binary::BinaryRawReader rawReader(&reader);
+
+ cursorId = rawReader.ReadInt64();
+
+ cursorPage.Get()->Read(reader);
+ }
+
+ ScanQueryRequest::ScanQueryRequest(int32_t cacheId, const ignite::thin::cache::query::ScanQuery &qry) :
+ CacheRequest<MessageType::QUERY_SCAN>(cacheId, false),
+ qry(qry)
+ {
+ // No-op.
+ }
+
+ void ScanQueryRequest::Write(binary::BinaryWriterImpl &writer, const ProtocolVersion &ver) const
+ {
+ CacheRequest::Write(writer, ver);
+
+ // TODO: IGNITE-16995 Implement a RemoteFilter for ScanQuery
+ writer.WriteNull();
+
+ writer.WriteInt32(qry.GetPageSize());
+ writer.WriteInt32(qry.GetPartition());
+ writer.WriteBool(qry.IsLocal());
+ }
+
SqlFieldsQueryRequest::SqlFieldsQueryRequest(
int32_t cacheId,
const ignite::thin::cache::query::SqlFieldsQuery &qry
@@ -372,12 +401,7 @@ namespace ignite
cursorPage.Get()->Read(reader);
}
- void SqlFieldsCursorGetPageRequest::Write(binary::BinaryWriterImpl& writer, const ProtocolVersion&) const
- {
- writer.WriteInt64(cursorId);
- }
-
- void SqlFieldsCursorGetPageResponse::ReadOnSuccess(binary::BinaryReaderImpl& reader, const ProtocolVersion&)
+ void QueryCursorGetPageResponse::ReadOnSuccess(binary::BinaryReaderImpl& reader, const ProtocolVersion&)
{
cursorPage.Get()->Read(reader);
}
diff --git a/modules/platforms/cpp/thin-client/src/impl/message.h b/modules/platforms/cpp/thin-client/src/impl/message.h
index dad00c701cd..c5ca32e8517 100644
--- a/modules/platforms/cpp/thin-client/src/impl/message.h
+++ b/modules/platforms/cpp/thin-client/src/impl/message.h
@@ -22,6 +22,7 @@
#include <string>
#include <vector>
+#include <ignite/thin/cache/query/query_scan.h>
#include <ignite/thin/cache/query/query_sql_fields.h>
#include <ignite/thin/transactions/transaction_consts.h>
@@ -164,6 +165,12 @@ namespace ignite
/** Cache partitions request. */
CACHE_PARTITIONS = 1101,
+ /** Scan query request. */
+ QUERY_SCAN = 2000,
+
+ /** Scan query get page request. */
+ QUERY_SCAN_CURSOR_GET_PAGE = 2001,
+
/** SQL fields query request. */
QUERY_SQL_FIELDS = 2004,
@@ -961,9 +968,10 @@ namespace ignite
};
/**
- * Cache SQL fields cursor get page request.
+ * Cache query cursor get page request.
*/
- class SqlFieldsCursorGetPageRequest : public RequestAdapter<MessageType::QUERY_SQL_FIELDS_CURSOR_GET_PAGE>
+ template<int16_t OpCode>
+ class QueryCursorGetPageRequest : public RequestAdapter<OpCode>
{
public:
/**
@@ -971,7 +979,7 @@ namespace ignite
*
* @param cursorId Cursor ID.
*/
- explicit SqlFieldsCursorGetPageRequest(int64_t cursorId) :
+ explicit QueryCursorGetPageRequest(int64_t cursorId) :
cursorId(cursorId)
{
// No-op.
@@ -980,7 +988,7 @@ namespace ignite
/**
* Destructor.
*/
- virtual ~SqlFieldsCursorGetPageRequest()
+ virtual ~QueryCursorGetPageRequest()
{
// No-op.
}
@@ -988,15 +996,51 @@ namespace ignite
/**
* Write request using provided writer.
* @param writer Writer.
- * @param ver Version.
*/
- virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion& ver) const;
+ virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion&) const
+ {
+ writer.WriteInt64(cursorId);
+ }
private:
/** Cursor ID. */
const int64_t cursorId;
};
+ /**
+ * Cache scan query request.
+ */
+ class ScanQueryRequest : public CacheRequest<MessageType::QUERY_SCAN>
+ {
+ public:
+ /**
+ * Constructor.
+ *
+ * @param cacheId Cache ID.
+ * @param qry SQL query.
+ */
+ explicit ScanQueryRequest(int32_t cacheId, const ignite::thin::cache::query::ScanQuery &qry);
+
+ /**
+ * Destructor.
+ */
+ virtual ~ScanQueryRequest()
+ {
+ // No-op.
+ }
+
+ /**
+ * Write request using provided writer.
+ * @param writer Writer.
+ * @param ver Version.
+ */
+ virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion& ver) const;
+
+ private:
+ /** Query. */
+ const ignite::thin::cache::query::ScanQuery &qry;
+ };
+
/**
* Continuous query request.
*/
@@ -1481,6 +1525,64 @@ namespace ignite
int32_t value;
};
+ /**
+ * Cache scan query response.
+ */
+ class ScanQueryResponse : public Response
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ ScanQueryResponse() :
+ cursorId(0),
+ cursorPage(new cache::query::CursorPage())
+ {
+ // No-op.
+ }
+
+ /**
+ * Destructor.
+ */
+ virtual ~ScanQueryResponse()
+ {
+ // No-op.
+ }
+
+ /**
+ * Get cursor ID.
+ *
+ * @return Cursor ID.
+ */
+ int64_t GetCursorId() const
+ {
+ return cursorId;
+ }
+
+ /**
+ * Get cursor page.
+ * @return Cursor page.
+ */
+ cache::query::SP_CursorPage GetCursorPage() const
+ {
+ return cursorPage;
+ }
+
+ /**
+ * Read data if response status is ResponseStatus::SUCCESS.
+ *
+ * @param reader Reader.
+ */
+ virtual void ReadOnSuccess(binary::BinaryReaderImpl& reader, const ProtocolVersion&);
+
+ private:
+ /** Cursor ID. */
+ int64_t cursorId;
+
+ /** Cursor Page. */
+ cache::query::SP_CursorPage cursorPage;
+ };
+
/**
* Cache SQL fields query response.
*/
@@ -1553,15 +1655,15 @@ namespace ignite
};
/**
- * Cache SQL fields cursor get page response.
+ * Query cursor get page response.
*/
- class SqlFieldsCursorGetPageResponse : public Response
+ class QueryCursorGetPageResponse : public Response
{
public:
/**
* Constructor.
*/
- SqlFieldsCursorGetPageResponse() :
+ QueryCursorGetPageResponse() :
cursorPage(new cache::query::CursorPage())
{
// No-op.
@@ -1570,7 +1672,7 @@ namespace ignite
/**
* Destructor.
*/
- virtual ~SqlFieldsCursorGetPageResponse()
+ virtual ~QueryCursorGetPageResponse()
{
// No-op.
}