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