Commit c164ebc2 authored by Razvan Becheriu's avatar Razvan Becheriu

refactored cassandra backend and fixed issues

parent 66e44792
#include <dhcpsrv/cql_exchange.h>
/// @name CqlBind auxiliary methods for binding data into Cassandra format:
/// @{
/// @todo These void* cast are unsafe. See ticket #4525.
static CassError CqlBindNone(CassStatement* statement, size_t index,
void*) {
return cass_statement_bind_null(statement, index);
}
static CassError CqlBindBool(CassStatement* statement, size_t index,
void* value) {
return cass_statement_bind_bool(statement, index,
*(static_cast<cass_bool_t*>(value)));
}
static CassError CqlBindInt32(CassStatement* statement, size_t index,
void* value) {
return cass_statement_bind_int32(statement, index,
*(static_cast<cass_int32_t*>(value)));
}
static CassError CqlBindInt64(CassStatement* statement, size_t index,
void* value) {
return cass_statement_bind_int64(statement, index,
*(static_cast<cass_int64_t*>(value)));
}
static CassError CqlBindTimestamp(CassStatement* statement, size_t index,
void* value) {
return cass_statement_bind_int64(statement, index,
*(static_cast<cass_int64_t*>(value)));
}
static CassError CqlBindString(CassStatement* statement, size_t index,
void* value) {
return cass_statement_bind_string(statement, index,
static_cast<std::string*>(value)->c_str());
}
static CassError CqlBindBytes(CassStatement* statement, size_t index,
void* value) {
return cass_statement_bind_bytes(statement, index,
static_cast<std::vector<cass_byte_t>*>(value)->data(),
static_cast<std::vector<cass_byte_t>*>(value)->size());
}
/// @}
static CassError CqlGetNone(const CassValue*, void*) {
return CASS_OK;
}
static CassError CqlGetBool(const CassValue* value, void* data) {
return cass_value_get_bool(value, static_cast<cass_bool_t*>(data));
}
static CassError CqlGetInt32(const CassValue* value, void* data) {
return cass_value_get_int32(value, static_cast<cass_int32_t*>(data));
}
static CassError CqlGetInt64(const CassValue* value, void* data) {
return cass_value_get_int64(value, static_cast<cass_int64_t*>(data));
}
static CassError CqlGetTimestamp(const CassValue* value, void* data) {
return cass_value_get_int64(value, static_cast<cass_int64_t*>(data));
}
static CassError CqlGetString(const CassValue* value, void* data) {
const char* dataValue;
size_t sizeValue;
CassError cassError = cass_value_get_string(value,
static_cast<const char**>(&dataValue), &sizeValue);
static_cast<std::string*>(data)->assign(dataValue, dataValue + sizeValue);
return cassError;
}
static CassError CqlGetBytes(const CassValue* value, void* data) {
const cass_byte_t* dataValue;
size_t sizeValue;
CassError cassError = cass_value_get_bytes(value,
static_cast<const cass_byte_t**>(&dataValue), &sizeValue);
static_cast<std::vector<cass_byte_t>*>(data)->assign(dataValue, dataValue +
sizeValue);
return cassError;
}
namespace isc {
namespace dhcp {
struct CqlFunctionData CqlFunctions[] = {
{CqlBindNone, CqlGetNone},
{CqlBindBool, CqlGetBool},
{CqlBindInt32, CqlGetInt32},
{CqlBindInt64, CqlGetInt64},
{CqlBindTimestamp, CqlGetTimestamp},
{CqlBindString, CqlGetString},
{CqlBindBytes, CqlGetBytes}
};
ExchangeDataType
CqlCommon::getDataType(const uint32_t stindex, int pindex,
const SqlExchange& exchange, CqlTaggedStatement* tagged_statements) {
if (tagged_statements[stindex].params_ &&
tagged_statements[stindex].params_[pindex]) {
const ExchangeColumnInfoContainerName& idx = exchange.parameters_.get<1>();
const ExchangeColumnInfoContainerNameRange& range =
idx.equal_range(tagged_statements[stindex].params_[pindex]);
if (std::distance(range.first, range.second) > 0) {
return (*range.first)->type_;
}
}
return EXCHANGE_DATA_TYPE_NONE;
}
void
CqlCommon::bindData(CassStatement* statement, const uint32_t stindex,
CqlDataArray& data, const SqlExchange& exchange, CqlTaggedStatement* tagged_statements) {
if (tagged_statements[stindex].params_ == NULL) {
return;
}
for (int i = 0; tagged_statements[stindex].params_[i]; i++) {
ExchangeDataType type = CqlCommon::getDataType(stindex, i, exchange, tagged_statements);
if (type >= sizeof(CqlFunctions) / sizeof(CqlFunctions[0])) {
isc_throw(BadValue, "index " << stindex << " out of bounds");
}
CqlFunctions[type].sqlBindFunction_(statement, i, data.values_[i]);
}
}
void
CqlCommon::getData(const CassRow* row, const int pindex, CqlDataArray& data,
const int dindex, const SqlExchange& exchange) {
const CassValue* value;
if (pindex >= exchange.parameters_.size()) {
return;
}
const ExchangeColumnInfoContainerIndex& idx = exchange.parameters_.get<2>();
const ExchangeColumnInfoContainerIndexRange& range = idx.equal_range(pindex);
if (std::distance(range.first, range.second) > 0) {
std::string name = (*range.first)->name_;
ExchangeDataType type = (*range.first)->type_;
value = cass_row_get_column_by_name(row, name.c_str());
if (NULL == value) {
isc_throw(BadValue, "column name " << name << " doesn't exist");
}
if (type >= sizeof(CqlFunctions) / sizeof(CqlFunctions[0])) {
isc_throw(BadValue, "index " << type << " out of bounds");
}
CqlFunctions[type].sqlGetFunction_(value, data.values_[dindex]);
}
}
}; // end of isc::dhcp namespace
}; // end of isc namespace
#ifndef CQL_EXCHANGE_H
#define CQL_EXCHANGE_H
#include <exceptions/exceptions.h>
#include <dhcpsrv/sql_common.h>
#include <vector>
#include <cassandra.h>
namespace isc {
namespace dhcp {
/// @brief Defines a single query
///
/// @param params_ Bind parameter names
/// @param name_ Short name of the query.
/// @param text_ Text representation of the actual query.
struct CqlTaggedStatement {
const char** params_;
const char* name_;
const char* text_;
};
typedef CassError (*CqlBindFunction)(CassStatement* statement, size_t index,
void* value);
typedef CassError (*CqlGetFunction)(const CassValue* value, void* data);
struct CqlFunctionData {
CqlBindFunction sqlBindFunction_;
CqlGetFunction sqlGetFunction_;
};
extern struct CqlFunctionData CqlFunctions[];
/// @brief Structure used to bind C++ input values to dynamic SQL parameters
/// The structure contains a vector which store the input values,
/// This vector is passed directly into the
/// CQL execute call.
///
/// Note that the data values are stored as pointers. These pointers need
/// to be valid for the duration of the CQL statement execution. In other
/// words populating them with pointers to values that go out of scope
/// before statement is executed is a bad idea.
struct CqlDataArray {
/// Add void pointer to a vector of pointers to the data values.
std::vector<void*> values_;
void add(void* value) {
values_.push_back(value);
}
/// Remove void pointer from a vector of pointers to the data values.
void remove(int index) {
if (values_.size() <= index) {
isc_throw(BadValue, "Index " << index << " out of bounds: [0, " <<
(values_.size() - 1) << "]");
}
values_.erase(values_.begin() + index);
}
/// Get size.
size_t size() {
return values_.size();
}
};
class CqlCommon {
public:
/// @brief Returns type of data for specific parameter.
///
/// Returns type of a given parameter of a given statement.
///
/// @param stindex Index of statement being executed.
/// @param pindex Index of the parameter for a given statement.
/// @param exchange Exchange object to use
/// @param tagged_statements CqlTaggedStatement array to use
static ExchangeDataType
getDataType(const uint32_t stindex, int pindex,
const SqlExchange& exchange, CqlTaggedStatement* tagged_statements);
/// @brief Binds data specified in data
///
/// This method calls one of cass_value_bind_{none,bool,int32,int64,string,bytes}.
/// It is used to bind C++ data types used by Kea into formats used by Cassandra.
///
/// @param statement Statement object representing the query
/// @param stindex Index of statement being executed
/// @param data array that has been created for the type of lease in question.
/// @param exchange Exchange object to use
/// @param tagged_statements CqlTaggedStatement array to use
static void
bindData(CassStatement* statement, const uint32_t stindex,
CqlDataArray& data, const SqlExchange& exchange, CqlTaggedStatement* tagged_statements);
/// @brief Retrieves data returned by Cassandra.
///
/// This method calls one of cass_value_get_{none,bool,int32,int64,string,bytes}.
/// It is used to retrieve data returned by Cassandra into standard C++ types
/// used by Kea.
///
/// @param row row of data returned by CQL library
/// @param pindex Index of statement being executed
/// @param data array that has been created for the type of lease in question.
/// @param size a structure that holds information about size
/// @param dindex data index (specifies which entry in size array is used)
/// @param exchange Exchange object to use
static void
getData(const CassRow* row, const int pindex, CqlDataArray& data,
const int dindex, const SqlExchange& exchange);
};
class CqlVersionExchange : public virtual SqlExchange {
public:
/// @brief Constructor
///
/// The initialization of the variables here is only to satisfy cppcheck -
/// all variables are initialized/set in the methods before they are used.
CqlVersionExchange() {
// Set the column names
const size_t MAX_COLUMNS = 2U;
parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("version",
parameters_.size(), EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("minor",
parameters_.size(), EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
BOOST_ASSERT(parameters_.size() == MAX_COLUMNS);
}
};
}; // end of isc::dhcp namespace
}; // end of isc namespace
#endif // CQL_EXCHANGE_H
#ifndef SQL_COMMON_H
#define SQL_COMMON_H
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/member.hpp>
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <vector>
namespace isc {
namespace dhcp {
/// @brief Used to map server data types with internal backend storage data
/// types.
enum ExchangeDataType {
EXCHANGE_DATA_TYPE_NONE,
EXCHANGE_DATA_TYPE_BOOL,
EXCHANGE_DATA_TYPE_INT32,
EXCHANGE_DATA_TYPE_INT64,
EXCHANGE_DATA_TYPE_TIMESTAMP,
EXCHANGE_DATA_TYPE_STRING,
EXCHANGE_DATA_TYPE_BYTES
};
/// @brief Used to specify the direction of the data exchange between the
/// database and the server.
enum ExchangeDataTypeIO {
EXCHANGE_DATA_TYPE_IO_IN,
EXCHANGE_DATA_TYPE_IO_OUT,
EXCHANGE_DATA_TYPE_IO_IN_OUT
};
/// @brief Used to map the column name with internal backend storage data types.
struct ExchangeColumnInfo {
ExchangeColumnInfo () : name_(""), index_(0), type_io_(EXCHANGE_DATA_TYPE_IO_IN),
type_(EXCHANGE_DATA_TYPE_NONE) {};
ExchangeColumnInfo (const char* name, const uint32_t index,
const ExchangeDataTypeIO type_io, const ExchangeDataType type) :
name_(name), index_(index), type_io_(type_io), type_(type) {};
std::string name_;
uint32_t index_;
ExchangeDataTypeIO type_io_;
ExchangeDataType type_;
};
typedef boost::shared_ptr<ExchangeColumnInfo> ExchangeColumnInfoPtr;
typedef boost::multi_index_container<
// Container comprises elements of ExchangeColumnInfoPtr type.
ExchangeColumnInfoPtr,
// Here we start enumerating various indexes.
boost::multi_index::indexed_by<
// Sequenced index allows accessing elements in the same way as elements
// in std::list.
// Sequenced is an index #0.
boost::multi_index::sequenced<>,
// Start definition of index #1.
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
ExchangeColumnInfo,
std::string,
&ExchangeColumnInfo::name_
>
>,
// Start definition of index #2.
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
ExchangeColumnInfo,
uint32_t,
&ExchangeColumnInfo::index_
>
>
>
> ExchangeColumnInfoContainer;
/// Pointer to the ExchangeColumnInfoContainer object.
typedef boost::shared_ptr<ExchangeColumnInfoContainer> ExchangeColumnInfoContainerPtr;
/// Type of the index #1 - name.
typedef ExchangeColumnInfoContainer::nth_index<1>::type ExchangeColumnInfoContainerName;
/// Pair of iterators to represent the range of ExchangeColumnInfo having the
/// same name value. The first element in this pair represents
/// the beginning of the range, the second element represents the end.
typedef std::pair<ExchangeColumnInfoContainerName::const_iterator,
ExchangeColumnInfoContainerName::const_iterator> ExchangeColumnInfoContainerNameRange;
/// Type of the index #2 - index.
typedef ExchangeColumnInfoContainer::nth_index<2>::type ExchangeColumnInfoContainerIndex;
/// Pair of iterators to represent the range of ExchangeColumnInfo having the
/// same index value. The first element in this pair represents
/// the beginning of the range, the second element represents the end.
typedef std::pair<ExchangeColumnInfoContainerIndex::const_iterator,
ExchangeColumnInfoContainerIndex::const_iterator> ExchangeColumnInfoContainerIndexRange;
class SqlExchange {
public:
SqlExchange () {}
virtual ~SqlExchange() {}
ExchangeColumnInfoContainer parameters_; ///< Column names and types
};
} //dhcp
} //isc
#endif // SQL_COMMON_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment