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;
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) {
243 CassBlob* blob_value = boost::any_cast<CassBlob*>(value);
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) {
274 element, i, udt->cass_user_type_));
275 }
catch (
const boost::bad_any_cast& exception) {
277 "CqlCommon::udtSetData(): "
278 << exception.what() <<
" when binding parameter "
279 <<
" of type " << element.type().name()
280 <<
"in UDT with function CQL_FUNCTIONS["
286 return cass_statement_bind_user_type(statement, index,
287 udt->cass_user_type_);
291 CqlBindCollection(
const boost::any& value,
293 CassStatement* statement) {
294 AnyCollection* elements = boost::any_cast<AnyCollection*>(value);
296 CassCollection* collection =
297 cass_collection_new(CASS_COLLECTION_TYPE_SET, elements->size());
301 for (boost::any& element : *elements) {
304 element, collection));
307 const CassError cass_error =
308 cass_statement_bind_collection(statement, index, collection);
309 cass_collection_free(collection);
319 CqlUdtSetNone(
const boost::any& ,
320 const size_t& position,
321 CassUserType* cass_user_type) {
322 return cass_user_type_set_null(cass_user_type, position);
326 CqlUdtSetBool(
const boost::any& udt_member,
327 const size_t& position,
328 CassUserType* cass_user_type) {
329 return cass_user_type_set_bool(cass_user_type, position,
330 *boost::any_cast<cass_bool_t*>(udt_member));
334 CqlUdtSetInt8(
const boost::any& udt_member,
335 const size_t& position,
336 CassUserType* cass_user_type) {
337 return cass_user_type_set_int8(cass_user_type, position,
338 *boost::any_cast<cass_int8_t*>(udt_member));
342 CqlUdtSetInt16(
const boost::any& udt_member,
343 const size_t& position,
344 CassUserType* cass_user_type) {
345 return cass_user_type_set_int16(
346 cass_user_type, position, *boost::any_cast<cass_int16_t*>(udt_member));
350 CqlUdtSetInt32(
const boost::any& udt_member,
351 const size_t& position,
352 CassUserType* cass_user_type) {
353 return cass_user_type_set_int32(
354 cass_user_type, position, *boost::any_cast<cass_int32_t*>(udt_member));
358 CqlUdtSetInt64(
const boost::any& udt_member,
359 const size_t& position,
360 CassUserType* cass_user_type) {
361 return cass_user_type_set_int64(
362 cass_user_type, position, *boost::any_cast<cass_int64_t*>(udt_member));
366 CqlUdtSetString(
const boost::any& udt_member,
367 const size_t& position,
368 CassUserType* cass_user_type) {
369 return cass_user_type_set_string(
370 cass_user_type, position,
371 boost::any_cast<std::string*>(udt_member)->c_str());
375 CqlUdtSetBytes(
const boost::any& udt_member,
376 const size_t& position,
377 CassUserType* cass_user_type) {
378 CassBlob* blob_value = boost::any_cast<CassBlob*>(udt_member);
379 return cass_user_type_set_bytes(cass_user_type, position,
380 blob_value->data(), blob_value->size());
384 CqlUdtSetUuid(
const boost::any& udt_member,
385 const size_t& position,
386 CassUserType* cass_user_type) {
387 return cass_user_type_set_uuid(cass_user_type, position,
388 *boost::any_cast<CassUuid*>(udt_member));
392 CqlUdtSetUdt(
const boost::any& udt_member,
393 const size_t& position,
394 CassUserType* cass_user_type) {
395 return cass_user_type_set_user_type(
396 cass_user_type, position,
397 boost::any_cast<Udt*>(udt_member)->cass_user_type_);
401 CqlUdtSetCollection(
const boost::any& udt_member,
402 const size_t& position,
403 CassUserType* cass_user_type) {
404 return cass_user_type_set_collection(
405 cass_user_type, position, boost::any_cast<CassCollection*>(udt_member));
413 CqlCollectionAppendNone(
const boost::any& ,
419 CqlCollectionAppendBool(
const boost::any& value, CassCollection* collection) {
420 return cass_collection_append_bool(collection,
421 *boost::any_cast<cass_bool_t*>(value));
425 CqlCollectionAppendInt8(
const boost::any& value, CassCollection* collection) {
426 return cass_collection_append_int8(collection,
427 *boost::any_cast<cass_int8_t*>(value));
431 CqlCollectionAppendInt16(
const boost::any& value, CassCollection* collection) {
432 return cass_collection_append_int16(collection,
433 *boost::any_cast<cass_int16_t*>(value));
437 CqlCollectionAppendInt32(
const boost::any& value, CassCollection* collection) {
438 return cass_collection_append_int32(collection,
439 *boost::any_cast<cass_int32_t*>(value));
443 CqlCollectionAppendInt64(
const boost::any& value, CassCollection* collection) {
444 return cass_collection_append_int64(collection,
445 *boost::any_cast<cass_int64_t*>(value));
449 CqlCollectionAppendString(
const boost::any& value, CassCollection* collection) {
450 return cass_collection_append_string(
451 collection, boost::any_cast<std::string*>(value)->c_str());
455 CqlCollectionAppendBytes(
const boost::any& value, CassCollection* collection) {
456 CassBlob* blob_value = boost::any_cast<CassBlob*>(value);
457 return cass_collection_append_bytes(collection, blob_value->data(),
462 CqlCollectionAppendUuid(
const boost::any& value, CassCollection* collection) {
463 return cass_collection_append_uuid(collection,
464 *boost::any_cast<CassUuid*>(value));
468 CqlCollectionAppendUdt(
const boost::any& value, CassCollection* collection) {
469 Udt* udt = boost::any_cast<Udt*>(value);
471 for (boost::any& element : *udt) {
473 element, i, udt->cass_user_type_));
476 return cass_collection_append_user_type(collection, udt->cass_user_type_);
480 CqlCollectionAppendCollection(
const boost::any& value,
481 CassCollection* collection) {
482 return cass_collection_append_collection(
483 collection, boost::any_cast<CassCollection*>(value));
490 CqlGetNone(
const boost::any& ,
const CassValue* ) {
495 CqlGetBool(
const boost::any& data,
const CassValue* value) {
496 return cass_value_get_bool(value, boost::any_cast<cass_bool_t*>(data));
500 CqlGetInt8(
const boost::any& data,
const CassValue* value) {
501 return cass_value_get_int8(value, boost::any_cast<cass_int8_t*>(data));
505 CqlGetInt16(
const boost::any& data,
const CassValue* value) {
506 return cass_value_get_int16(value, boost::any_cast<cass_int16_t*>(data));
510 CqlGetInt32(
const boost::any& data,
const CassValue* value) {
511 return cass_value_get_int32(value, boost::any_cast<cass_int32_t*>(data));
515 CqlGetInt64(
const boost::any& data,
const CassValue* value) {
516 return cass_value_get_int64(value, boost::any_cast<cass_int64_t*>(data));
520 CqlGetString(
const boost::any& data,
const CassValue* value) {
521 char const* data_value;
523 CassError cass_error = cass_value_get_string(
524 value,
static_cast<char const**
>(&data_value), &size_value);
525 boost::any_cast<std::string*>(data)->assign(data_value,
526 data_value + size_value);
531 CqlGetBytes(
const boost::any& data,
const CassValue* value) {
532 const cass_byte_t* data_value;
534 CassError cass_error = cass_value_get_bytes(
535 value,
static_cast<const cass_byte_t**
>(&data_value), &size_value);
536 boost::any_cast<CassBlob*>(data)->assign(data_value,
537 data_value + size_value);
542 CqlGetUuid(
const boost::any& data,
const CassValue* value) {
543 return cass_value_get_uuid(value, boost::any_cast<CassUuid*>(data));
547 CqlGetUdt(
const boost::any& data,
const CassValue* value) {
548 Udt* udt = boost::any_cast<Udt*>(data);
550 CassIterator* fields = cass_iterator_fields_from_user_type(value);
552 isc_throw(DbOperationError,
"CqlGetUdt(): column is not a UDT");
554 Udt::const_iterator it = udt->begin();
555 while (cass_iterator_next(fields)) {
556 const CassValue* field_value =
557 cass_iterator_get_user_type_field_value(fields);
558 if (cass_value_is_null(field_value)) {
560 "CqlGetUdt(): null value returned in UDT");
562 const CassValueType& type = cass_value_type(field_value);
570 cass_iterator_free(fields);
575 CqlGetCollection(
const boost::any& data,
const CassValue* value) {
576 AnyCollection* collection = boost::any_cast<AnyCollection*>(data);
578 isc_throw(DbOperationError,
"CqlGetCollection(): column is not a collection");
581 BOOST_ASSERT(collection->size() == 1);
585 boost::any underlying_object = *collection->begin();
589 CassIterator* items = cass_iterator_from_collection(value);
592 "CqlGetCollection(): column is not a collection");
594 while (cass_iterator_next(items)) {
595 const CassValue* item_value = cass_iterator_get_value(items);
596 if (cass_value_is_null(item_value)) {
598 "CqlGetCollection(): null value returned in collection");
600 const CassValueType& type = cass_value_type(item_value);
602 collection->push_back(underlying_object);
604 *collection->rbegin(), item_value));
609 cass_iterator_free(items);
617 {CqlBindNone, CqlUdtSetNone, CqlCollectionAppendNone, CqlGetNone}},
619 {CqlBindBool, CqlUdtSetBool, CqlCollectionAppendBool, CqlGetBool}},
621 {CqlBindInt8, CqlUdtSetInt8, CqlCollectionAppendInt8, CqlGetInt8}},
623 {CqlBindInt16, CqlUdtSetInt16, CqlCollectionAppendInt16, CqlGetInt16}},
625 {CqlBindInt32, CqlUdtSetInt32, CqlCollectionAppendInt32, CqlGetInt32}},
627 {CqlBindInt64, CqlUdtSetInt64, CqlCollectionAppendInt64, CqlGetInt64}},
629 {CqlBindString, CqlUdtSetString, CqlCollectionAppendString,
632 {CqlBindBytes, CqlUdtSetBytes, CqlCollectionAppendBytes, CqlGetBytes}},
634 {CqlBindUuid, CqlUdtSetUuid, CqlCollectionAppendUuid, CqlGetUuid}},
636 {CqlBindUdt, CqlUdtSetUdt, CqlCollectionAppendUdt, CqlGetUdt}},
638 {CqlBindCollection, CqlUdtSetCollection, CqlCollectionAppendCollection,
643 const std::type_index type =
object.type();
644 AnyTypeMap::const_iterator exchange_type_it = ANY_TYPE_MAP.find(type);
645 if (exchange_type_it == ANY_TYPE_MAP.end()) {
647 "exchangeType(): boost::any type "
648 << type.name() <<
" does not map to any exchange type");
653 "exchangeType(): index " << exchange_type <<
" out of bounds "
657 return exchange_type;
662 CassTypeMap::const_iterator exchange_type_it = CASS_TYPE_MAP.find(type);
663 if (exchange_type_it == CASS_TYPE_MAP.end()) {
665 "exchangeType(): Cassandra value type "
666 << type <<
" does not map to any exchange type");
671 "exchangeType(): index " << exchange_type <<
" out of bounds "
675 return exchange_type;
681 for (
const boost::any& element : data) {
682 CassError cass_error;
685 element, i, statement);
686 }
catch (
const boost::bad_any_cast& exception) {
688 "CqlCommon::bindData(): "
689 << exception.
what() <<
" when binding parameter " << i
690 <<
" which is of type " << element.type().name()
691 <<
" with function CQL_FUNCTIONS["
694 if (cass_error != CASS_OK) {
696 "CqlCommon::bindData(): unable to bind parameter "
697 << i <<
" which is of type " << element.type().name()
698 <<
" with function CQL_FUNCTIONS["
700 <<
"].cqlBindFunction_(), Cassandra error code: "
701 << cass_error_desc(cass_error));
710 for (boost::any& element : data) {
711 const CassValue* value = cass_row_get_column(row, i);
712 CassError cass_error;
716 }
catch (
const boost::bad_any_cast& exception) {
718 "CqlCommon::getData(): "
719 << exception.
what() <<
" when retrieving parameter "
720 << i <<
" which is of type " << element.type().name()
721 <<
" with function CQL_FUNCTIONS["
724 if (cass_error != CASS_OK) {
727 "CqlCommon::getData(): Cassandra error when retrieving column "
728 << i <<
", Cassandra error code: "
729 << cass_error_desc(cass_error));
743 const uint32_t& valid_lifetime,
744 cass_int64_t& expire) {
747 cass_int64_t expire_time =
static_cast<cass_int64_t
>(cltt) +
748 static_cast<cass_int64_t
>(valid_lifetime);
752 "CqlExchange(): convertToDatabaseTime(): time value "
753 << expire_time <<
" is too large");
756 expire = expire_time;
761 const cass_int64_t& valid_lifetime,
768 cltt =
static_cast<time_t
>(expire - valid_lifetime);
775 CassStatement* statement = NULL;
776 CassFuture* future = NULL;
780 StatementMap::const_iterator it = connection.
statements_.find(statement_tag);
783 "CqlExchange::executeSelect(): Statement "
784 << statement_tag <<
"has not been prepared.");
789 if (tagged_statement.
is_raw_) {
791 std::string* query = boost::any_cast<std::string*>(local_data.back());
792 local_data.pop_back();
793 statement = cass_statement_new(query->c_str(), local_data.size());
798 "CqlExchange::executeSelect(): unable to bind statement "
799 << tagged_statement.
name_);
805 rc = cass_statement_set_consistency(statement, connection.
consistency_);
807 cass_statement_free(statement);
809 "CqlExchange::executeSelect(): unable to set statement "
810 "consistency for statement "
811 << tagged_statement.
name_
812 <<
", Cassandra error code: " << cass_error_desc(rc));
819 future = cass_session_execute(connection.
session_, statement);
821 cass_statement_free(statement);
823 "CqlExchange::executeSelect(): no CassFuture for statement "
824 << tagged_statement.
name_);
828 cass_future_wait(future);
830 "CqlExchange::executeSelect(): cass_session_execute() != CASS_OK",
831 future, statement_tag);
832 rc = cass_future_error_code(future);
834 cass_future_free(future);
835 cass_statement_free(statement);
840 const CassResult* result_collection = cass_future_get_result(future);
841 if (single && cass_result_row_count(result_collection) > 1) {
842 cass_result_free(result_collection);
843 cass_future_free(future);
844 cass_statement_free(statement);
847 "CqlExchange::executeSelect(): multiple records were found in "
848 "the database where only one was expected for statement "
849 << tagged_statement.
name_);
855 CassIterator* rows = cass_iterator_from_result(result_collection);
856 while (cass_iterator_next(rows)) {
857 const CassRow* row = cass_iterator_get_row(rows);
864 cass_iterator_free(rows);
865 cass_result_free(result_collection);
866 cass_future_free(future);
867 cass_statement_free(statement);
876 CassStatement* statement = NULL;
877 CassFuture* future = NULL;
880 StatementMap::const_iterator it =
884 << statement_tag <<
"has not been prepared.");
891 "CqlExchange::executeMutation(): unable to bind statement "
892 << tagged_statement.
name_);
897 rc = cass_statement_set_consistency(statement, connection.
consistency_);
899 cass_statement_free(statement);
901 " statement consistency for statement " << tagged_statement.
name_
902 <<
", Cassandra error code: " << cass_error_desc(rc));
908 future = cass_session_execute(connection.
session_, statement);
910 cass_statement_free(statement);
912 "CqlExchange::executeMutation(): unable to execute statement "
913 << tagged_statement.
name_);
915 cass_future_wait(future);
916 const std::string error = connection.
checkFutureError(
"CqlExchange::executeMutation():"
917 "cass_session_execute() != CASS_OK", future, statement_tag);
918 rc = cass_future_error_code(future);
920 cass_future_free(future);
921 cass_statement_free(statement);
929 cass_future_free(future);
930 cass_statement_free(statement);
935 "CqlExchange::executeMutation(): [applied] is false for statement "
936 << tagged_statement.
name_);
943 size_t* column_count) {
944 const CassResult* result_collection = cass_future_get_result(future);
945 if (!result_collection) {
947 " results collection");
950 *row_count = cass_result_row_count(result_collection);
953 *column_count = cass_result_column_count(result_collection);
955 CassIterator* rows = cass_iterator_from_result(result_collection);
957 cass_bool_t applied = cass_true;
958 while (cass_iterator_next(rows)) {
959 const CassRow* row = cass_iterator_get_row(rows);
964 cass_iterator_free(rows);
965 cass_result_free(result_collection);
966 return applied == cass_true;
972 {GET_VERSION, {GET_VERSION,
"SELECT version, minor FROM schema_version "}}
1001 if (!version_collection.empty()) {
1002 return *boost::any_cast<VersionPair*>(*version_collection.begin());