From 5fc35bdeabe96842e12a3b29951c690edbc5cd6d Mon Sep 17 00:00:00 2001 From: Megh Bhatt Date: Wed, 23 Nov 2016 17:08:07 -0800 Subject: [PATCH] CQL driver enhancements Add support to retrieve all rows in a table. Added Db_GetAllRows API to achieve the same. Added MockCassLibrary and unit tests for the above. Change-Id: I3811c5840167d7d1f5d89bbd3bdc73c7f74afb39 Closes-Bug: #1632531 --- src/database/cassandra/cql/cql_if.cc | 194 +++++++++++++++-- src/database/cassandra/cql/cql_if.h | 2 + src/database/cassandra/cql/cql_if_impl.h | 10 + .../cassandra/cql/test/cql_if_test.cc | 204 ++++++++++++++++++ .../cassandra/cql/test/mock_cql_lib_if.h | 171 +++++++++++++++ src/database/gendb_if.h | 8 + 6 files changed, 576 insertions(+), 13 deletions(-) create mode 100644 src/database/cassandra/cql/test/mock_cql_lib_if.h diff --git a/src/database/cassandra/cql/cql_if.cc b/src/database/cassandra/cql/cql_if.cc index 2f4f8c537fa..86d3c5b4165 100644 --- a/src/database/cassandra/cql/cql_if.cc +++ b/src/database/cassandra/cql/cql_if.cc @@ -725,7 +725,7 @@ static std::string CassSelectFromTableInternal(const std::string &table, const GenDb::ColumnNameRange &ck_range) { std::ostringstream query; // Table - query << "SELECT * FROM " << table << " WHERE "; + query << "SELECT * FROM " << table; int rk_size(rkeys.size()); CassQueryPrinter cprinter(query); for (int i = 0; i < rk_size; i++) { @@ -733,7 +733,7 @@ static std::string CassSelectFromTableInternal(const std::string &table, int key_num(i + 1); query << " AND key" << key_num << "="; } else { - query << "key="; + query << " WHERE key="; } boost::apply_visitor(cprinter, rkeys[i]); } @@ -794,6 +794,11 @@ std::string PartitionKeyAndClusteringKeyRange2CassSelectFromTable( return CassSelectFromTableInternal(table, rkeys, ck_range); } +std::string CassSelectFromTable(const std::string &table) { + return CassSelectFromTableInternal(table, GenDb::DbDataValueVec(), + GenDb::ColumnNameRange()); +} + static GenDb::DbDataValue CassValue2DbDataValue( interface::CassLibrary *cci, const CassValue *cvalue) { CassValueType cvtype(cci->GetCassValueType(cvalue)); @@ -960,7 +965,7 @@ static GenDb::DbOpResult::type CassError2DbOpResult(CassError rc) { } } -static void GetDynamicCfResult(interface::CassLibrary *cci, +static void DynamicCfGetResult(interface::CassLibrary *cci, CassResultPtr *result, size_t rk_count, size_t ck_count, GenDb::NewColVec *v_columns) { // Row iterator @@ -990,7 +995,60 @@ static void GetDynamicCfResult(interface::CassLibrary *cci, } } -static void GetStaticCfResult(interface::CassLibrary *cci, +void DynamicCfGetResult(interface::CassLibrary *cci, + CassResultPtr *result, size_t rk_count, + size_t ck_count, GenDb::ColListVec *v_col_list) { + std::auto_ptr col_list; + // Row iterator + CassIteratorPtr riterator(cci->CassIteratorFromResult(result->get()), cci); + while (cci->CassIteratorNext(riterator.get())) { + const CassRow *row(cci->CassIteratorGetRow(riterator.get())); + // Iterate over columns + size_t ccount(cci->CassResultColumnCount(result->get())); + // Partiiton key + GenDb::DbDataValueVec rkey; + for (size_t i = 0; i < rk_count; i++) { + const CassValue *cvalue(cci->CassRowGetColumn(row, i)); + assert(cvalue); + GenDb::DbDataValue db_value(CassValue2DbDataValue(cci, cvalue)); + rkey.push_back(db_value); + } + // Clustering key + GenDb::DbDataValueVec *cnames(new GenDb::DbDataValueVec); + for (size_t i = rk_count; i < rk_count + ck_count; i++) { + const CassValue *cvalue(cci->CassRowGetColumn(row, i)); + assert(cvalue); + GenDb::DbDataValue db_value(CassValue2DbDataValue(cci, cvalue)); + cnames->push_back(db_value); + } + // Values + GenDb::DbDataValueVec *values(new GenDb::DbDataValueVec); + for (size_t i = rk_count + ck_count; i < ccount; i++) { + const CassValue *cvalue(cci->CassRowGetColumn(row, i)); + assert(cvalue); + GenDb::DbDataValue db_value(CassValue2DbDataValue(cci, cvalue)); + values->push_back(db_value); + } + GenDb::NewCol *column(new GenDb::NewCol(cnames, values, 0)); + // Do we need a new ColList? + if (!col_list.get()) { + col_list.reset(new GenDb::ColList); + col_list->rowkey_ = rkey; + } + if (rkey != col_list->rowkey_) { + v_col_list->push_back(col_list.release()); + col_list.reset(new GenDb::ColList); + col_list->rowkey_ = rkey; + } + GenDb::NewColVec *v_columns(&col_list->columns_); + v_columns->push_back(column); + } + if (col_list.get()) { + v_col_list->push_back(col_list.release()); + } +} + +static void StaticCfGetResult(interface::CassLibrary *cci, CassResultPtr *result, GenDb::NewColVec *v_columns) { // Row iterator CassIteratorPtr riterator(cci->CassIteratorFromResult(result->get()), cci); @@ -1016,6 +1074,55 @@ static void GetStaticCfResult(interface::CassLibrary *cci, } } +void StaticCfGetResult(interface::CassLibrary *cci, + CassResultPtr *result, size_t rk_count, GenDb::ColListVec *v_col_list) { + std::auto_ptr col_list; + // Row iterator + CassIteratorPtr riterator(cci->CassIteratorFromResult(result->get()), cci); + while (cci->CassIteratorNext(riterator.get())) { + const CassRow *row(cci->CassIteratorGetRow(riterator.get())); + // Iterate over columns + size_t ccount(cci->CassResultColumnCount(result->get())); + // Partiiton key + GenDb::DbDataValueVec rkey; + for (size_t i = 0; i < rk_count; i++) { + const CassValue *cvalue(cci->CassRowGetColumn(row, i)); + assert(cvalue); + GenDb::DbDataValue db_value(CassValue2DbDataValue(cci, cvalue)); + rkey.push_back(db_value); + } + // Do we need a new ColList? + if (!col_list.get()) { + col_list.reset(new GenDb::ColList); + col_list->rowkey_ = rkey; + } + if (rkey != col_list->rowkey_) { + v_col_list->push_back(col_list.release()); + col_list.reset(new GenDb::ColList); + col_list->rowkey_ = rkey; + } + GenDb::NewColVec *v_columns(&col_list->columns_); + for (size_t i = 0; i < ccount; i++) { + CassString cname; + CassError rc(cci->CassResultColumnName(result->get(), i, + &cname.data, &cname.length)); + assert(rc == CASS_OK); + const CassValue *cvalue(cci->CassRowGetColumn(row, i)); + assert(cvalue); + GenDb::DbDataValue db_value(CassValue2DbDataValue(cci, cvalue)); + if (db_value.which() == GenDb::DB_VALUE_BLANK) { + continue; + } + GenDb::NewCol *column(new GenDb::NewCol( + std::string(cname.data, cname.length), db_value, 0)); + v_columns->push_back(column); + } + } + if (col_list.get()) { + v_col_list->push_back(col_list.release()); + } +} + static void OnExecuteQueryAsync(CassFuture *future, void *data) { assert(data); std::auto_ptr ctx( @@ -1036,16 +1143,16 @@ static void OnExecuteQueryAsync(CassFuture *future, void *data) { CassResultPtr result(cci->CassFutureGetResult(future), cci); // In case of select parse the results if (cci->CassResultColumnCount(result.get())) { - std::auto_ptr collist(new GenDb::ColList); - collist->cfname_ = rctx->cf_name_; - collist->rowkey_ = rctx->row_key_; + std::auto_ptr col_list(new GenDb::ColList); + col_list->cfname_ = rctx->cf_name_; + col_list->rowkey_ = rctx->row_key_; if (rctx->is_dynamic_cf_) { - GetDynamicCfResult(cci, &result, rctx->rk_count_, - rctx->ck_count_, &collist->columns_); + DynamicCfGetResult(cci, &result, rctx->rk_count_, + rctx->ck_count_, &col_list->columns_); } else { - GetStaticCfResult(cci, &result, &collist->columns_); + StaticCfGetResult(cci, &result, &col_list->columns_); } - ctx->cb_(db_rc, collist); + ctx->cb_(db_rc, col_list); return; } } @@ -1110,7 +1217,21 @@ static bool DynamicCfGetResultSync(interface::CassLibrary *cci, if (!success) { return success; } - GetDynamicCfResult(cci, &result, rk_count, ck_count, v_columns); + DynamicCfGetResult(cci, &result, rk_count, ck_count, v_columns); + return success; +} + +static bool DynamicCfGetResultSync(interface::CassLibrary *cci, + CassSession *session, const char *query, + size_t rk_count, size_t ck_count, CassConsistency consistency, + GenDb::ColListVec *v_col_list) { + CassResultPtr result(NULL, cci); + bool success(ExecuteQueryResultSync(cci, session, query, &result, + consistency)); + if (!success) { + return success; + } + DynamicCfGetResult(cci, &result, rk_count, ck_count, v_col_list); return success; } @@ -1134,7 +1255,20 @@ static bool StaticCfGetResultSync(interface::CassLibrary *cci, if (!success) { return success; } - GetStaticCfResult(cci, &result, v_columns); + StaticCfGetResult(cci, &result, v_columns); + return success; +} + +static bool StaticCfGetResultSync(interface::CassLibrary *cci, + CassSession *session, const char *query, size_t rk_count, + CassConsistency consistency, GenDb::ColListVec *v_col_list) { + CassResultPtr result(NULL, cci); + bool success(ExecuteQueryResultSync(cci, session, query, &result, + consistency)); + if (!success) { + return success; + } + StaticCfGetResult(cci, &result, rk_count, v_col_list); return success; } @@ -1565,6 +1699,27 @@ bool CqlIfImpl::SelectFromTableSync(const std::string &cfname, } } +bool CqlIfImpl::SelectFromTableSync(const std::string &cfname, + CassConsistency consistency, GenDb::ColListVec *out) { + if (session_state_ != SessionState::CONNECTED) { + return false; + } + std::string query(impl::CassSelectFromTable(cfname)); + size_t rk_count; + assert(impl::GetCassTablePartitionKeyCount(cci_, session_.get(), + keyspace_, cfname, &rk_count)); + if (IsTableStatic(cfname)) { + return impl::StaticCfGetResultSync(cci_, session_.get(), + query.c_str(), rk_count, consistency, out); + } else { + size_t ck_count; + assert(impl::GetCassTableClusteringKeyCount(cci_, session_.get(), + keyspace_, cfname, &ck_count)); + return impl::DynamicCfGetResultSync(cci_, session_.get(), + query.c_str(), rk_count, ck_count, consistency, out); + } +} + bool CqlIfImpl::SelectFromTableClusteringKeyRangeSync(const std::string &cfname, const GenDb::DbDataValueVec &rkey, const GenDb::ColumnNameRange &ck_range, CassConsistency consistency, @@ -2155,6 +2310,19 @@ bool CqlIf::Db_GetMultiRow(GenDb::ColListVec *out, const std::string &cfname, return true; } +bool CqlIf::Db_GetAllRows(GenDb::ColListVec *out, const std::string &cfname, + GenDb::DbConsistency::type dconsistency) { + CassConsistency consistency(impl::Db2CassConsistency(dconsistency)); + bool success(impl_->SelectFromTableSync(cfname, consistency, out)); + if (!success) { + IncrementTableReadFailStats(cfname); + IncrementErrors(GenDb::IfErrors::ERR_READ_COLUMN); + return success; + } + IncrementTableReadStats(cfname); + return success; +} + // Queue bool CqlIf::Db_GetQueueStats(uint64_t *queue_count, uint64_t *enqueues) const { diff --git a/src/database/cassandra/cql/cql_if.h b/src/database/cassandra/cql/cql_if.h index 5f196f4e8db..b420e33427c 100644 --- a/src/database/cassandra/cql/cql_if.h +++ b/src/database/cassandra/cql/cql_if.h @@ -79,6 +79,8 @@ class CqlIf : public GenDb::GenDbIf { const GenDb::ColumnNameRange &crange, GenDb::DbConsistency::type dconsistency, int task_id, int task_instance, GenDb::GenDbIf::DbGetRowCb cb); + virtual bool Db_GetAllRows(GenDb::ColListVec *out, + const std::string &cfname, GenDb::DbConsistency::type dconsistency); // Queue virtual bool Db_GetQueueStats(uint64_t *queue_count, uint64_t *enqueues) const; diff --git a/src/database/cassandra/cql/cql_if_impl.h b/src/database/cassandra/cql/cql_if_impl.h index 5e0fb692659..0db150b9fe8 100644 --- a/src/database/cassandra/cql/cql_if_impl.h +++ b/src/database/cassandra/cql/cql_if_impl.h @@ -30,6 +30,7 @@ std::string StaticCf2CassInsertIntoTable(const GenDb::ColList *v_columns); std::string DynamicCf2CassInsertIntoTable(const GenDb::ColList *v_columns); std::string StaticCf2CassPrepareInsertIntoTable(const GenDb::NewCf &cf); std::string DynamicCf2CassPrepareInsertIntoTable(const GenDb::NewCf &cf); +std::string CassSelectFromTable(const std::string &table); std::string PartitionKey2CassSelectFromTable(const std::string &table, const GenDb::DbDataValueVec &rkeys); std::string PartitionKeyAndClusteringKeyRange2CassSelectFromTable( @@ -186,6 +187,13 @@ struct CassAsyncQueryContext { boost::scoped_ptr result_ctx_; }; +void DynamicCfGetResult(interface::CassLibrary *cci, + CassResultPtr *result, size_t rk_count, + size_t ck_count, GenDb::ColListVec *v_col_list); +void StaticCfGetResult(interface::CassLibrary *cci, + CassResultPtr *result, size_t rk_count, + GenDb::ColListVec *v_col_list); + } // namespace impl // @@ -224,6 +232,8 @@ class CqlIfImpl { bool SelectFromTableSync(const std::string &cfname, const GenDb::DbDataValueVec &rkey, CassConsistency consistency, GenDb::NewColVec *out); + bool SelectFromTableSync(const std::string &cfname, + CassConsistency consistency, GenDb::ColListVec *out); bool SelectFromTableClusteringKeyRangeSync(const std::string &cfname, const GenDb::DbDataValueVec &rkey, const GenDb::ColumnNameRange &ck_range, CassConsistency consistency, diff --git a/src/database/cassandra/cql/test/cql_if_test.cc b/src/database/cassandra/cql/test/cql_if_test.cc index e0e93e95d13..24a42e01610 100644 --- a/src/database/cassandra/cql/test/cql_if_test.cc +++ b/src/database/cassandra/cql/test/cql_if_test.cc @@ -14,6 +14,7 @@ #include #include #include +#include class CqlIfTest : public ::testing::Test { protected: @@ -402,6 +403,15 @@ TEST_F(CqlIfTest, InsertIntoStaticTable) { EXPECT_EQ(expected_qstring, actual_qstring); } +TEST_F(CqlIfTest, SelectFromTable) { + std::string table("SelectTable"); + std::string actual_qstring( + cass::cql::impl::CassSelectFromTable(table)); + std::string expected_qstring( + "SELECT * FROM SelectTable"); + EXPECT_EQ(expected_qstring, actual_qstring); +} + TEST_F(CqlIfTest, SelectFromTablePartitionKey) { std::string table("PartitionKeySelectTable"); std::string actual_qstring( @@ -532,6 +542,200 @@ TEST_F(CqlIfTest, SelectFromTableSlice) { EXPECT_EQ(expected_qstring4, actual_string4); } +using ::testing::_; +using ::testing::Return; +using ::testing::DoAll; +using ::testing::SetArgPointee; +using ::testing::ContainerEq; + +TEST_F(CqlIfTest, DynamicCfGetResultAllRows) { + cass::cql::test::MockCassLibrary mock_cci; + size_t rk_count(1); + size_t ck_count(1); + size_t ccount(rk_count + ck_count + 1); + size_t rows(3); + EXPECT_CALL(mock_cci, CassIteratorNext(_)) + .Times(rows + 1) + .WillOnce(Return(cass_true)) + .WillOnce(Return(cass_true)) + .WillOnce(Return(cass_true)) + .WillOnce(Return(cass_false)); + EXPECT_CALL(mock_cci, CassResultColumnCount(_)) + .Times(rows) + .WillRepeatedly(Return(ccount)); + // Return dummy pointer to avoid assert + uint8_t dummy_cass_value; + EXPECT_CALL(mock_cci, CassRowGetColumn(_, _)) + .Times(rows * ccount) + .WillRepeatedly(Return( + reinterpret_cast(&dummy_cass_value))); + EXPECT_CALL(mock_cci, GetCassValueType(_)) + .Times(rows * ccount) + .WillRepeatedly(Return(CASS_VALUE_TYPE_TEXT)); + EXPECT_CALL(mock_cci, CassValueGetString(_, _, _)) + .Times(rows * ccount) + .WillOnce(DoAll(SetArgPointee<1>("key"), + SetArgPointee<2>(strlen("key")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("column"), + SetArgPointee<2>(strlen("column")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("value"), + SetArgPointee<2>(strlen("value")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("key"), + SetArgPointee<2>(strlen("key")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("column1"), + SetArgPointee<2>(strlen("column1")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("value1"), + SetArgPointee<2>(strlen("value1")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("key1"), + SetArgPointee<2>(strlen("key1")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("column"), + SetArgPointee<2>(strlen("column")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("value"), + SetArgPointee<2>(strlen("value")), Return(CASS_OK))); + GenDb::ColList *col_list(new GenDb::ColList); + col_list->rowkey_.push_back("key"); + GenDb::NewCol *column(new GenDb::NewCol( + new GenDb::DbDataValueVec(1, "column"), + new GenDb::DbDataValueVec(1, "value"), 0)); + col_list->columns_.push_back(column); + GenDb::NewCol *column1(new GenDb::NewCol( + new GenDb::DbDataValueVec(1, "column1"), + new GenDb::DbDataValueVec(1, "value1"), 0)); + col_list->columns_.push_back(column1); + GenDb::ColList *col_list1(new GenDb::ColList); + col_list1->rowkey_.push_back("key1"); + GenDb::NewCol *column2(new GenDb::NewCol( + new GenDb::DbDataValueVec(1, "column"), + new GenDb::DbDataValueVec(1, "value"), 0)); + col_list1->columns_.push_back(column2); + GenDb::ColListVec expected_v_col_list; + expected_v_col_list.push_back(col_list); + expected_v_col_list.push_back(col_list1); + GenDb::ColListVec actual_v_col_list; + cass::cql::impl::CassResultPtr result(NULL, &mock_cci); + cass::cql::impl::DynamicCfGetResult(&mock_cci, &result, rk_count, + ck_count, &actual_v_col_list); + EXPECT_THAT(actual_v_col_list, ContainerEq(expected_v_col_list)); +} + +TEST_F(CqlIfTest, StaticCfGetResultAllRows) { + cass::cql::test::MockCassLibrary mock_cci; + size_t rk_count(1); + size_t ccount(rk_count + 2); + size_t rows(3); + EXPECT_CALL(mock_cci, CassIteratorNext(_)) + .Times(rows + 1) + .WillOnce(Return(cass_true)) + .WillOnce(Return(cass_true)) + .WillOnce(Return(cass_true)) + .WillOnce(Return(cass_false)); + EXPECT_CALL(mock_cci, CassResultColumnCount(_)) + .Times(rows) + .WillRepeatedly(Return(ccount)); + EXPECT_CALL(mock_cci, CassResultColumnName(_, _, _, _)) + .Times(rows * ccount) + .WillOnce(DoAll(SetArgPointee<2>("KeyRow"), + SetArgPointee<3>(strlen("KeyRow")), + Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<2>("Column1"), + SetArgPointee<3>(strlen("Column1")), + Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<2>("Column2"), + SetArgPointee<3>(strlen("Column2")), + Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<2>("KeyRow"), + SetArgPointee<3>(strlen("KeyRow")), + Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<2>("Column1"), + SetArgPointee<3>(strlen("Column1")), + Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<2>("Column2"), + SetArgPointee<3>(strlen("Column2")), + Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<2>("KeyRow"), + SetArgPointee<3>(strlen("KeyRow")), + Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<2>("Column1"), + SetArgPointee<3>(strlen("Column1")), + Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<2>("Column2"), + SetArgPointee<3>(strlen("Column2")), + Return(CASS_OK))); + // Return dummy pointer to avoid assert + uint8_t dummy_cass_value; + EXPECT_CALL(mock_cci, CassRowGetColumn(_, _)) + .Times(rows * (rk_count + ccount)) + .WillRepeatedly(Return( + reinterpret_cast(&dummy_cass_value))); + EXPECT_CALL(mock_cci, GetCassValueType(_)) + .Times(rows * (rk_count + ccount)) + .WillRepeatedly(Return(CASS_VALUE_TYPE_TEXT)); + EXPECT_CALL(mock_cci, CassValueGetString(_, _, _)) + .Times(rows * (rk_count + ccount)) + .WillOnce(DoAll(SetArgPointee<1>("key"), + SetArgPointee<2>(strlen("key")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("key"), + SetArgPointee<2>(strlen("key")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("column1"), + SetArgPointee<2>(strlen("column1")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("column2"), + SetArgPointee<2>(strlen("column2")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("key1"), + SetArgPointee<2>(strlen("key1")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("key1"), + SetArgPointee<2>(strlen("key1")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("column11"), + SetArgPointee<2>(strlen("column11")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("column21"), + SetArgPointee<2>(strlen("column21")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("key2"), + SetArgPointee<2>(strlen("key2")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("key2"), + SetArgPointee<2>(strlen("key2")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("column12"), + SetArgPointee<2>(strlen("column12")), Return(CASS_OK))) + .WillOnce(DoAll(SetArgPointee<1>("column22"), + SetArgPointee<2>(strlen("column22")), Return(CASS_OK))); + + GenDb::ColListVec expected_v_col_list; + // ColList + GenDb::ColList *col_list(new GenDb::ColList); + col_list->rowkey_.push_back("key"); + GenDb::NewCol *rcolumn(new GenDb::NewCol("KeyRow", "key", 0)); + col_list->columns_.push_back(rcolumn); + GenDb::NewCol *column1(new GenDb::NewCol("Column1", "column1", 0)); + col_list->columns_.push_back(column1); + GenDb::NewCol *column2(new GenDb::NewCol("Column2", "column2", 0)); + col_list->columns_.push_back(column2); + expected_v_col_list.push_back(col_list); + // ColList1 + GenDb::ColList *col_list1(new GenDb::ColList); + col_list1->rowkey_.push_back("key1"); + GenDb::NewCol *rcolumn1(new GenDb::NewCol("KeyRow", "key1", 0)); + col_list1->columns_.push_back(rcolumn1); + GenDb::NewCol *column11(new GenDb::NewCol("Column1", "column11", 0)); + col_list1->columns_.push_back(column11); + GenDb::NewCol *column21(new GenDb::NewCol("Column2", "column21", 0)); + col_list1->columns_.push_back(column21); + expected_v_col_list.push_back(col_list1); + // ColList2 + GenDb::ColList *col_list2(new GenDb::ColList); + col_list2->rowkey_.push_back("key2"); + GenDb::NewCol *rcolumn2(new GenDb::NewCol("KeyRow", "key2", 0)); + col_list2->columns_.push_back(rcolumn2); + GenDb::NewCol *column12(new GenDb::NewCol("Column1", "column12", 0)); + col_list2->columns_.push_back(column12); + GenDb::NewCol *column22(new GenDb::NewCol("Column2", "column22", 0)); + col_list2->columns_.push_back(column22); + expected_v_col_list.push_back(col_list2); + + GenDb::ColListVec actual_v_col_list; + cass::cql::impl::CassResultPtr result(NULL, &mock_cci); + cass::cql::impl::StaticCfGetResult(&mock_cci, &result, rk_count, + &actual_v_col_list); + EXPECT_THAT(actual_v_col_list, ContainerEq(expected_v_col_list)); +} + int main(int argc, char **argv) { LoggingInit(); ::testing::InitGoogleTest(&argc, argv); diff --git a/src/database/cassandra/cql/test/mock_cql_lib_if.h b/src/database/cassandra/cql/test/mock_cql_lib_if.h new file mode 100644 index 00000000000..a6d6be65dae --- /dev/null +++ b/src/database/cassandra/cql/test/mock_cql_lib_if.h @@ -0,0 +1,171 @@ +// +// Copyright (c) 2016 Juniper Networks, Inc. All rights reserved. +// + +#ifndef DATABASE_CASSANDRA_CQL_TEST_MOCK_CQL_LIB_IF_H_ +#define DATABASE_CASSANDRA_CQL_TEST_MOCK_CQL_LIB_IF_H_ + +#include +#include + +namespace cass { +namespace cql { +namespace test { + +class MockCassLibrary : public interface::CassLibrary { + public: + + // CassCluster + MOCK_METHOD0(CassClusterNew, CassCluster* ()); + MOCK_METHOD1(CassClusterFree, void (CassCluster* cluster)); + MOCK_METHOD2(CassClusterSetContactPoints, CassError (CassCluster* cluster, + const char* contact_points)); + MOCK_METHOD2(CassClusterSetPort, CassError (CassCluster* cluster, + int port)); + MOCK_METHOD3(CassClusterSetCredentials, void (CassCluster* cluster, + const char* username, const char* password)); + MOCK_METHOD2(CassClusterSetNumThreadsIo, CassError (CassCluster* cluster, + unsigned num_threads)); + MOCK_METHOD2(CassClusterSetPendingRequestsHighWaterMark, CassError ( + CassCluster* cluster, unsigned num_requests)); + MOCK_METHOD2(CassClusterSetPendingRequestsLowWaterMark, CassError ( + CassCluster* cluster, unsigned num_requests)); + MOCK_METHOD2(CassClusterSetWriteBytesHighWaterMark, CassError ( + CassCluster* cluster, unsigned num_bytes)); + MOCK_METHOD2(CassClusterSetWriteBytesLowWaterMark, CassError ( + CassCluster* cluster, unsigned num_bytes)); + + // CassSession + MOCK_METHOD0(CassSessionNew, CassSession* ()); + MOCK_METHOD1(CassSessionFree, void (CassSession* session)); + MOCK_METHOD2(CassSessionConnect, CassFuture* (CassSession* session, + const CassCluster* cluster)); + MOCK_METHOD1(CassSessionClose, CassFuture* (CassSession* session)); + MOCK_METHOD2(CassSessionExecute, CassFuture* (CassSession* session, + const CassStatement* statement)); + MOCK_METHOD1(CassSessionGetSchemaMeta, const CassSchemaMeta* ( + const CassSession* session)); + MOCK_METHOD2(CassSessionPrepare, CassFuture* (CassSession* session, + const char* query)); + MOCK_METHOD2(CassSessionGetMetrics, void (const CassSession* session, + CassMetrics* output)); + + // CassSchema + MOCK_METHOD1(CassSchemaMetaFree, void (const CassSchemaMeta* schema_meta)); + MOCK_METHOD2(CassSchemaMetaKeyspaceByName, const CassKeyspaceMeta* ( + const CassSchemaMeta* schema_meta, const char* keyspace)); + MOCK_METHOD2(CassKeyspaceMetaTableByName, const CassTableMeta* ( + const CassKeyspaceMeta* keyspace_meta, const char* table)); + MOCK_METHOD1(CassTableMetaPartitionKeyCount, size_t ( + const CassTableMeta* table_meta)); + MOCK_METHOD1(CassTableMetaClusteringKeyCount, size_t ( + const CassTableMeta* table_meta)); + + // CassFuture + MOCK_METHOD1(CassFutureFree, void (CassFuture* future)); + MOCK_METHOD3(CassFutureSetCallback, CassError (CassFuture* future, + CassFutureCallback callback, void* data)); + MOCK_METHOD1(CassFutureWait, void (CassFuture* future)); + MOCK_METHOD1(CassFutureGetResult, const CassResult* (CassFuture* future)); + MOCK_METHOD3(CassFutureErrorMessage, void (CassFuture* future, + const char** message, size_t* message_length)); + MOCK_METHOD1(CassFutureErrorCode, CassError (CassFuture* future)); + MOCK_METHOD1(CassFutureGetPrepared, const CassPrepared* ( + CassFuture* future)); + + // CassResult + MOCK_METHOD1(CassResultFree, void (const CassResult* result)); + MOCK_METHOD1(CassResultColumnCount, size_t (const CassResult* result)); + MOCK_METHOD4(CassResultColumnName, CassError (const CassResult *result, + size_t index, const char** name, size_t* name_length)); + + // CassIterator + MOCK_METHOD1(CassIteratorFree, void (CassIterator* iterator)); + MOCK_METHOD1(CassIteratorFromResult, CassIterator* ( + const CassResult* result)); + MOCK_METHOD1(CassIteratorNext, cass_bool_t (CassIterator* iterator)); + MOCK_METHOD1(CassIteratorGetRow, const CassRow* ( + const CassIterator* iterator)); + + // CassStatement + MOCK_METHOD2(CassStatementNew, CassStatement* (const char* query, + size_t parameter_count)); + MOCK_METHOD1(CassStatementFree, void (CassStatement* statement)); + MOCK_METHOD2(CassStatementSetConsistency, CassError ( + CassStatement* statement, CassConsistency consistency)); + MOCK_METHOD4(CassStatementBindStringN, CassError (CassStatement* statement, + size_t index, const char* value, size_t value_length)); + MOCK_METHOD3(CassStatementBindInt32, CassError (CassStatement* statement, + size_t index, cass_int32_t value)); + MOCK_METHOD3(CassStatementBindInt64, CassError (CassStatement* statement, + size_t index, cass_int64_t value)); + MOCK_METHOD3(CassStatementBindUuid, CassError (CassStatement* statement, + size_t index, CassUuid value)); + MOCK_METHOD3(CassStatementBindDouble, CassError (CassStatement* statement, + size_t index, cass_double_t value)); + MOCK_METHOD3(CassStatementBindInet, CassError (CassStatement* statement, + size_t index, CassInet value)); + MOCK_METHOD4(CassStatementBindBytes, CassError (CassStatement* statement, + size_t index, const cass_byte_t* value, size_t value_length)); + MOCK_METHOD5(CassStatementBindStringByNameN, CassError ( + CassStatement* statement, const char* name, size_t name_length, + const char* value, size_t value_length)); + MOCK_METHOD3(CassStatementBindInt32ByName, CassError ( + CassStatement* statement, const char* name, cass_int32_t value)); + MOCK_METHOD3(CassStatementBindInt64ByName, CassError ( + CassStatement* statement, const char* name, cass_int64_t value)); + MOCK_METHOD3(CassStatementBindUuidByName, CassError ( + CassStatement* statement, const char* name, CassUuid value)); + MOCK_METHOD3(CassStatementBindDoubleByName, CassError ( + CassStatement* statement, const char* name, cass_double_t value)); + MOCK_METHOD3(CassStatementBindInetByName, CassError ( + CassStatement* statement, const char* name, CassInet value)); + MOCK_METHOD5(CassStatementBindBytesByNameN, CassError ( + CassStatement* statement, const char* name, size_t name_length, + const cass_byte_t* value, size_t value_length)); + + // CassPrepare + MOCK_METHOD1(CassPreparedFree, void (const CassPrepared* prepared)); + MOCK_METHOD1(CassPreparedBind, CassStatement* ( + const CassPrepared* prepared)); + + // CassValue + MOCK_METHOD1(GetCassValueType, CassValueType (const CassValue* value)); + MOCK_METHOD3(CassValueGetString, CassError (const CassValue* value, + const char** output, size_t* output_size)); + MOCK_METHOD2(CassValueGetInt8, CassError (const CassValue* value, + cass_int8_t* output)); + MOCK_METHOD2(CassValueGetInt16, CassError (const CassValue* value, + cass_int16_t* output)); + MOCK_METHOD2(CassValueGetInt32, CassError (const CassValue* value, + cass_int32_t* output)); + MOCK_METHOD2(CassValueGetInt64, CassError (const CassValue* value, + cass_int64_t* output)); + MOCK_METHOD2(CassValueGetUuid, CassError (const CassValue* value, + CassUuid* output)); + MOCK_METHOD2(CassValueGetDouble, CassError (const CassValue* value, + cass_double_t* output)); + MOCK_METHOD2(CassValueGetInet, CassError (const CassValue* value, + CassInet* output)); + MOCK_METHOD3(CassValueGetBytes, CassError (const CassValue* value, + const cass_byte_t** output, size_t* output_size)); + + // CassInet + MOCK_METHOD1(CassInetInitV4, CassInet (const cass_uint8_t* address)); + MOCK_METHOD1(CassInetInitV6, CassInet (const cass_uint8_t* address)); + + // CassRow + MOCK_METHOD2(CassRowGetColumn, const CassValue* (const CassRow* row, + size_t index)); + + // CassLog + MOCK_METHOD1(CassLogSetLevel, void (CassLogLevel log_level)); + MOCK_METHOD2(CassLogSetCallback, void (CassLogCallback callback, + void* data)); +}; + +} // namespace test +} // namespace cql +} // namespace cass + +#endif // DATABASE_CASSANDRA_CQL_TEST_MOCK_CQL_LIB_IF_H_ diff --git a/src/database/gendb_if.h b/src/database/gendb_if.h index 448869e5f9d..f040592acc5 100644 --- a/src/database/gendb_if.h +++ b/src/database/gendb_if.h @@ -166,6 +166,12 @@ struct ColList { NewColVec columns_; }; +inline bool operator==(const ColList &lhs, const ColList &rhs) { + return (lhs.cfname_ == rhs.cfname_ && + lhs.rowkey_ == rhs.rowkey_ && + lhs.columns_ == rhs.columns_); +} + typedef boost::ptr_vector ColListVec; struct ColumnNameRange { @@ -249,6 +255,8 @@ class GenDbIf { const DbDataValueVec& rowkey, const ColumnNameRange &crange, DbConsistency::type dconsistency, int task_id, int task_instance, DbGetRowCb cb) = 0; + virtual bool Db_GetAllRows(ColListVec *ret, + const std::string& cfname, DbConsistency::type dconsistency) = 0; // Queue virtual bool Db_GetQueueStats(uint64_t *queue_count, uint64_t *enqueues) const = 0;