@@ -36,6 +36,20 @@ using namespace datastax;
3636using namespace datastax ::internal;
3737using namespace datastax ::internal::core;
3838
39+ static String to_hex (const String& byte_id) {
40+ static const char half_byte_to_hex[] = { ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' ,
41+ ' 8' , ' 9' , ' a' , ' b' , ' c' , ' d' , ' e' , ' f' };
42+ OStringStream ss;
43+
44+ const char * data = byte_id.data ();
45+ for (size_t i = 0 ; i < byte_id.length (); ++i) {
46+ uint8_t byte = static_cast <uint8_t >(data[i]);
47+ ss << half_byte_to_hex[(byte >> 4 ) & 0x0F ];
48+ ss << half_byte_to_hex[byte & 0x0F ];
49+ }
50+ return ss.str ();
51+ }
52+
3953class SingleHostQueryPlan : public QueryPlan {
4054public:
4155 SingleHostQueryPlan (const Address& address)
@@ -53,7 +67,7 @@ class SingleHostQueryPlan : public QueryPlan {
5367
5468class PrepareCallback : public SimpleRequestCallback {
5569public:
56- PrepareCallback (const String& query, RequestExecution* request_execution);
70+ PrepareCallback (const String& query, const String& id, RequestExecution* request_execution);
5771
5872private:
5973 class PrepareRequest : public core ::PrepareRequest {
@@ -72,21 +86,29 @@ class PrepareCallback : public SimpleRequestCallback {
7286
7387private:
7488 RequestExecution::Ptr request_execution_;
89+ String id_;
7590};
7691
77- PrepareCallback::PrepareCallback (const String& query, RequestExecution* request_execution)
92+ PrepareCallback::PrepareCallback (const String& query, const String& id,
93+ RequestExecution* request_execution)
7894 : SimpleRequestCallback(
7995 Request::ConstPtr (new PrepareRequest(query, request_execution->request ()->keyspace(),
8096 request_execution->request_timeout_ms())))
81- , request_execution_(request_execution) {}
97+ , request_execution_(request_execution)
98+ , id_(id) {}
8299
83100void PrepareCallback::on_internal_set (ResponseMessage* response) {
84101 switch (response->opcode ()) {
85102 case CQL_OPCODE_RESULT: {
86103 ResultResponse* result = static_cast <ResultResponse*>(response->response_body ().get ());
87104 if (result->kind () == CASS_RESULT_KIND_PREPARED) {
88- request_execution_->notify_result_metadata_changed (request (), result);
89- request_execution_->on_retry_current_host ();
105+ String result_id = result->prepared_id ().to_string ();
106+ if (id_ != result_id) {
107+ request_execution_->notify_prepared_id_mismatch (id_, result_id);
108+ } else {
109+ request_execution_->notify_result_metadata_changed (request (), result);
110+ request_execution_->on_retry_current_host ();
111+ }
90112 } else {
91113 request_execution_->on_retry_next_host ();
92114 }
@@ -461,6 +483,17 @@ void RequestExecution::notify_result_metadata_changed(const Request* request,
461483 }
462484}
463485
486+ void RequestExecution::notify_prepared_id_mismatch (const String& expected_id,
487+ const String& received_id) {
488+ OStringStream ss;
489+ ss << " ID mismatch while trying to prepare query (expected ID " << to_hex (expected_id)
490+ << " , received ID " << to_hex (received_id)
491+ << " ). This prepared statement won't work anymore. This usually happens when you run a "
492+ " 'USE...' query after the statement was prepared." ;
493+ String message = ss.str ();
494+ request_handler_->set_error (CASS_ERROR_LIB_UNEXPECTED_RESPONSE, message);
495+ }
496+
464497void RequestExecution::on_result_response (Connection* connection, ResponseMessage* response) {
465498 ResultResponse* result = static_cast <ResultResponse*>(response->response_body ().get ());
466499
@@ -602,14 +635,17 @@ void RequestExecution::on_error_response(Connection* connection, ResponseMessage
602635}
603636
604637void RequestExecution::on_error_unprepared (Connection* connection, ErrorResponse* error) {
605- String query;
638+ LOG_DEBUG (" Unprepared error response returned for request: %s" ,
639+ error->message ().to_string ().c_str ());
606640
641+ String query;
642+ String id = error->prepared_id ().to_string ();
607643 if (request ()->opcode () == CQL_OPCODE_EXECUTE) {
608644 const ExecuteRequest* execute = static_cast <const ExecuteRequest*>(request ());
609645 query = execute->prepared ()->query ();
610646 } else if (request ()->opcode () == CQL_OPCODE_BATCH) {
611647 const BatchRequest* batch = static_cast <const BatchRequest*>(request ());
612- if (!batch->find_prepared_query (error-> prepared_id (). to_string () , &query)) {
648+ if (!batch->find_prepared_query (id , &query)) {
613649 set_error (CASS_ERROR_LIB_UNEXPECTED_RESPONSE,
614650 " Unable to find prepared statement in batch statement" );
615651 return ;
@@ -621,7 +657,7 @@ void RequestExecution::on_error_unprepared(Connection* connection, ErrorResponse
621657 return ;
622658 }
623659
624- RequestCallback::Ptr callback (new PrepareCallback (query, this ));
660+ RequestCallback::Ptr callback (new PrepareCallback (query, id, this ));
625661 if (connection->write_and_flush (callback) < 0 ) {
626662 // Try to prepare on the same host but on a different connection
627663 retry_current_host ();
0 commit comments