26 #include <boost/multi_index/hashed_index.hpp>
27 #include <boost/multi_index/member.hpp>
28 #include <boost/multi_index/sequenced_index.hpp>
29 #include <boost/multi_index_container.hpp>
30 #include <boost/noncopyable.hpp>
31 #include <boost/shared_ptr.hpp>
44 #define KEA_CASS_CHECK(cass_error) \
46 if (cass_error != CASS_OK) { \
56 return std::hash<size_t>{}(
static_cast<size_t>(key));
61 typedef std::unordered_map<ExchangeDataType, CqlFunction, ExchangeDataTypeHash>
81 typedef std::unordered_map<std::type_index, ExchangeDataType>
AnyTypeMap;
85 typedef std::unordered_map<uint8_t, ExchangeDataType>
CassTypeMap;
89 static AnyTypeMap ANY_TYPE_MAP = {
103 static CassTypeMap CASS_TYPE_MAP = {
140 "Udt::Udt(): UDT " <<
name_ <<
" does not exist ");
146 "Udt::Udt(): Type " <<
name_
147 <<
" is not a UDT as expected. ");
171 if (size() <= index) {
173 "AnyArray::remove(): index "
174 << index <<
" out of bounds: [0, " << (size() - 1)
177 erase(begin() + index);
185 CqlBindNone(
const boost::any& ,
187 CassStatement* statement) {
188 return cass_statement_bind_null(statement, index);
192 CqlBindBool(
const boost::any& value,
194 CassStatement* statement) {
195 return cass_statement_bind_bool(statement, index,
196 *boost::any_cast<cass_bool_t*>(value));
200 CqlBindInt8(
const boost::any& value,
202 CassStatement* statement) {
203 return cass_statement_bind_int8(statement, index,
204 *boost::any_cast<cass_int8_t*>(value));
208 CqlBindInt16(
const boost::any& value,
210 CassStatement* statement) {
211 return cass_statement_bind_int16(statement, index,
212 *boost::any_cast<cass_int16_t*>(value));
216 CqlBindInt32(
const boost::any& value,
218 CassStatement* statement) {
219 return cass_statement_bind_int32(statement, index,
220 *boost::any_cast<cass_int32_t*>(value));
224 CqlBindInt64(
const boost::any& value,
226 CassStatement* statement) {
227 return cass_statement_bind_int64(statement, index,
228 *boost::any_cast<cass_int64_t*>(value));
232 CqlBindString(
const boost::any& value,
234 CassStatement* statement) {
235 return cass_statement_bind_string(
236 statement, index, boost::any_cast<std::string*>(value)->c_str());
240 CqlBindBytes(
const boost::any& value,
242 CassStatement* statement) {
244 return cass_statement_bind_bytes(statement, index, blob_value->data(),
249 CqlBindUuid(
const boost::any& value,
251 CassStatement* statement) {
252 return cass_statement_bind_uuid(statement, index,
253 *boost::any_cast<CassUuid*>(value));
257 CqlBindUdt(
const boost::any& value,
259 CassStatement* statement) {
260 Udt* udt = boost::any_cast<Udt*>(value);
263 isc_throw(BadValue,
"Invalid value specified, not an Udt object");
270 for (boost::any& element : *udt) {
273 CQL_FUNCTIONS[
exchangeType(element)].cqlUdtSetFunction_(
274 element, i, udt->cass_user_type_));
275 }
catch (
const boost::bad_any_cast& exception) {
277 "CqlCommon::udtSetData(): "
279 <<
" when binding parameter of type "
280 << element.type().name()
281 <<
"in UDT with function CQL_FUNCTIONS["
287 return cass_statement_bind_user_type(statement, index,
288 udt->cass_user_type_);
292 CqlBindCollection(
const boost::any& value,
294 CassStatement* statement) {
297 CassCollection* collection =
298 cass_collection_new(CASS_COLLECTION_TYPE_SET, elements->size());
302 for (boost::any& element : *elements) {
305 element, collection));
308 const CassError cass_error =
309 cass_statement_bind_collection(statement, index, collection);
310 cass_collection_free(collection);
320 CqlUdtSetNone(
const boost::any& ,
321 const size_t& position,
322 CassUserType* cass_user_type) {
323 return cass_user_type_set_null(cass_user_type, position);
327 CqlUdtSetBool(
const boost::any& udt_member,
328 const size_t& position,
329 CassUserType* cass_user_type) {
330 return cass_user_type_set_bool(cass_user_type, position,
331 *boost::any_cast<cass_bool_t*>(udt_member));
335 CqlUdtSetInt8(
const boost::any& udt_member,
336 const size_t& position,
337 CassUserType* cass_user_type) {
338 return cass_user_type_set_int8(cass_user_type, position,
339 *boost::any_cast<cass_int8_t*>(udt_member));
343 CqlUdtSetInt16(
const boost::any& udt_member,
344 const size_t& position,
345 CassUserType* cass_user_type) {
346 return cass_user_type_set_int16(
347 cass_user_type, position, *boost::any_cast<cass_int16_t*>(udt_member));
351 CqlUdtSetInt32(
const boost::any& udt_member,
352 const size_t& position,
353 CassUserType* cass_user_type) {
354 return cass_user_type_set_int32(
355 cass_user_type, position, *boost::any_cast<cass_int32_t*>(udt_member));
359 CqlUdtSetInt64(
const boost::any& udt_member,
360 const size_t& position,
361 CassUserType* cass_user_type) {
362 return cass_user_type_set_int64(
363 cass_user_type, position, *boost::any_cast<cass_int64_t*>(udt_member));
367 CqlUdtSetString(
const boost::any& udt_member,
368 const size_t& position,
369 CassUserType* cass_user_type) {
370 return cass_user_type_set_string(
371 cass_user_type, position,
372 boost::any_cast<std::string*>(udt_member)->c_str());
376 CqlUdtSetBytes(
const boost::any& udt_member,
377 const size_t& position,
378 CassUserType* cass_user_type) {
380 return cass_user_type_set_bytes(cass_user_type, position,
381 blob_value->data(), blob_value->size());
385 CqlUdtSetUuid(
const boost::any& udt_member,
386 const size_t& position,
387 CassUserType* cass_user_type) {
388 return cass_user_type_set_uuid(cass_user_type, position,
389 *boost::any_cast<CassUuid*>(udt_member));
393 CqlUdtSetUdt(
const boost::any& udt_member,
394 const size_t& position,
395 CassUserType* cass_user_type) {
396 return cass_user_type_set_user_type(
397 cass_user_type, position,
398 boost::any_cast<Udt*>(udt_member)->cass_user_type_);
402 CqlUdtSetCollection(
const boost::any& udt_member,
403 const size_t& position,
404 CassUserType* cass_user_type) {
405 return cass_user_type_set_collection(
406 cass_user_type, position, boost::any_cast<CassCollection*>(udt_member));
414 CqlCollectionAppendNone(
const boost::any& ,
420 CqlCollectionAppendBool(
const boost::any& value, CassCollection* collection) {
421 return cass_collection_append_bool(collection,
422 *boost::any_cast<cass_bool_t*>(value));
426 CqlCollectionAppendInt8(
const boost::any& value, CassCollection* collection) {
427 return cass_collection_append_int8(collection,
428 *boost::any_cast<cass_int8_t*>(value));
432 CqlCollectionAppendInt16(
const boost::any& value, CassCollection* collection) {
433 return cass_collection_append_int16(collection,
434 *boost::any_cast<cass_int16_t*>(value));
438 CqlCollectionAppendInt32(
const boost::any& value, CassCollection* collection) {
439 return cass_collection_append_int32(collection,
440 *boost::any_cast<cass_int32_t*>(value));
444 CqlCollectionAppendInt64(
const boost::any& value, CassCollection* collection) {
445 return cass_collection_append_int64(collection,
446 *boost::any_cast<cass_int64_t*>(value));
450 CqlCollectionAppendString(
const boost::any& value, CassCollection* collection) {
451 return cass_collection_append_string(
452 collection, boost::any_cast<std::string*>(value)->c_str());
456 CqlCollectionAppendBytes(
const boost::any& value, CassCollection* collection) {
458 return cass_collection_append_bytes(collection, blob_value->data(),
463 CqlCollectionAppendUuid(
const boost::any& value, CassCollection* collection) {
464 return cass_collection_append_uuid(collection,
465 *boost::any_cast<CassUuid*>(value));
469 CqlCollectionAppendUdt(
const boost::any& value, CassCollection* collection) {
470 Udt* udt = boost::any_cast<Udt*>(value);
472 for (boost::any& element : *udt) {
474 element, i, udt->cass_user_type_));
477 return cass_collection_append_user_type(collection, udt->cass_user_type_);
481 CqlCollectionAppendCollection(
const boost::any& value,
482 CassCollection* collection) {
483 return cass_collection_append_collection(
484 collection, boost::any_cast<CassCollection*>(value));
491 CqlGetNone(
const boost::any& ,
const CassValue* ) {
496 CqlGetBool(
const boost::any& data,
const CassValue* value) {
497 return cass_value_get_bool(value, boost::any_cast<cass_bool_t*>(data));
501 CqlGetInt8(
const boost::any& data,
const CassValue* value) {
502 return cass_value_get_int8(value, boost::any_cast<cass_int8_t*>(data));
506 CqlGetInt16(
const boost::any& data,
const CassValue* value) {
507 return cass_value_get_int16(value, boost::any_cast<cass_int16_t*>(data));
511 CqlGetInt32(
const boost::any& data,
const CassValue* value) {
512 return cass_value_get_int32(value, boost::any_cast<cass_int32_t*>(data));
516 CqlGetInt64(
const boost::any& data,
const CassValue* value) {
517 return cass_value_get_int64(value, boost::any_cast<cass_int64_t*>(data));
521 CqlGetString(
const boost::any& data,
const CassValue* value) {
522 char const* data_value;
524 CassError cass_error = cass_value_get_string(
525 value, static_cast<char const**>(&data_value), &size_value);
526 boost::any_cast<std::string*>(data)->assign(data_value,
527 data_value + size_value);
532 CqlGetBytes(
const boost::any& data,
const CassValue* value) {
533 const cass_byte_t* data_value;
535 CassError cass_error = cass_value_get_bytes(
536 value, static_cast<const cass_byte_t**>(&data_value), &size_value);
537 boost::any_cast<
CassBlob*>(data)->assign(data_value,
538 data_value + size_value);
543 CqlGetUuid(
const boost::any& data,
const CassValue* value) {
544 return cass_value_get_uuid(value, boost::any_cast<CassUuid*>(data));
548 CqlGetUdt(
const boost::any& data,
const CassValue* value) {
549 Udt* udt = boost::any_cast<Udt*>(data);
551 CassIterator* fields = cass_iterator_fields_from_user_type(value);
553 isc_throw(DbOperationError,
"CqlGetUdt(): column is not a UDT");
555 Udt::const_iterator it = udt->begin();
556 while (cass_iterator_next(fields)) {
557 const CassValue* field_value =
558 cass_iterator_get_user_type_field_value(fields);
559 if (cass_value_is_null(field_value)) {
561 "CqlGetUdt(): null value returned in UDT");
563 const CassValueType& type = cass_value_type(field_value);
571 cass_iterator_free(fields);
576 CqlGetCollection(
const boost::any& data,
const CassValue* value) {
579 isc_throw(DbOperationError,
"CqlGetCollection(): column is not a collection");
582 BOOST_ASSERT(collection->size() == 1);
586 boost::any underlying_object = *collection->begin();
590 CassIterator* items = cass_iterator_from_collection(value);
593 "CqlGetCollection(): column is not a collection");
595 while (cass_iterator_next(items)) {
596 const CassValue* item_value = cass_iterator_get_value(items);
597 if (cass_value_is_null(item_value)) {
599 "CqlGetCollection(): null value returned in collection");
601 const CassValueType& type = cass_value_type(item_value);
603 collection->push_back(underlying_object);
605 *collection->rbegin(), item_value));
610 cass_iterator_free(items);
618 {CqlBindNone, CqlUdtSetNone, CqlCollectionAppendNone, CqlGetNone}},
620 {CqlBindBool, CqlUdtSetBool, CqlCollectionAppendBool, CqlGetBool}},
622 {CqlBindInt8, CqlUdtSetInt8, CqlCollectionAppendInt8, CqlGetInt8}},
624 {CqlBindInt16, CqlUdtSetInt16, CqlCollectionAppendInt16, CqlGetInt16}},
626 {CqlBindInt32, CqlUdtSetInt32, CqlCollectionAppendInt32, CqlGetInt32}},
628 {CqlBindInt64, CqlUdtSetInt64, CqlCollectionAppendInt64, CqlGetInt64}},
630 {CqlBindString, CqlUdtSetString, CqlCollectionAppendString,
633 {CqlBindBytes, CqlUdtSetBytes, CqlCollectionAppendBytes, CqlGetBytes}},
635 {CqlBindUuid, CqlUdtSetUuid, CqlCollectionAppendUuid, CqlGetUuid}},
637 {CqlBindUdt, CqlUdtSetUdt, CqlCollectionAppendUdt, CqlGetUdt}},
639 {CqlBindCollection, CqlUdtSetCollection, CqlCollectionAppendCollection,
644 const std::type_index type =
object.type();
645 AnyTypeMap::const_iterator exchange_type_it = ANY_TYPE_MAP.find(type);
646 if (exchange_type_it == ANY_TYPE_MAP.end()) {
648 "exchangeType(): boost::any type "
649 << type.name() <<
" does not map to any exchange type");
652 if (exchange_type >= CQL_FUNCTIONS.size()) {
654 "exchangeType(): index " << exchange_type <<
" out of bounds "
656 << (CQL_FUNCTIONS.size() - 1));
658 return exchange_type;
663 CassTypeMap::const_iterator exchange_type_it = CASS_TYPE_MAP.find(type);
664 if (exchange_type_it == CASS_TYPE_MAP.end()) {
666 "exchangeType(): Cassandra value type "
667 << type <<
" does not map to any exchange type");
670 if (exchange_type >= CQL_FUNCTIONS.size()) {
672 "exchangeType(): index " << exchange_type <<
" out of bounds "
674 << CQL_FUNCTIONS.size() - 1);
676 return exchange_type;
682 for (
const boost::any& element : data) {
683 CassError cass_error;
685 cass_error = CQL_FUNCTIONS[
exchangeType(element)].cqlBindFunction_(
686 element, i, statement);
687 }
catch (
const boost::bad_any_cast& exception) {
689 "CqlCommon::bindData(): "
690 << exception.
what() <<
" when binding parameter " << i
691 <<
" which is of type " << element.type().name()
692 <<
" with function CQL_FUNCTIONS["
695 if (cass_error != CASS_OK) {
697 "CqlCommon::bindData(): unable to bind parameter "
698 << i <<
" which is of type " << element.type().name()
699 <<
" with function CQL_FUNCTIONS["
701 <<
"].cqlBindFunction_(), Cassandra error code: "
702 << cass_error_desc(cass_error));
711 for (boost::any& element : data) {
712 const CassValue* value = cass_row_get_column(row, i);
713 CassError cass_error;
715 cass_error = CQL_FUNCTIONS[
exchangeType(element)].cqlGetFunction_(
717 }
catch (
const boost::bad_any_cast& exception) {
719 "CqlCommon::getData(): "
720 << exception.
what() <<
" when retrieving parameter "
721 << i <<
" which is of type " << element.type().name()
722 <<
" with function CQL_FUNCTIONS["
725 if (cass_error != CASS_OK) {
728 "CqlCommon::getData(): Cassandra error when retrieving column "
729 << i <<
", Cassandra error code: "
730 << cass_error_desc(cass_error));
744 const uint32_t& valid_lifetime,
745 cass_int64_t& expire) {
747 cass_int64_t expire_time =
static_cast<cass_int64_t
>(cltt) +
748 static_cast<cass_int64_t>(valid_lifetime);
750 expire = expire_time;
755 const cass_int64_t& valid_lifetime,
758 cltt =
static_cast<time_t
>(expire - valid_lifetime);
765 CassStatement* statement = NULL;
766 CassFuture* future = NULL;
770 StatementMap::const_iterator it = connection.
statements_.find(statement_tag);
773 "CqlExchange::executeSelect(): Statement "
774 << statement_tag <<
"has not been prepared.");
779 if (tagged_statement.
is_raw_) {
781 std::string* query = boost::any_cast<std::string*>(local_data.back());
782 local_data.pop_back();
783 statement = cass_statement_new(query->c_str(), local_data.size());
788 "CqlExchange::executeSelect(): unable to bind statement "
789 << tagged_statement.
name_);
795 rc = cass_statement_set_consistency(statement, connection.
consistency_);
797 cass_statement_free(statement);
799 "CqlExchange::executeSelect(): unable to set statement "
800 "consistency for statement "
801 << tagged_statement.
name_
802 <<
", Cassandra error code: " << cass_error_desc(rc));
807 cass_statement_free(statement);
809 "CqlExchange::executeSelect(): unable to set statement "
810 "serial consistency for statement "
811 << tagged_statement.
name_
812 <<
", Cassandra error code: " << cass_error_desc(rc));
820 future = cass_session_execute(connection.
session_, statement);
822 cass_statement_free(statement);
824 "CqlExchange::executeSelect(): no CassFuture for statement "
825 << tagged_statement.
name_);
829 cass_future_wait(future);
831 "CqlExchange::executeSelect(): cass_session_execute() != CASS_OK",
832 future, statement_tag);
833 rc = cass_future_error_code(future);
835 cass_future_free(future);
836 cass_statement_free(statement);
841 const CassResult* result_collection = cass_future_get_result(future);
842 if (single && cass_result_row_count(result_collection) > 1) {
843 cass_result_free(result_collection);
844 cass_future_free(future);
845 cass_statement_free(statement);
848 "CqlExchange::executeSelect(): multiple records were found in "
849 "the database where only one was expected for statement "
850 << tagged_statement.
name_);
856 CassIterator* rows = cass_iterator_from_result(result_collection);
857 while (cass_iterator_next(rows)) {
858 const CassRow* row = cass_iterator_get_row(rows);
865 cass_iterator_free(rows);
866 cass_result_free(result_collection);
867 cass_future_free(future);
868 cass_statement_free(statement);
877 CassStatement* statement = NULL;
878 CassFuture* future = NULL;
881 StatementMap::const_iterator it =
885 << statement_tag <<
"has not been prepared.");
892 "CqlExchange::executeMutation(): unable to bind statement "
893 << tagged_statement.
name_);
898 rc = cass_statement_set_consistency(statement, connection.
consistency_);
900 cass_statement_free(statement);
902 " statement consistency for statement " << tagged_statement.
name_
903 <<
", Cassandra error code: " << cass_error_desc(rc));
908 cass_statement_free(statement);
910 "CqlExchange::executeMutation(): unable to set statement "
911 "serial consistency for statement "
912 << tagged_statement.
name_
913 <<
", Cassandra error code: " << cass_error_desc(rc));
920 future = cass_session_execute(connection.
session_, statement);
922 cass_statement_free(statement);
924 "CqlExchange::executeMutation(): unable to execute statement "
925 << tagged_statement.
name_);
927 cass_future_wait(future);
929 "cass_session_execute() != CASS_OK", future, statement_tag);
930 rc = cass_future_error_code(future);
932 cass_future_free(future);
933 cass_statement_free(statement);
941 cass_future_free(future);
942 cass_statement_free(statement);
947 "CqlExchange::executeMutation(): [applied] is false for statement "
948 << tagged_statement.
name_);
955 size_t* column_count) {
956 const CassResult* result_collection = cass_future_get_result(future);
957 if (!result_collection) {
959 " results collection");
962 *row_count = cass_result_row_count(result_collection);
965 *column_count = cass_result_column_count(result_collection);
967 CassIterator* rows = cass_iterator_from_result(result_collection);
969 cass_bool_t applied = cass_true;
970 while (cass_iterator_next(rows)) {
971 const CassRow* row = cass_iterator_get_row(rows);
976 cass_iterator_free(rows);
977 cass_result_free(result_collection);
978 return applied == cass_true;
984 {GET_VERSION, {GET_VERSION,
"SELECT version, minor FROM schema_version "}}
1013 if (!version_collection.empty()) {
1014 return *boost::any_cast<
VersionPair*>(*version_collection.begin());
Database statement not applied.
#define KEA_CASS_CHECK(cass_error)
Macro to return directly from caller function.
StatementMap statements_
Pointer to external array of tagged statements containing statement name, array of names of bind para...
void executeMutation(const CqlConnection &connection, const AnyArray &assigned_values, StatementTag statement_tag)
Executes INSERT, UPDATE or DELETE statements.
virtual void createBindForSelect(AnyArray &data, StatementTag statement_tag=NULL) override
Create BIND array to receive C++ data.
ExchangeDataType exchangeType(const boost::any &object)
Determine exchange type based on boost::any type.
const CassDataType * cass_data_type_
Internal Cassandra driver object representing a Cassandra data type.
Structure used to bind C++ input values to dynamic CQL parameters.
StatementTag name_
Short description of the query.
const CassPrepared * prepared_statement_
Internal Cassandra object representing the prepared statement.
std::unordered_map< std::type_index, ExchangeDataType > AnyTypeMap
Map types used to determine exchange type.
bool force_consistency_
CQL consistency enabled.
static constexpr StatementTag GET_VERSION
Statement tags definitions.
virtual ~CqlVersionExchange()
Destructor.
size_t operator()(const ExchangeDataType &key) const
static void getData(const CassRow *row, AnyArray &data)
Retrieves data returned by Cassandra.
const CqlConnection & connection_
Connection to the Cassandra database.
std::unordered_map< ExchangeDataType, CqlFunction, ExchangeDataTypeHash > CqlFunctionMap
Defines a type for storing aux. Cassandra functions.
CqlFunctionMap CQL_FUNCTIONS
Functions used to interface with the Cassandra C++ driver.
char const *const StatementTag
Statement index representing the statement name.
const CassKeyspaceMeta * keyspace_meta_
Keyspace meta information, used for UDTs.
bool statementApplied(CassFuture *future, size_t *row_count=NULL, size_t *column_count=NULL)
Check if CQL statement has been applied.
Multiple lease records found where one expected.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
CassUserType * cass_user_type_
Internal Cassandra driver object representing a user defined type.
Defines a single statement or query.
void add(const boost::any &value)
Add a value at the end of the vector.
static void convertToDatabaseTime(const time_t &cltt, const uint32_t &valid_lifetime, cass_int64_t &expire)
CassConsistency consistency_
CQL consistency.
virtual boost::any retrieve() override
Copy received data into the pair.
std::vector< cass_byte_t > CassBlob
Host identifier converted to Cassandra data type.
CassSession * session_
CQL session handle.
std::pair< uint32_t, uint32_t > VersionPair
Pair containing major and minor versions.
ExchangeDataType
Used to map server data types with internal backend storage data types.
Udt(const CqlConnection &connection, const std::string &name)
Parameterized constructor.
const std::string name_
Name of the UDT in the schema: CREATE TYPE ___ { ... }.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Collection (used in Cassandra)
Defines the logger used by the top-level component of kea-dhcp-ddns.
static void convertFromDatabaseTime(const cass_int64_t &expire, const cass_int64_t &valid_lifetime, time_t &cltt)
Converts time from Cassandra format.
std::unordered_map< uint8_t, ExchangeDataType > CassTypeMap
static void bindData(const AnyArray &data, CassStatement *statement)
Assigns values to every column of an INSERT or an UPDATE statement.
std::unordered_map< StatementTag, CqlTaggedStatement, StatementTagHash, StatementTagEqual > StatementMap
A container for all statements.
CassConsistency serial_consistency_
CQL serial consistency.
AnyArray executeSelect(const CqlConnection &connection, const AnyArray &where_values, StatementTag statement_tag, const bool &single=false)
Executes SELECT statements.
void remove(const size_t &index)
Remove the void pointer to the data value from a specified position inside the vector.
a helper structure with a function call operator that returns key value in a format expected by std::...
virtual boost::any retrieve()=0
Copy received data into the derived class' object.
virtual ~CqlExchange()
Destructor.
std::size_t hash_value(const CassValueType &key)
hash function for CassTypeMap
static StatementMap tagged_statements_
Cassandra statements.
Common CQL connector pool.
static const std::string checkFutureError(const std::string &what, CassFuture *future, StatementTag statement_tag=NULL)
Check for errors.
User-Defined Type (used in Cassandra)
virtual VersionPair retrieveVersion(const CqlConnection &connection)
Standalone method used to retrieve schema version.
Exception thrown on failure to execute a database function.
bool is_raw_
Should the statement be executed raw or with binds?
CqlExchange()
Constructor.
CqlVersionExchange()
Constructor.
AnyArray AnyCollection
Defines an array of arbitrary objects (used by Cassandra backend)
virtual void createBindForSelect(AnyArray &data, StatementTag statement_tag=NULL)=0
Create BIND array to receive C++ data.