| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| #include "error_response.hpp" |
| |
| #include "external.hpp" |
| #include "logger.hpp" |
| #include "serialization.hpp" |
| |
| #include <iomanip> |
| |
| using namespace datastax; |
| using namespace datastax::internal; |
| using namespace datastax::internal::core; |
| |
| extern "C" { |
| |
| void cass_error_result_free(const CassErrorResult* error_result) { error_result->dec_ref(); } |
| |
| CassError cass_error_result_code(const CassErrorResult* error_result) { |
| return static_cast<CassError>(CASS_ERROR(CASS_ERROR_SOURCE_SERVER, error_result->code())); |
| } |
| |
| CassConsistency cass_error_result_consistency(const CassErrorResult* error_result) { |
| return error_result->consistency(); |
| } |
| |
| cass_int32_t cass_error_result_responses_received(const CassErrorResult* error_result) { |
| return error_result->received(); |
| } |
| |
| cass_int32_t cass_error_result_responses_required(const CassErrorResult* error_result) { |
| return error_result->required(); |
| } |
| |
| cass_int32_t cass_error_result_num_failures(const CassErrorResult* error_result) { |
| return error_result->num_failures(); |
| } |
| |
| cass_bool_t cass_error_result_data_present(const CassErrorResult* error_result) { |
| return static_cast<cass_bool_t>(error_result->data_present()); |
| } |
| |
| CassWriteType cass_error_result_write_type(const CassErrorResult* error_result) { |
| return error_result->write_type(); |
| } |
| |
| CassError cass_error_result_keyspace(const CassErrorResult* error_result, const char** keyspace, |
| size_t* keyspace_length) { |
| if (error_result->code() != CQL_ERROR_ALREADY_EXISTS && |
| error_result->code() != CQL_ERROR_FUNCTION_FAILURE) { |
| return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE; |
| } |
| *keyspace = error_result->keyspace().data(); |
| *keyspace_length = error_result->keyspace().size(); |
| return CASS_OK; |
| } |
| |
| CassError cass_error_result_table(const CassErrorResult* error_result, const char** table, |
| size_t* table_length) { |
| if (error_result->code() != CQL_ERROR_ALREADY_EXISTS) { |
| return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE; |
| } |
| *table = error_result->table().data(); |
| *table_length = error_result->table().size(); |
| return CASS_OK; |
| } |
| |
| CassError cass_error_result_function(const CassErrorResult* error_result, const char** function, |
| size_t* function_length) { |
| if (error_result->code() != CQL_ERROR_FUNCTION_FAILURE) { |
| return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE; |
| } |
| *function = error_result->function().data(); |
| *function_length = error_result->function().size(); |
| return CASS_OK; |
| } |
| |
| size_t cass_error_num_arg_types(const CassErrorResult* error_result) { |
| return error_result->arg_types().size(); |
| } |
| |
| CassError cass_error_result_arg_type(const CassErrorResult* error_result, size_t index, |
| const char** arg_type, size_t* arg_type_length) { |
| if (error_result->code() != CQL_ERROR_FUNCTION_FAILURE) { |
| return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE; |
| } |
| if (index > error_result->arg_types().size()) { |
| return CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS; |
| } |
| StringRef arg_type_ref = error_result->arg_types()[index]; |
| *arg_type = arg_type_ref.data(); |
| *arg_type_length = arg_type_ref.size(); |
| return CASS_OK; |
| } |
| |
| } // extern "C" |
| |
| String ErrorResponse::error_message() const { |
| OStringStream ss; |
| ss << "'" << message().to_string() << "'" |
| << " (0x" << std::hex << std::uppercase << std::setw(8) << std::setfill('0') |
| << CASS_ERROR(CASS_ERROR_SOURCE_SERVER, code()) << ")"; |
| return ss.str(); |
| } |
| |
| bool ErrorResponse::decode(Decoder& decoder) { |
| decoder.set_type("error"); |
| CHECK_RESULT(decoder.decode_int32(code_)); |
| CHECK_RESULT(decoder.decode_string(&message_)); |
| |
| switch (code_) { |
| case CQL_ERROR_UNAVAILABLE: |
| CHECK_RESULT(decoder.decode_uint16(cl_)); |
| CHECK_RESULT(decoder.decode_int32(required_)); |
| CHECK_RESULT(decoder.decode_int32(received_)); |
| break; |
| case CQL_ERROR_READ_TIMEOUT: |
| CHECK_RESULT(decoder.decode_uint16(cl_)); |
| CHECK_RESULT(decoder.decode_int32(received_)); |
| CHECK_RESULT(decoder.decode_int32(required_)); |
| CHECK_RESULT(decoder.decode_byte(data_present_)); |
| break; |
| case CQL_ERROR_WRITE_TIMEOUT: |
| CHECK_RESULT(decoder.decode_uint16(cl_)); |
| CHECK_RESULT(decoder.decode_int32(received_)); |
| CHECK_RESULT(decoder.decode_int32(required_)); |
| CHECK_RESULT(decoder.decode_write_type(write_type_)); |
| break; |
| case CQL_ERROR_READ_FAILURE: |
| CHECK_RESULT(decoder.decode_uint16(cl_)); |
| CHECK_RESULT(decoder.decode_int32(received_)); |
| CHECK_RESULT(decoder.decode_int32(required_)); |
| CHECK_RESULT(decoder.decode_failures(failures_, num_failures_)); |
| CHECK_RESULT(decoder.decode_byte(data_present_)); |
| break; |
| case CQL_ERROR_FUNCTION_FAILURE: |
| CHECK_RESULT(decoder.decode_string(&keyspace_)); |
| CHECK_RESULT(decoder.decode_string(&function_)); |
| CHECK_RESULT(decoder.decode_stringlist(arg_types_)); |
| break; |
| case CQL_ERROR_WRITE_FAILURE: |
| CHECK_RESULT(decoder.decode_uint16(cl_)); |
| CHECK_RESULT(decoder.decode_int32(received_)); |
| CHECK_RESULT(decoder.decode_int32(required_)); |
| CHECK_RESULT(decoder.decode_failures(failures_, num_failures_)); |
| CHECK_RESULT(decoder.decode_write_type(write_type_)); |
| break; |
| case CQL_ERROR_UNPREPARED: |
| CHECK_RESULT(decoder.decode_string(&prepared_id_)); |
| break; |
| case CQL_ERROR_ALREADY_EXISTS: |
| CHECK_RESULT(decoder.decode_string(&keyspace_)); |
| CHECK_RESULT(decoder.decode_string(&table_)); |
| break; |
| } |
| |
| decoder.maybe_log_remaining(); |
| return true; |
| } |
| |
| bool check_error_or_invalid_response(const String& prefix, uint8_t expected_opcode, |
| const Response* response) { |
| if (response->opcode() == expected_opcode) { |
| return false; |
| } |
| |
| OStringStream ss; |
| if (response->opcode() == CQL_OPCODE_ERROR) { |
| ss << prefix << ": Error response " |
| << static_cast<const ErrorResponse*>(response)->error_message(); |
| } else { |
| ss << prefix << ": Unexpected opcode " << opcode_to_string(response->opcode()); |
| } |
| |
| LOG_ERROR("%s", ss.str().c_str()); |
| |
| return true; |
| } |