1 /*
2   Copyright (c) DataStax, Inc.
3 
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7 
8   http://www.apache.org/licenses/LICENSE-2.0
9 
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15 */
16 
17 #include "error_response.hpp"
18 
19 #include "external.hpp"
20 #include "logger.hpp"
21 #include "serialization.hpp"
22 
23 #include <iomanip>
24 
25 using namespace datastax;
26 using namespace datastax::internal;
27 using namespace datastax::internal::core;
28 
29 extern "C" {
30 
cass_error_result_free(const CassErrorResult * error_result)31 void cass_error_result_free(const CassErrorResult* error_result) { error_result->dec_ref(); }
32 
cass_error_result_code(const CassErrorResult * error_result)33 CassError cass_error_result_code(const CassErrorResult* error_result) {
34   return static_cast<CassError>(CASS_ERROR(CASS_ERROR_SOURCE_SERVER, error_result->code()));
35 }
36 
cass_error_result_consistency(const CassErrorResult * error_result)37 CassConsistency cass_error_result_consistency(const CassErrorResult* error_result) {
38   return error_result->consistency();
39 }
40 
cass_error_result_responses_received(const CassErrorResult * error_result)41 cass_int32_t cass_error_result_responses_received(const CassErrorResult* error_result) {
42   return error_result->received();
43 }
44 
cass_error_result_responses_required(const CassErrorResult * error_result)45 cass_int32_t cass_error_result_responses_required(const CassErrorResult* error_result) {
46   return error_result->required();
47 }
48 
cass_error_result_num_failures(const CassErrorResult * error_result)49 cass_int32_t cass_error_result_num_failures(const CassErrorResult* error_result) {
50   return error_result->num_failures();
51 }
52 
cass_error_result_data_present(const CassErrorResult * error_result)53 cass_bool_t cass_error_result_data_present(const CassErrorResult* error_result) {
54   return static_cast<cass_bool_t>(error_result->data_present());
55 }
56 
cass_error_result_write_type(const CassErrorResult * error_result)57 CassWriteType cass_error_result_write_type(const CassErrorResult* error_result) {
58   return error_result->write_type();
59 }
60 
cass_error_result_keyspace(const CassErrorResult * error_result,const char ** keyspace,size_t * keyspace_length)61 CassError cass_error_result_keyspace(const CassErrorResult* error_result, const char** keyspace,
62                                      size_t* keyspace_length) {
63   if (error_result->code() != CQL_ERROR_ALREADY_EXISTS &&
64       error_result->code() != CQL_ERROR_FUNCTION_FAILURE) {
65     return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE;
66   }
67   *keyspace = error_result->keyspace().data();
68   *keyspace_length = error_result->keyspace().size();
69   return CASS_OK;
70 }
71 
cass_error_result_table(const CassErrorResult * error_result,const char ** table,size_t * table_length)72 CassError cass_error_result_table(const CassErrorResult* error_result, const char** table,
73                                   size_t* table_length) {
74   if (error_result->code() != CQL_ERROR_ALREADY_EXISTS) {
75     return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE;
76   }
77   *table = error_result->table().data();
78   *table_length = error_result->table().size();
79   return CASS_OK;
80 }
81 
cass_error_result_function(const CassErrorResult * error_result,const char ** function,size_t * function_length)82 CassError cass_error_result_function(const CassErrorResult* error_result, const char** function,
83                                      size_t* function_length) {
84   if (error_result->code() != CQL_ERROR_FUNCTION_FAILURE) {
85     return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE;
86   }
87   *function = error_result->function().data();
88   *function_length = error_result->function().size();
89   return CASS_OK;
90 }
91 
cass_error_num_arg_types(const CassErrorResult * error_result)92 size_t cass_error_num_arg_types(const CassErrorResult* error_result) {
93   return error_result->arg_types().size();
94 }
95 
cass_error_result_arg_type(const CassErrorResult * error_result,size_t index,const char ** arg_type,size_t * arg_type_length)96 CassError cass_error_result_arg_type(const CassErrorResult* error_result, size_t index,
97                                      const char** arg_type, size_t* arg_type_length) {
98   if (error_result->code() != CQL_ERROR_FUNCTION_FAILURE) {
99     return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE;
100   }
101   if (index > error_result->arg_types().size()) {
102     return CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS;
103   }
104   StringRef arg_type_ref = error_result->arg_types()[index];
105   *arg_type = arg_type_ref.data();
106   *arg_type_length = arg_type_ref.size();
107   return CASS_OK;
108 }
109 
110 } // extern "C"
111 
error_message() const112 String ErrorResponse::error_message() const {
113   OStringStream ss;
114   ss << "'" << message().to_string() << "'"
115      << " (0x" << std::hex << std::uppercase << std::setw(8) << std::setfill('0')
116      << CASS_ERROR(CASS_ERROR_SOURCE_SERVER, code()) << ")";
117   return ss.str();
118 }
119 
decode(Decoder & decoder)120 bool ErrorResponse::decode(Decoder& decoder) {
121   decoder.set_type("error");
122   CHECK_RESULT(decoder.decode_int32(code_));
123   CHECK_RESULT(decoder.decode_string(&message_));
124 
125   switch (code_) {
126     case CQL_ERROR_UNAVAILABLE:
127       CHECK_RESULT(decoder.decode_uint16(cl_));
128       CHECK_RESULT(decoder.decode_int32(required_));
129       CHECK_RESULT(decoder.decode_int32(received_));
130       break;
131     case CQL_ERROR_READ_TIMEOUT:
132       CHECK_RESULT(decoder.decode_uint16(cl_));
133       CHECK_RESULT(decoder.decode_int32(received_));
134       CHECK_RESULT(decoder.decode_int32(required_));
135       CHECK_RESULT(decoder.decode_byte(data_present_));
136       break;
137     case CQL_ERROR_WRITE_TIMEOUT:
138       CHECK_RESULT(decoder.decode_uint16(cl_));
139       CHECK_RESULT(decoder.decode_int32(received_));
140       CHECK_RESULT(decoder.decode_int32(required_));
141       CHECK_RESULT(decoder.decode_write_type(write_type_));
142       break;
143     case CQL_ERROR_READ_FAILURE:
144       CHECK_RESULT(decoder.decode_uint16(cl_));
145       CHECK_RESULT(decoder.decode_int32(received_));
146       CHECK_RESULT(decoder.decode_int32(required_));
147       CHECK_RESULT(decoder.decode_failures(failures_, num_failures_));
148       CHECK_RESULT(decoder.decode_byte(data_present_));
149       break;
150     case CQL_ERROR_FUNCTION_FAILURE:
151       CHECK_RESULT(decoder.decode_string(&keyspace_));
152       CHECK_RESULT(decoder.decode_string(&function_));
153       CHECK_RESULT(decoder.decode_stringlist(arg_types_));
154       break;
155     case CQL_ERROR_WRITE_FAILURE:
156       CHECK_RESULT(decoder.decode_uint16(cl_));
157       CHECK_RESULT(decoder.decode_int32(received_));
158       CHECK_RESULT(decoder.decode_int32(required_));
159       CHECK_RESULT(decoder.decode_failures(failures_, num_failures_));
160       CHECK_RESULT(decoder.decode_write_type(write_type_));
161       break;
162     case CQL_ERROR_UNPREPARED:
163       CHECK_RESULT(decoder.decode_string(&prepared_id_));
164       break;
165     case CQL_ERROR_ALREADY_EXISTS:
166       CHECK_RESULT(decoder.decode_string(&keyspace_));
167       CHECK_RESULT(decoder.decode_string(&table_));
168       break;
169   }
170 
171   decoder.maybe_log_remaining();
172   return true;
173 }
174 
check_error_or_invalid_response(const String & prefix,uint8_t expected_opcode,const Response * response)175 bool check_error_or_invalid_response(const String& prefix, uint8_t expected_opcode,
176                                      const Response* response) {
177   if (response->opcode() == expected_opcode) {
178     return false;
179   }
180 
181   OStringStream ss;
182   if (response->opcode() == CQL_OPCODE_ERROR) {
183     ss << prefix << ": Error response "
184        << static_cast<const ErrorResponse*>(response)->error_message();
185   } else {
186     ss << prefix << ": Unexpected opcode " << opcode_to_string(response->opcode());
187   }
188 
189   LOG_ERROR("%s", ss.str().c_str());
190 
191   return true;
192 }
193