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-1770 Commit: 667c2e65de65cf6486b7ef56bb03c85b02ebee66 Parents: 09339de Author: isapego <[email protected]> Authored: Fri Oct 30 12:20:54 2015 +0300 Committer: vozerov-gridgain <[email protected]> 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.
