blob: 457e179a139ecebde3378395bd108e33d72182bf [file] [log] [blame]
/*
* 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 <stdint.h>
#include <sstream>
#include <iterator>
#include <boost/test/unit_test.hpp>
#include <ignite/common/utils.h>
#include "ignite/cache/cache.h"
#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"
#include "ignite/test_utils.h"
#include "teamcity_messages.h"
using namespace boost::unit_test;
using namespace ignite;
using namespace ignite::cache;
using namespace ignite::cache::query;
using namespace ignite::common;
using ignite::impl::binary::BinaryUtils;
/**
* Person class for query tests.
*/
class QueryPerson
{
public:
/**
* Constructor.
*/
QueryPerson() :
name(NULL),
age(0),
birthday(),
recordCreated()
{
// No-op.
}
/**
* Constructor.
*
* @param name Name.
* @param age Age.
*/
QueryPerson(const std::string& name, int age,
const Date& birthday, const Timestamp& recordCreated) :
name(CopyChars(name.c_str())),
age(age),
birthday(birthday),
recordCreated(recordCreated)
{
// No-op.
}
/**
* Copy constructor.
*
* @param other Other instance.
*/
QueryPerson(const QueryPerson& other) :
name(CopyChars(other.name)),
age(other.age),
birthday(other.birthday),
recordCreated(other.recordCreated)
{
// No-op.
}
/**
* Assignment operator.
*
* @param other Other instance.
* @return This instance.
*/
QueryPerson& operator=(const QueryPerson& other)
{
using std::swap;
if (&other != this)
{
QueryPerson tmp(other);
swap(name, tmp.name);
swap(age, tmp.age);
swap(birthday, tmp.birthday);
swap(recordCreated, tmp.recordCreated);
}
return *this;
}
/**
* Destructor.
*/
~QueryPerson()
{
ReleaseChars(name);
}
/**
* Get name.
*
* @return Name.
*/
std::string GetName() const
{
return name ? std::string(name) : std::string();
}
/**
* Get age.
*
* @return Age.
*/
int32_t GetAge() const
{
return age;
}
/**
* Get birthday.
*
* @return Birthday date.
*/
const Date& GetBirthday() const
{
return birthday;
}
/**
* Get creation time.
*
* @return Creation time.
*/
const Timestamp& GetCreationTime() const
{
return recordCreated;
}
/**
* @return true if objects are equal.
*/
friend bool operator==(QueryPerson const& lhs, QueryPerson const& rhs)
{
return lhs.GetName() == rhs.GetName() && lhs.GetAge() == rhs.GetAge() &&
lhs.GetBirthday() == rhs.GetBirthday() && lhs.GetCreationTime() == rhs.GetCreationTime();
}
/**
* Outputs the object to stream.
*
* @return Stream.
*/
friend std::ostream& operator<<(std::ostream& str, QueryPerson const& obj)
{
str << "QueryPerson::name: " << obj.GetName()
<< "QueryPerson::age: " << obj.GetAge()
<< "QueryPerson::birthday: " << obj.GetBirthday().GetMilliseconds()
<< "QueryPerson::recordCreated: " << obj.GetCreationTime().GetSeconds() << "." << obj.GetCreationTime().GetSecondFraction();
return str;
}
private:
/** Name. */
char* name;
/** Age. */
int age;
/** Birthday. */
Date birthday;
/** Record creation timestamp. */
Timestamp recordCreated;
};
/**
* Relation class for query tests.
*/
class QueryRelation
{
public:
/**
* Constructor.
*/
QueryRelation() :
personId(),
someVal()
{
// No-op.
}
/**
* Constructor.
*
* @param personId Id.
* @param someVal Int value.
*/
QueryRelation(int32_t personId, int32_t someVal) :
personId(personId),
someVal(someVal)
{
// No-op.
}
/**
* Get person ID.
*
* @return Person ID.
*/
int32_t GetPersonId() const
{
return personId;
}
/**
* Get hobby ID.
*
* @return Some test value.
*/
int32_t GetHobbyId() const
{
return someVal;
}
private:
/** Person ID. */
int32_t personId;
/** Some test value. */
int32_t someVal;
};
/**
* Byte array test type.
*/
struct ByteArrayType
{
/**
* Test constructor.
*
* @param val Init value.
*/
ByteArrayType(int32_t val) :
intVal(val),
arrayVal(val + 1, val + 1)
{
// No-op.
}
/**
* Default constructor.
*/
ByteArrayType() :
intVal(0),
arrayVal()
{
// No-op.
}
/** Int field. */
int32_t intVal;
/** Array field. */
std::vector<int8_t> arrayVal;
};
namespace ignite
{
namespace binary
{
/**
* Binary type definition for QueryPerson.
*/
IGNITE_BINARY_TYPE_START(QueryPerson)
IGNITE_BINARY_GET_TYPE_ID_AS_HASH(QueryPerson)
IGNITE_BINARY_GET_TYPE_NAME_AS_IS(QueryPerson)
IGNITE_BINARY_GET_FIELD_ID_AS_HASH
IGNITE_BINARY_IS_NULL_FALSE(QueryPerson)
IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(QueryPerson)
static void Write(BinaryWriter& writer, const QueryPerson& obj)
{
writer.WriteString("name", obj.GetName());
writer.WriteInt32("age", obj.GetAge());
writer.WriteDate("birthday", obj.GetBirthday());
writer.WriteTimestamp("recordCreated", obj.GetCreationTime());
}
static void Read(BinaryReader& reader, QueryPerson& dst)
{
std::string name = reader.ReadString("name");
int age = reader.ReadInt32("age");
Date birthday = reader.ReadDate("birthday");
Timestamp recordCreated = reader.ReadTimestamp("recordCreated");
dst = QueryPerson(name, age, birthday, recordCreated);
}
IGNITE_BINARY_TYPE_END
/**
* Binary type definition for QueryRelation.
*/
IGNITE_BINARY_TYPE_START(QueryRelation)
IGNITE_BINARY_GET_TYPE_ID_AS_HASH(QueryRelation)
IGNITE_BINARY_GET_TYPE_NAME_AS_IS(QueryRelation)
IGNITE_BINARY_GET_FIELD_ID_AS_HASH
IGNITE_BINARY_IS_NULL_FALSE(QueryRelation)
IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(QueryRelation)
static void Write(BinaryWriter& writer, const QueryRelation& obj)
{
writer.WriteInt32("personId", obj.GetPersonId());
writer.WriteInt32("someVal", obj.GetHobbyId());
}
static void Read(BinaryReader& reader, QueryRelation& dst)
{
int32_t personId = reader.ReadInt32("personId");
int32_t someVal = reader.ReadInt32("someVal");
dst = QueryRelation(personId, someVal);
}
IGNITE_BINARY_TYPE_END
/**
* Binary type definition for ByteArrayType.
*/
IGNITE_BINARY_TYPE_START(ByteArrayType)
IGNITE_BINARY_GET_TYPE_ID_AS_HASH(ByteArrayType)
IGNITE_BINARY_GET_TYPE_NAME_AS_IS(ByteArrayType)
IGNITE_BINARY_GET_FIELD_ID_AS_HASH
IGNITE_BINARY_IS_NULL_FALSE(ByteArrayType)
IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(ByteArrayType)
static void Write(BinaryWriter& writer, const ByteArrayType& obj)
{
writer.WriteInt32("intVal", obj.intVal);
writer.WriteInt8Array("arrayVal", &obj.arrayVal[0], static_cast<int32_t>(obj.arrayVal.size()));
}
static void Read(BinaryReader& reader, ByteArrayType& dst)
{
dst.intVal = reader.ReadInt32("intVal");
int32_t arrayValSize = reader.ReadInt8Array("arrayVal", 0, 0);
dst.arrayVal.resize(static_cast<size_t>(arrayValSize));
reader.ReadInt8Array("arrayVal", &dst.arrayVal[0], arrayValSize);
}
IGNITE_BINARY_TYPE_END
}
}
/**
* Count number of records returned by cursor.
*
* @param cur Cursor.
*/
template<typename Cursor>
int CountRecords(Cursor& cur)
{
int number = 0;
while (cur.HasNext())
{
++number;
cur.GetNext();
}
return number;
}
/**
* Ensure that HasNext() fails.
*
* @param cur Cursor.
*/
template<typename Cursor>
void CheckHasNextFail(Cursor& cur)
{
BOOST_CHECK_EXCEPTION(cur.HasNext(), IgniteError, ignite_test::IsGenericError);
}
/**
* Ensure that GetNext() fails.
*
* @param cur Cursor.
*/
template<typename Cursor>
void CheckGetNextFail(Cursor& cur)
{
BOOST_CHECK_EXCEPTION(cur.GetNext(), IgniteError, ignite_test::IsGenericError);
}
/**
* Ensure that GetAll() fails.
*
* @param cur Cursor.
*/
void CheckGetAllFail(QueryCursor<int, QueryPerson>& cur)
{
std::vector<CacheEntry<int, QueryPerson> > res;
BOOST_CHECK_EXCEPTION(cur.GetAll(res), IgniteError, ignite_test::IsGenericError);
}
/**
* Ensure that iter version of GetAll() fails.
*
* @param cur Cursor.
*/
void CheckGetAllFailIter(QueryCursor<int, QueryPerson>& cur)
{
std::vector<CacheEntry<int, QueryPerson> > res;
BOOST_CHECK_EXCEPTION(cur.GetAll(std::back_inserter(res)), IgniteError, ignite_test::IsGenericError);
}
/**
* Check empty result through iteration.
*
* @param cur Cursor.
*/
void CheckEmpty(QueryCursor<int, QueryPerson>& cur)
{
BOOST_REQUIRE(!cur.HasNext());
CheckGetNextFail(cur);
CheckGetAllFail(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)
{
std::vector<CacheEntry<int, QueryPerson> > res;
cur.GetAll(res);
BOOST_REQUIRE(res.size() == 0);
CheckHasNextFail(cur);
CheckGetNextFail(cur);
}
/**
* Check empty result through iter version of GetAll().
*
* @param cur Cursor.
*/
void CheckEmptyGetAllIter(QueryCursor<int, QueryPerson>& cur)
{
std::vector<CacheEntry<int, QueryPerson> > res;
cur.GetAll(std::back_inserter(res));
BOOST_REQUIRE(res.size() == 0);
CheckHasNextFail(cur);
CheckGetNextFail(cur);
}
/**
* Check single result through iteration.
*
* @param cur Cursor.
* @param key Key.
* @param name Name.
* @param age Age.
*/
void CheckSingle(QueryCursor<int, QueryPerson>& cur, int key, const std::string& name, int age)
{
BOOST_REQUIRE(cur.HasNext());
CheckGetAllFail(cur);
CacheEntry<int, QueryPerson> entry = cur.GetNext();
CheckGetAllFail(cur);
BOOST_REQUIRE(entry.GetKey() == key);
BOOST_REQUIRE(entry.GetValue().GetName().compare(name) == 0);
BOOST_REQUIRE(entry.GetValue().GetAge() == age);
BOOST_REQUIRE(!cur.HasNext());
CheckGetNextFail(cur);
CheckGetAllFail(cur);
}
/**
* Check single result through iteration.
*
* @param cur Cursor.
* @param key Key.
* @param name Name.
* @param age Age.
*/
void CheckSingle(QueryFieldsCursor& cur, int key, const std::string& name, int age)
{
BOOST_REQUIRE(cur.HasNext());
QueryFieldsRow row = cur.GetNext();
BOOST_REQUIRE_EQUAL(row.GetNext<int32_t>(), key);
BOOST_REQUIRE_EQUAL(row.GetNext<std::string>(), name);
BOOST_REQUIRE_EQUAL(row.GetNext<int32_t>(), age);
BOOST_REQUIRE(!row.HasNext());
BOOST_REQUIRE(!cur.HasNext());
CheckGetNextFail(cur);
}
/**
* Check single result through GetAll().
*
* @param cur Cursor.
* @param key Key.
* @param name Name.
* @param age Age.
*/
void CheckSingleGetAll(QueryCursor<int, QueryPerson>& cur, int key, const std::string& name, int age)
{
std::vector<CacheEntry<int, QueryPerson> > res;
cur.GetAll(res);
CheckHasNextFail(cur);
CheckGetNextFail(cur);
CheckGetAllFail(cur);
BOOST_CHECK_EQUAL(res.size(), 1);
BOOST_CHECK_EQUAL(res[0].GetKey(), key);
BOOST_CHECK_EQUAL(res[0].GetValue().GetName(), name);
BOOST_CHECK_EQUAL(res[0].GetValue().GetAge(), age);
CheckHasNextFail(cur);
CheckGetNextFail(cur);
CheckGetAllFail(cur);
}
/**
* Check single result through iter version of GetAll().
*
* @param cur Cursor.
* @param key Key.
* @param name Name.
* @param age Age.
*/
void CheckSingleGetAllIter(QueryCursor<int, QueryPerson>& cur, int key, const std::string& name, int age)
{
std::vector<CacheEntry<int, QueryPerson> > res;
cur.GetAll(std::back_inserter(res));
CheckHasNextFail(cur);
CheckGetNextFail(cur);
CheckGetAllFail(cur);
BOOST_CHECK_EQUAL(res.size(), 1);
BOOST_CHECK_EQUAL(res[0].GetKey(), key);
BOOST_CHECK_EQUAL(res[0].GetValue().GetName(), name);
BOOST_CHECK_EQUAL(res[0].GetValue().GetAge(), age);
CheckHasNextFail(cur);
CheckGetNextFail(cur);
CheckGetAllFail(cur);
}
/**
* Check multiple results through iteration.
*
* @param cur Cursor.
* @param key1 Key 1.
* @param name1 Name 1.
* @param age1 Age 1.
* @param key2 Key 2.
* @param name2 Name 2.
* @param age2 Age 2.
*/
void CheckMultiple(QueryCursor<int, QueryPerson>& cur, int key1, const std::string& name1,
int age1, int key2, const std::string& name2, int age2)
{
for (int i = 0; i < 2; i++)
{
BOOST_REQUIRE(cur.HasNext());
CheckGetAllFail(cur);
CacheEntry<int, QueryPerson> entry = cur.GetNext();
CheckGetAllFail(cur);
if (entry.GetKey() == key1)
{
BOOST_CHECK_EQUAL(entry.GetValue().GetName(), name1);
BOOST_CHECK_EQUAL(entry.GetValue().GetAge(), age1);
}
else if (entry.GetKey() == key2)
{
BOOST_CHECK_EQUAL(entry.GetValue().GetName(), name2);
BOOST_CHECK_EQUAL(entry.GetValue().GetAge(), age2);
}
else
BOOST_FAIL("Unexpected entry.");
}
BOOST_REQUIRE(!cur.HasNext());
CheckGetNextFail(cur);
CheckGetAllFail(cur);
}
/**
* Check multiple results through GetAll().
*
* @param cur Cursor.
* @param key1 Key 1.
* @param name1 Name 1.
* @param age1 Age 1.
* @param key2 Key 2.
* @param name2 Name 2.
* @param age2 Age 2.
*/
void CheckMultipleGetAll(QueryCursor<int, QueryPerson>& cur, int key1, const std::string& name1,
int age1, int key2, const std::string& name2, int age2)
{
std::vector<CacheEntry<int, QueryPerson> > res;
cur.GetAll(res);
CheckHasNextFail(cur);
CheckGetNextFail(cur);
CheckGetAllFail(cur);
BOOST_REQUIRE_EQUAL(res.size(), 2);
for (int i = 0; i < 2; i++)
{
CacheEntry<int, QueryPerson> entry = res[i];
if (entry.GetKey() == key1)
{
BOOST_CHECK_EQUAL(entry.GetValue().GetName(), name1);
BOOST_CHECK_EQUAL(entry.GetValue().GetAge(), age1);
}
else if (entry.GetKey() == key2)
{
BOOST_CHECK_EQUAL(entry.GetValue().GetName(), name2);
BOOST_CHECK_EQUAL(entry.GetValue().GetAge(), age2);
}
else
BOOST_FAIL("Unexpected entry.");
}
}
/**
* Check multiple results through iter verion of GetAll().
*
* @param cur Cursor.
* @param key1 Key 1.
* @param name1 Name 1.
* @param age1 Age 1.
* @param key2 Key 2.
* @param name2 Name 2.
* @param age2 Age 2.
*/
void CheckMultipleGetAllIter(QueryCursor<int, QueryPerson>& cur, int key1, const std::string& name1,
int age1, int key2, const std::string& name2, int age2)
{
std::vector<CacheEntry<int, QueryPerson> > res;
cur.GetAll(std::back_inserter(res));
CheckHasNextFail(cur);
CheckGetNextFail(cur);
CheckGetAllFail(cur);
BOOST_REQUIRE_EQUAL(res.size(), 2);
for (int i = 0; i < 2; i++)
{
CacheEntry<int, QueryPerson> entry = res[i];
if (entry.GetKey() == key1)
{
BOOST_CHECK_EQUAL(entry.GetValue().GetName(), name1);
BOOST_CHECK_EQUAL(entry.GetValue().GetAge(), age1);
}
else if (entry.GetKey() == key2)
{
BOOST_CHECK_EQUAL(entry.GetValue().GetName(), name2);
BOOST_CHECK_EQUAL(entry.GetValue().GetAge(), age2);
}
else
BOOST_FAIL("Unexpected entry.");
}
}
/**
* Test setup fixture.
*/
struct CacheQueryTestSuiteFixture
{
Ignite StartNode(const char* name)
{
#ifdef IGNITE_TESTS_32
return ignite_test::StartNode("cache-query-32.xml", name);
#else
return ignite_test::StartNode("cache-query.xml", name);
#endif
}
void CheckFieldsQueryPages(int32_t pageSize, int32_t pagesNum, int32_t additionalNum)
{
// Test simple query.
Cache<int, QueryPerson> cache = GetPersonCache();
// Test query with two fields of different type.
SqlFieldsQuery qry("select name, age from QueryPerson order by age");
QueryFieldsCursor cursor = cache.Query(qry);
CheckEmpty(cursor);
const int32_t entryCnt = pageSize * pagesNum + additionalNum; // Number of entries.
qry.SetPageSize(pageSize);
for (int i = 0; i < entryCnt; i++)
{
std::stringstream stream;
stream << "A" << i;
cache.Put(i, QueryPerson(stream.str(), i * 10, MakeDateGmt(1970 + i),
MakeTimestampGmt(2016, 1, 1, i / 60, i % 60)));
}
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_EQUAL(name, expected_name);
int age = row.GetNext<int>(error);
BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
BOOST_REQUIRE_EQUAL(age, expected_age);
BOOST_REQUIRE(!row.HasNext());
}
CheckEmpty(cursor);
}
/**
* Constructor.
*/
CacheQueryTestSuiteFixture() :
grid(StartNode("Node1"))
{
// No-op.
}
/**
* Destructor.
*/
~CacheQueryTestSuiteFixture()
{
Ignition::StopAll(true);
}
/** Person cache accessor. */
Cache<int, QueryPerson> GetPersonCache()
{
return grid.GetCache<int, QueryPerson>("QueryPerson");
}
/** Relation cache accessor. */
Cache<int, QueryRelation> GetRelationCache()
{
return grid.GetCache<int, QueryRelation>("QueryRelation");
}
/** Node started during the test. */
Ignite grid;
};
BOOST_FIXTURE_TEST_SUITE(CacheQueryTestSuite, CacheQueryTestSuiteFixture)
/**
* Test SQL query.
*/
BOOST_AUTO_TEST_CASE(TestSqlQuery)
{
Cache<int, QueryPerson> cache = GetPersonCache();
// Test query with no results.
SqlQuery qry("QueryPerson", "age < 20");
QueryCursor<int, QueryPerson> cursor = cache.Query(qry);
CheckEmpty(cursor);
cursor = cache.Query(qry);
CheckEmptyGetAll(cursor);
cursor = cache.Query(qry);
CheckEmptyGetAllIter(cursor);
// Test simple query.
cache.Put(1, QueryPerson("A1", 10, MakeDateGmt(1990, 03, 18),
MakeTimestampGmt(2016, 02, 10, 17, 39, 34, 579304685)));
cache.Put(2, QueryPerson("A2", 20, MakeDateGmt(1989, 10, 26),
MakeTimestampGmt(2016, 02, 10, 17, 39, 35, 678403201)));
cursor = cache.Query(qry);
CheckSingle(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAll(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAllIter(cursor, 1, "A1", 10);
// Test simple distributed joins query.
BOOST_CHECK(!qry.IsDistributedJoins());
qry.SetDistributedJoins(true);
BOOST_CHECK(qry.IsDistributedJoins());
cursor = cache.Query(qry);
CheckSingle(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAll(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAllIter(cursor, 1, "A1", 10);
qry.SetDistributedJoins(false);
// Test simple local query.
BOOST_CHECK(!qry.IsLocal());
qry.SetLocal(true);
BOOST_CHECK(qry.IsLocal());
cursor = cache.Query(qry);
CheckSingle(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAll(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAllIter(cursor, 1, "A1", 10);
// Test query with arguments.
qry.SetSql("age < ? AND name = ?");
qry.AddArgument<int>(20);
qry.AddArgument<std::string>("A1");
cursor = cache.Query(qry);
CheckSingle(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAll(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAllIter(cursor, 1, "A1", 10);
// Test resetting query arguments.
qry.ClearArguments();
qry.AddArgument<int>(30);
qry.AddArgument<std::string>("A2");
cursor = cache.Query(qry);
CheckSingle(cursor, 2, "A2", 20);
cursor = cache.Query(qry);
CheckSingleGetAll(cursor, 2, "A2", 20);
cursor = cache.Query(qry);
CheckSingleGetAllIter(cursor, 2, "A2", 20);
// Test query returning multiple entries.
qry = SqlQuery("QueryPerson", "age < 30");
cursor = cache.Query(qry);
CheckMultiple(cursor, 1, "A1", 10, 2, "A2", 20);
cursor = cache.Query(qry);
CheckMultipleGetAll(cursor, 1, "A1", 10, 2, "A2", 20);
cursor = cache.Query(qry);
CheckMultipleGetAllIter(cursor, 1, "A1", 10, 2, "A2", 20);
}
/**
* Test SQL query distributed joins.
*/
BOOST_AUTO_TEST_CASE(TestSqlQueryDistributedJoins)
{
MUTE_TEST_FOR_TEAMCITY;
Cache<int, QueryPerson> cache1 = GetPersonCache();
Cache<int, QueryRelation> cache2 = GetRelationCache();
// Starting second node.
Ignite node2 = StartNode("Node2");
int firstKey = 0;
int entryCnt = 1000;
// Filling caches
for (int i = firstKey; i < firstKey + entryCnt; i++)
{
std::stringstream stream;
stream << "A" << i;
cache1.Put(i, QueryPerson(stream.str(), i * 10, MakeDateGmt(1970 + i),
MakeTimestampGmt(2016, 1, 1, i / 60, i % 60)));
cache2.Put(i + 1, QueryRelation(i, i * 10));
}
// Test query with no results.
SqlQuery qry("QueryPerson",
"from \"QueryPerson\".QueryPerson, \"QueryRelation\".QueryRelation "
"where (\"QueryPerson\".QueryPerson.age = \"QueryRelation\".QueryRelation.someVal) "
"and (\"QueryPerson\".QueryPerson._key < 1000)");
QueryCursor<int, QueryPerson> cursor = cache1.Query(qry);
// Ensure that data is not collocated, so not full result set is returned.
int recordsNum = CountRecords(cursor);
BOOST_CHECK_GT(recordsNum, 0);
BOOST_CHECK_LT(recordsNum, entryCnt);
qry.SetDistributedJoins(true);
cursor = cache1.Query(qry);
// Check that full result set is returned.
recordsNum = CountRecords(cursor);
BOOST_CHECK_EQUAL(recordsNum, entryCnt);
}
/**
* Test text query.
*/
BOOST_AUTO_TEST_CASE(TestTextQuery)
{
Cache<int, QueryPerson> cache = GetPersonCache();
// Test query with no results.
TextQuery qry("QueryPerson", "A1");
QueryCursor<int, QueryPerson> cursor = cache.Query(qry);
CheckEmpty(cursor);
cursor = cache.Query(qry);
CheckEmptyGetAll(cursor);
cursor = cache.Query(qry);
CheckEmptyGetAllIter(cursor);
// Test simple query.
cache.Put(1, QueryPerson("A1", 10, MakeDateGmt(1990, 03, 18),
MakeTimestampGmt(2016, 02, 10, 17, 39, 34, 579304685)));
cache.Put(2, QueryPerson("A2", 20, MakeDateGmt(1989, 10, 26),
MakeTimestampGmt(2016, 02, 10, 17, 39, 35, 678403201)));
cursor = cache.Query(qry);
CheckSingle(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAll(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAllIter(cursor, 1, "A1", 10);
// Test simple local query.
qry.SetLocal(true);
cursor = cache.Query(qry);
CheckSingle(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAll(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAllIter(cursor, 1, "A1", 10);
// Test query returning multiple entries.
qry = TextQuery("QueryPerson", "A*");
cursor = cache.Query(qry);
CheckMultiple(cursor, 1, "A1", 10, 2, "A2", 20);
cursor = cache.Query(qry);
CheckMultipleGetAll(cursor, 1, "A1", 10, 2, "A2", 20);
cursor = cache.Query(qry);
CheckMultipleGetAllIter(cursor, 1, "A1", 10, 2, "A2", 20);
}
/**
* Test scan query.
*/
BOOST_AUTO_TEST_CASE(TestScanQuery)
{
// Test simple query.
Cache<int, QueryPerson> cache = GetPersonCache();
// Test query with no results.
ScanQuery qry;
QueryCursor<int, QueryPerson> cursor = cache.Query(qry);
CheckEmpty(cursor);
cursor = cache.Query(qry);
CheckEmptyGetAll(cursor);
cursor = cache.Query(qry);
CheckEmptyGetAllIter(cursor);
// Test simple query.
cache.Put(1, QueryPerson("A1", 10, MakeDateGmt(1990, 03, 18),
MakeTimestampGmt(2016, 02, 10, 17, 39, 34, 579304685)));
cursor = cache.Query(qry);
CheckSingle(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAll(cursor, 1, "A1", 10);
cursor = cache.Query(qry);
CheckSingleGetAllIter(cursor, 1, "A1", 10);
// Test query returning multiple entries.
cache.Put(2, QueryPerson("A2", 20, MakeDateGmt(1989, 10, 26),
MakeTimestampGmt(2016, 02, 10, 17, 39, 35, 678403201)));
cursor = cache.Query(qry);
CheckMultiple(cursor, 1, "A1", 10, 2, "A2", 20);
cursor = cache.Query(qry);
CheckMultipleGetAll(cursor, 1, "A1", 10, 2, "A2", 20);
cursor = cache.Query(qry);
CheckMultipleGetAllIter(cursor, 1, "A1", 10, 2, "A2", 20);
}
/**
* Test scan query over partitions.
*/
BOOST_AUTO_TEST_CASE(TestScanQueryPartitioned)
{
// Populate cache with data.
Cache<int, QueryPerson> cache = GetPersonCache();
int32_t partCnt = 256; // Defined in configuration explicitly.
int32_t entryCnt = 1000; // Should be greater than partCnt.
for (int i = 0; i < entryCnt; i++)
{
std::stringstream stream;
stream << "A" << i;
cache.Put(i, QueryPerson(stream.str(), i * 10, MakeDateGmt(1970 + i),
MakeTimestampGmt(2016, 1, 1, i / 60, i % 60)));
}
// Iterate over all partitions and collect data.
std::set<int> keys;
for (int i = 0; i < partCnt; i++)
{
ScanQuery qry(i);
QueryCursor<int, QueryPerson> cur = cache.Query(qry);
while (cur.HasNext())
{
CacheEntry<int, QueryPerson> entry = cur.GetNext();
int key = entry.GetKey();
keys.insert(key);
std::stringstream stream;
stream << "A" << key;
BOOST_REQUIRE_EQUAL(entry.GetValue().GetName().compare(stream.str()), 0);
BOOST_REQUIRE_EQUAL(entry.GetValue().GetAge(), key * 10);
}
}
// Ensure that all keys were read.
BOOST_CHECK_EQUAL(keys.size(), entryCnt);
}
/**
* Basic test for SQL fields query.
*/
BOOST_AUTO_TEST_CASE(TestSqlFieldsQueryBasic)
{
Cache<int, QueryPerson> cache = GetPersonCache();
// Test query with no results.
SqlFieldsQuery qry("select _key, name, age from QueryPerson where age < 20");
QueryFieldsCursor cursor = cache.Query(qry);
CheckEmpty(cursor);
// Test simple query.
cache.Put(1, QueryPerson("A1", 10, MakeDateGmt(1990, 03, 18),
MakeTimestampGmt(2016, 02, 10, 17, 39, 34, 579304685)));
cache.Put(2, QueryPerson("A2", 20, MakeDateGmt(1989, 10, 26),
MakeTimestampGmt(2016, 02, 10, 17, 39, 35, 678403201)));
cursor = cache.Query(qry);
CheckSingle(cursor, 1, "A1", 10);
// Test simple distributed joins query.
BOOST_CHECK(!qry.IsDistributedJoins());
BOOST_CHECK(!qry.IsEnforceJoinOrder());
qry.SetDistributedJoins(true);
BOOST_CHECK(qry.IsDistributedJoins());
BOOST_CHECK(!qry.IsEnforceJoinOrder());
qry.SetEnforceJoinOrder(true);
BOOST_CHECK(qry.IsDistributedJoins());
BOOST_CHECK(qry.IsEnforceJoinOrder());
cursor = cache.Query(qry);
CheckSingle(cursor, 1, "A1", 10);
qry.SetDistributedJoins(false);
qry.SetEnforceJoinOrder(false);
// Test simple local query.
BOOST_CHECK(!qry.IsLocal());
qry.SetLocal(true);
BOOST_CHECK(qry.IsLocal());
cursor = cache.Query(qry);
CheckSingle(cursor, 1, "A1", 10);
// Test query with arguments.
qry.SetSql("select _key, name, age from QueryPerson where age < ? AND name = ?");
qry.AddArgument<int>(20);
qry.AddArgument<std::string>("A1");
cursor = cache.Query(qry);
CheckSingle(cursor, 1, "A1", 10);
// Test resetting query arguments.
qry.ClearArguments();
qry.AddArgument<int>(30);
qry.AddArgument<std::string>("A2");
cursor = cache.Query(qry);
CheckSingle(cursor, 2, "A2", 20);
}
/**
* Test SQL fields query distributed joins.
*/
BOOST_AUTO_TEST_CASE(TestSqlFieldsQueryDistributedJoins)
{
MUTE_TEST_FOR_TEAMCITY;
Cache<int, QueryPerson> cache1 = GetPersonCache();
Cache<int, QueryRelation> cache2 = GetRelationCache();
// Starting second node.
Ignite node2 = StartNode("Node2");
int beginFrom = 2000;
int entryCnt = 1000;
// Filling caches
for (int i = beginFrom; i < entryCnt + beginFrom; ++i)
{
std::stringstream stream;
stream << "A" << i;
cache1.Put(i, QueryPerson(stream.str(), i * 10, MakeDateGmt(1970 + (i / 100)),
MakeTimestampGmt(2016, 1, 1, (i / 60) % 24, i % 60)));
cache2.Put(i + 1, QueryRelation(i, i * 10));
}
// Test query with no results.
SqlFieldsQuery qry(
"select age, name "
"from \"QueryPerson\".QueryPerson as QP "
"inner join \"QueryRelation\".QueryRelation as QR "
"on QP.age = QR.someVal "
"where QP._key >= 2000 and QP._key < 3000");
QueryFieldsCursor cursor = cache1.Query(qry);
// Ensure that data is not collocated, so not full result set is returned.
int recordsNum = CountRecords(cursor);
BOOST_CHECK_GT(recordsNum, 0);
BOOST_CHECK_LT(recordsNum, entryCnt);
qry.SetDistributedJoins(true);
cursor = cache1.Query(qry);
// Check that full result set is returned.
recordsNum = CountRecords(cursor);
BOOST_CHECK_EQUAL(recordsNum, entryCnt);
}
/**
* Test fields query with single entry.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQuerySingle)
{
// Test simple query.
Cache<int, QueryPerson> cache = GetPersonCache();
// 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, MakeDateGmt(1990, 03, 18),
MakeTimestampGmt(2016, 02, 10, 17, 39, 34, 579304685)));
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 single entry.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryExceptions)
{
// Test simple query.
Cache<int, QueryPerson> cache = GetPersonCache();
// 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, MakeDateGmt(1990, 03, 18),
MakeTimestampGmt(2016, 02, 10, 17, 39, 34, 579304685)));
cursor = cache.Query(qry);
BOOST_REQUIRE(cursor.HasNext());
QueryFieldsRow row = cursor.GetNext();
BOOST_REQUIRE(row.HasNext());
int age = row.GetNext<int>();
BOOST_REQUIRE(age == 10);
std::string name = row.GetNext<std::string>();
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 = GetPersonCache();
// 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, MakeDateGmt(1990, 03, 18),
MakeTimestampGmt(2016, 02, 10, 17, 39, 34, 579304685)));
cache.Put(2, QueryPerson("A2", 20, MakeDateGmt(1989, 10, 26),
MakeTimestampGmt(2016, 02, 10, 17, 39, 35, 678403201)));
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 = GetPersonCache();
// Test query with two fields of different type.
SqlFieldsQuery qry("select name, age from QueryPerson order by age");
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;
QueryPerson val(stream.str(), i * 10, MakeDateGmt(1980 + i, 1, 1),
MakeTimestampGmt(2016, 1, 1, i / 60, i % 60));
cache.Put(i, val);
}
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_EQUAL(name, expected_name);
int age = row.GetNext<int>(error);
BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
BOOST_REQUIRE_EQUAL(age, expected_age);
BOOST_REQUIRE(!row.HasNext());
}
CheckEmpty(cursor);
}
/**
* Test query for Date type.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryDateLess)
{
// Test simple query.
Cache<int, QueryPerson> cache = GetPersonCache();
// Test query with field of type 'Date'.
SqlFieldsQuery qry("select birthday from QueryPerson where birthday<'1990-01-01'");
QueryFieldsCursor cursor = cache.Query(qry);
CheckEmpty(cursor);
int32_t entryCnt = 100; // Number of entries.
for (int i = 0; i < entryCnt; i++)
{
std::stringstream stream;
stream << "A" << i;
QueryPerson val(stream.str(), i * 10, MakeDateGmt(1980 + i, 1, 1),
MakeTimestampGmt(2016, 1, 1, i / 60, i % 60));
cache.Put(i, val);
}
cursor = cache.Query(qry);
IgniteError error;
int32_t resultSetSize = 0; // Number of entries in query result set.
while (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);
Date birthday = row.GetNext<Date>(error);
BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
BOOST_CHECK(birthday == MakeDateGmt(1980 + resultSetSize, 1, 1));
BOOST_CHECK(birthday < MakeDateGmt(1990, 1, 1));
BOOST_REQUIRE(!row.HasNext());
++resultSetSize;
}
BOOST_CHECK_EQUAL(resultSetSize, 10);
CheckEmpty(cursor);
}
/**
* Test query for Date type.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryDateMore)
{
// Test simple query.
Cache<int, QueryPerson> cache = GetPersonCache();
// Test query with field of type 'Date'.
SqlFieldsQuery qry("select birthday from QueryPerson where birthday>'2070-01-01'");
QueryFieldsCursor cursor = cache.Query(qry);
CheckEmpty(cursor);
int32_t entryCnt = 100; // Number of entries.
for (int i = 0; i < entryCnt; i++)
{
std::stringstream stream;
stream << "A" << i;
QueryPerson val(stream.str(), i * 10, MakeDateGmt(1980 + i, 1, 1),
MakeTimestampGmt(2016, 1, 1, i / 60, i % 60));
cache.Put(i, val);
}
cursor = cache.Query(qry);
IgniteError error;
int32_t resultSetSize = 0; // Number of entries in query result set.
while (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);
Date birthday = row.GetNext<Date>(error);
BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
BOOST_CHECK(birthday == MakeDateGmt(2071 + resultSetSize, 1, 1));
BOOST_CHECK(birthday > MakeDateGmt(2070, 1, 1));
BOOST_REQUIRE(!row.HasNext());
++resultSetSize;
}
BOOST_CHECK_EQUAL(resultSetSize, 9);
CheckEmpty(cursor);
}
/**
* Test query for Date type.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryDateEqual)
{
// Test simple query.
Cache<int, QueryPerson> cache = GetPersonCache();
// Test query with field of type 'Date'.
SqlFieldsQuery qry("select birthday from QueryPerson where birthday='2032-01-01'");
QueryFieldsCursor cursor = cache.Query(qry);
CheckEmpty(cursor);
int32_t entryCnt = 100; // Number of entries.
for (int i = 0; i < entryCnt; i++)
{
std::stringstream stream;
stream << "A" << i;
QueryPerson val(stream.str(), i * 10, MakeDateGmt(1980 + i, 1, 1),
MakeTimestampGmt(2016, 1, 1, i / 60, i % 60));
cache.Put(i, val);
}
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);
Date birthday = row.GetNext<Date>(error);
BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
BOOST_CHECK(birthday == MakeDateGmt(2032, 1, 1));
BOOST_REQUIRE(!row.HasNext());
CheckEmpty(cursor);
}
/**
* Test query for Timestamp type.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryTimestampLess)
{
// Test simple query.
Cache<int, QueryPerson> cache = GetPersonCache();
// Test query with field of type 'Timestamp'.
SqlFieldsQuery qry("select recordCreated from QueryPerson where recordCreated<'2016-01-01 01:00:00'");
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;
QueryPerson val(stream.str(), i * 10, MakeDateGmt(1980 + i, 1, 1),
MakeTimestampGmt(2016, 1, 1, i / 60, i % 60));
cache.Put(i, val);
}
cursor = cache.Query(qry);
IgniteError error;
int32_t resultSetSize = 0; // Number of entries in query result set.
while (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);
Timestamp recordCreated = row.GetNext<Timestamp>(error);
BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
BOOST_CHECK(recordCreated == MakeTimestampGmt(2016, 1, 1, 0, resultSetSize % 60, 0));
BOOST_CHECK(recordCreated < MakeTimestampGmt(2016, 1, 1, 1, 0, 0));
BOOST_REQUIRE(!row.HasNext());
++resultSetSize;
}
BOOST_CHECK_EQUAL(resultSetSize, 60);
CheckEmpty(cursor);
}
/**
* Test query for Timestamp type.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryTimestampMore)
{
// Test simple query.
Cache<int, QueryPerson> cache = GetPersonCache();
// Test query with field of type 'Timestamp'.
SqlFieldsQuery qry("select recordCreated from QueryPerson where recordCreated>'2016-01-01 15:30:00'");
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;
QueryPerson val(stream.str(), i * 10, MakeDateGmt(1980 + i, 1, 1),
MakeTimestampGmt(2016, 1, 1, i / 60, i % 60));
cache.Put(i, val);
}
cursor = cache.Query(qry);
IgniteError error;
int32_t resultSetSize = 0; // Number of entries in query result set.
while (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);
Timestamp recordCreated = row.GetNext<Timestamp>(error);
BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
int32_t minutes = resultSetSize + 31;
BOOST_CHECK(recordCreated == MakeTimestampGmt(2016, 1, 1, 15 + minutes / 60, minutes % 60, 0));
BOOST_CHECK(recordCreated > MakeTimestampGmt(2016, 1, 1, 15, 30, 0));
BOOST_REQUIRE(!row.HasNext());
++resultSetSize;
}
BOOST_CHECK_EQUAL(resultSetSize, 69);
CheckEmpty(cursor);
}
/**
* Test query for Timestamp type.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryTimestampEqual)
{
// Test simple query.
Cache<int, QueryPerson> cache = GetPersonCache();
// Test query with field of type 'Timestamp'.
SqlFieldsQuery qry("select recordCreated from QueryPerson where recordCreated='2016-01-01 09:18:00'");
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;
QueryPerson val(stream.str(), i * 10, MakeDateGmt(1980 + i, 1, 1),
MakeTimestampGmt(2016, 1, 1, i / 60, i % 60));
cache.Put(i, val);
}
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);
Timestamp recordCreated = row.GetNext<Timestamp>(error);
BOOST_REQUIRE(error.GetCode() == IgniteError::IGNITE_SUCCESS);
BOOST_CHECK(recordCreated == MakeTimestampGmt(2016, 1, 1, 9, 18, 0));
BOOST_REQUIRE(!row.HasNext());
CheckEmpty(cursor);
}
/**
* Test query for Time type.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryTimeEqual)
{
// Test simple query.
Cache<int, Time> cache = grid.GetOrCreateCache<int, Time>("TimeCache");
// Test query with field of type 'Timestamp'.
SqlFieldsQuery qry("select _key from Time where _val='04:11:02'");
QueryFieldsCursor cursor = cache.Query(qry);
CheckEmpty(cursor);
int32_t entryCnt = 1000; // Number of entries.
for (int i = 0; i < entryCnt; i++)
{
int secs = i % 60;
int mins = i / 60;
cache.Put(i, MakeTimeGmt(4, mins, secs));
}
cursor = cache.Query(qry);
BOOST_REQUIRE(cursor.HasNext());
QueryFieldsRow row = cursor.GetNext();
BOOST_REQUIRE(row.HasNext());
int key = row.GetNext<int>();
BOOST_CHECK(key == 662);
BOOST_REQUIRE(!row.HasNext());
CheckEmpty(cursor);
}
/**
* Test fields query with several pages.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryPagesSeveral)
{
CheckFieldsQueryPages(32, 8, 1);
}
/**
* Test fields query with page size 1.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryPageSingle)
{
CheckFieldsQueryPages(1, 100, 0);
}
/**
* Test fields query with page size 0.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryPageZero)
{
BOOST_CHECK_THROW(CheckFieldsQueryPages(0, 100, 0), IgniteError);
}
/**
* Test query for key and value fields.
*/
BOOST_AUTO_TEST_CASE(TestKeyValFields)
{
Cache<int, QueryPerson> cache = GetPersonCache();
QueryPerson person("John", 30, MakeDateGmt(1987), MakeTimestampGmt(2017, 1, 1, 1, 1));
cache.Put(1, person);
for (int i = 0; i < 2; i++)
{
SqlFieldsQuery qry(i == 0 ?
"select _key, _val, k, v, name, age, birthday, recordCreated from QueryPerson" :
"select _key, _val, * from QueryPerson");
QueryFieldsCursor cursor = cache.Query(qry);
BOOST_REQUIRE(cursor.HasNext());
QueryFieldsRow row = cursor.GetNext();
BOOST_REQUIRE(row.HasNext());
int id = row.GetNext<int>();
BOOST_CHECK_EQUAL(1, id);
BOOST_REQUIRE(row.HasNext());
QueryPerson p = row.GetNext<QueryPerson>();
BOOST_CHECK_EQUAL(p, person);
BOOST_REQUIRE(row.HasNext());
id = row.GetNext<int>();
BOOST_CHECK_EQUAL(1, id);
BOOST_REQUIRE(row.HasNext());
p = row.GetNext<QueryPerson>();
BOOST_CHECK_EQUAL(p, person);
BOOST_REQUIRE(row.HasNext());
std::string name = row.GetNext<std::string>();
BOOST_CHECK_EQUAL(name, person.GetName());
BOOST_REQUIRE(row.HasNext());
int age = row.GetNext<int>();
BOOST_CHECK_EQUAL(age, person.GetAge());
BOOST_REQUIRE(row.HasNext());
Date birthday = row.GetNext<Date>();
BOOST_CHECK(birthday == person.GetBirthday());
BOOST_REQUIRE(row.HasNext());
Timestamp recordCreated = row.GetNext<Timestamp>();
BOOST_CHECK(recordCreated == person.GetCreationTime());
BOOST_CHECK(!row.HasNext());
}
}
/**
* Test query for Public schema.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQuerySetSchema)
{
Cache<int32_t, Time> timeCache = grid.GetCache<int32_t, Time>("TimeCache");
int32_t entryCnt = 1000; // Number of entries.
for (int i = 0; i < entryCnt; i++)
{
int secs = i % 60;
int mins = i / 60;
timeCache.Put(i, MakeTimeGmt(4, mins, secs));
}
Cache<int32_t, int32_t> intCache = grid.GetCache<int32_t, int32_t>("IntCache");
SqlFieldsQuery qry("select _key from Time where _val='04:11:02'");
BOOST_CHECK_EXCEPTION(intCache.Query(qry), IgniteError, ignite_test::IsGenericError);
qry.SetSchema("TimeCache");
QueryFieldsCursor cursor = intCache.Query(qry);
BOOST_REQUIRE(cursor.HasNext());
QueryFieldsRow row = cursor.GetNext();
BOOST_REQUIRE(row.HasNext());
int32_t key = row.GetNext<int32_t>();
BOOST_CHECK(key == 662);
BOOST_REQUIRE(!row.HasNext());
CheckEmpty(cursor);
}
/**
* Test query for byte arrays.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryByteArraySelect)
{
Cache<int32_t, ByteArrayType> byteArrayCache = grid.GetCache<int32_t, ByteArrayType>("ByteArrayCache");
int32_t entryCnt = 100; // Number of entries.
for (int32_t i = 0; i < entryCnt; i++)
byteArrayCache.Put(i, ByteArrayType(i));
SqlFieldsQuery qry("select intVal, arrayVal, intVal + 1 from ByteArrayType where _key=42");
QueryFieldsCursor cursor = byteArrayCache.Query(qry);
BOOST_REQUIRE(cursor.HasNext());
QueryFieldsRow row = cursor.GetNext();
BOOST_REQUIRE(row.HasNext());
int32_t intVal1 = row.GetNext<int32_t>();
BOOST_CHECK_EQUAL(intVal1, 42);
BOOST_REQUIRE(row.HasNext());
std::vector<int8_t> arrayVal;
int32_t arrayValSize = row.GetNextInt8Array(0, 0);
arrayVal.resize(static_cast<size_t>(arrayValSize));
row.GetNextInt8Array(&arrayVal[0], arrayValSize);
BOOST_CHECK_EQUAL(arrayValSize, 43);
for (int32_t i = 0; i < arrayValSize; ++i)
BOOST_CHECK_EQUAL(arrayVal[i], 43);
BOOST_REQUIRE(row.HasNext());
int32_t intVal2 = row.GetNext<int32_t>();
BOOST_CHECK_EQUAL(intVal2, 43);
BOOST_REQUIRE(!row.HasNext());
CheckEmpty(cursor);
}
/**
* Test query for byte arrays.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryByteArrayInsert)
{
Cache<int32_t, ByteArrayType> byteArrayCache = grid.GetCache<int32_t, ByteArrayType>("ByteArrayCache");
SqlFieldsQuery qry("insert into ByteArrayType(_key, intVal, arrayVal) values (?, ?, ?)");
int32_t entryCnt = 100; // Number of entries.
for (int32_t i = 0; i < entryCnt; i++)
{
int32_t key = i;
int32_t intVal = i;
std::vector<int8_t> arrayVal(i + 1, i + 1);
qry.AddArgument(key);
qry.AddArgument(intVal);
qry.AddInt8ArrayArgument(&arrayVal[0], i + 1);
byteArrayCache.Query(qry);
qry.ClearArguments();
}
ByteArrayType val = byteArrayCache.Get(42);
BOOST_CHECK_EQUAL(val.intVal, 42);
BOOST_CHECK_EQUAL(val.arrayVal.size(), 43);
for (int32_t i = 0; i < 43; ++i)
BOOST_CHECK_EQUAL(val.arrayVal[i], 43);
}
/**
* Test query for byte arrays.
*/
BOOST_AUTO_TEST_CASE(TestFieldsQueryByteArrayInsertSelect)
{
Cache<int32_t, ByteArrayType> byteArrayCache = grid.GetCache<int32_t, ByteArrayType>("ByteArrayCache");
SqlFieldsQuery qry("insert into ByteArrayType(_key, intVal, arrayVal) values (?, ?, ?)");
int32_t entryCnt = 100; // Number of entries.
for (int32_t i = 0; i < entryCnt; i++)
{
int32_t key = i;
int32_t intVal = i;
std::vector<int8_t> arrayVal(i + 1, i + 1);
qry.AddArgument(key);
qry.AddArgument(intVal);
qry.AddInt8ArrayArgument(&arrayVal[0], i + 1);
byteArrayCache.Query(qry);
qry.ClearArguments();
}
qry = SqlFieldsQuery("select intVal, arrayVal, intVal + 1 from ByteArrayType where _key=42");
QueryFieldsCursor cursor = byteArrayCache.Query(qry);
BOOST_REQUIRE(cursor.HasNext());
QueryFieldsRow row = cursor.GetNext();
BOOST_REQUIRE(row.HasNext());
int32_t intVal1 = row.GetNext<int32_t>();
BOOST_CHECK_EQUAL(intVal1, 42);
BOOST_REQUIRE(row.HasNext());
std::vector<int8_t> arrayVal;
int32_t arrayValSize = row.GetNextInt8Array(0, 0);
arrayVal.resize(static_cast<size_t>(arrayValSize));
row.GetNextInt8Array(&arrayVal[0], arrayValSize);
BOOST_CHECK_EQUAL(arrayValSize, 43);
for (int32_t i = 0; i < arrayValSize; ++i)
BOOST_CHECK_EQUAL(arrayVal[i], 43);
BOOST_REQUIRE(row.HasNext());
int32_t intVal2 = row.GetNext<int32_t>();
BOOST_CHECK_EQUAL(intVal2, 43);
BOOST_REQUIRE(!row.HasNext());
CheckEmpty(cursor);
}
BOOST_AUTO_TEST_SUITE_END()