Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add tsurugi-error handling functionality #108

Merged
merged 5 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions include/ogawayama/stub/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,13 @@ class Connection : public manager::message::Receiver {
*/
[[nodiscard]] manager::message::Status receive_drop_index(manager::metadata::ObjectIdType object_id) const override;

/**
* @brief get the error of the last SQL executed
* @param code returns the error code reported by the tsurugidb
* @return error code defined in error_code.h
*/
ErrorCode tsurugi_error(tsurugi_error_code& code);

private:
std::unique_ptr<Impl> impl_;

Expand Down
27 changes: 26 additions & 1 deletion include/ogawayama/stub/error_code.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2023 Project Tsurugi.
* Copyright 2019-2024 Project Tsurugi.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,6 +15,9 @@
*/
#pragma once

#include <cstdint>
#include <string>

namespace ogawayama::stub {

/**
Expand Down Expand Up @@ -87,6 +90,10 @@ enum class ErrorCode {
*/
TRANSACTION_ALREADY_STARTED,

/**
* @brief Encountered server error, where you can obtain error detail with Connection::tsurugi_error() API.
*/
SERVER_ERROR,
};

constexpr std::string_view error_name(ErrorCode code) {
Expand All @@ -107,4 +114,22 @@ constexpr std::string_view error_name(ErrorCode code) {
}
}

struct tsurugi_error_code {
public:
enum class tsurugi_error_type : std::int32_t {
none = 0,
framework_error = 1,
sql_error = 2
};
// SQL or framework error
tsurugi_error_type type{}; //NOLINT(misc-non-private-member-variables-in-classes)
// see SqlServiceCode.java for SQL error
std::uint32_t code{}; //NOLINT(misc-non-private-member-variables-in-classes)
std::string name{}; //NOLINT(misc-non-private-member-variables-in-classes)
std::string detail{}; //NOLINT(misc-non-private-member-variables-in-classes)
std::string supplemental_text{}; //NOLINT(misc-non-private-member-variables-in-classes)

tsurugi_error_code() = default;
};

} // namespace ogawayama::stub
19 changes: 1 addition & 18 deletions src/jogasaki/proto/sql/response.proto
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,6 @@ message Explain {
// request is successfully completed.
Success success = 11;

// deprecated: The result output string of the explain.
string output = 1;

Error error = 2;
}
}
Expand Down Expand Up @@ -144,20 +141,6 @@ message DescribeTable {
}
}

// execute a statement with 2-D parameter table.
message Batch {
reserved 1 to 10;

// the response body.
oneof result {
// request is successfully completed.
Success success = 11;

// engine error was occurred.
Error error = 12;
}
}

message Identifier {
// the label.
string label = 1;
Expand Down Expand Up @@ -295,7 +278,7 @@ message Response {
ExecuteQuery execute_query = 4;
Explain explain = 5;
DescribeTable describe_table = 6;
Batch batch = 7;
// 7 is no longer used.
ListTables list_tables = 8;
GetSearchPath get_search_path = 9;
GetErrorInfo get_error_info = 10;
Expand Down
138 changes: 107 additions & 31 deletions src/ogawayama/stub/connection.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2023 Project Tsurugi.
* Copyright 2019-2024 Project Tsurugi.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -29,6 +29,7 @@

#include <ogawayama/common/bridge.h>
#include "prepared_statementImpl.h"
#include "ogawayama/transport/tsurugi_error.h"
#include "connectionImpl.h"

namespace ogawayama::stub {
Expand Down Expand Up @@ -76,17 +77,22 @@ ErrorCode Connection::Impl::hello()
*/
ErrorCode Connection::Impl::begin(TransactionPtr& transaction)
{
::jogasaki::proto::sql::request::Begin request{};
auto response_opt = transport_.send(request);
if (!response_opt) {
return ErrorCode::SERVER_FAILURE;
}
auto response_begin = response_opt.value();
if (response_begin.has_success()) {
transaction = std::make_unique<Transaction>(std::make_unique<Transaction::Impl>(this, transport_, response_begin.success().transaction_handle()));
return ErrorCode::OK;
try {
::jogasaki::proto::sql::request::Begin request{};

auto response_opt = transport_.send(request);
if (!response_opt) {
return ErrorCode::SERVER_FAILURE;
}
auto response_begin = response_opt.value();
if (response_begin.has_success()) {
transaction = std::make_unique<Transaction>(std::make_unique<Transaction::Impl>(this, transport_, response_begin.success().transaction_handle()));
return ErrorCode::OK;
}
return ErrorCode::SERVER_ERROR;
} catch (std::runtime_error &e) {
return ErrorCode::SERVER_ERROR;
}
return ErrorCode::SERVER_FAILURE;
}

/**
Expand Down Expand Up @@ -143,16 +149,20 @@ ErrorCode Connection::Impl::begin(const boost::property_tree::ptree& option, Tra
}
}

auto response_opt = transport_.send(request);
if (!response_opt) {
try {
auto response_opt = transport_.send(request);
if (!response_opt) {
return ErrorCode::SERVER_FAILURE;
}
auto response_begin = response_opt.value();
if (response_begin.has_success()) {
transaction = std::make_unique<Transaction>(std::make_unique<Transaction::Impl>(this, transport_, response_begin.success().transaction_handle()));
return ErrorCode::OK;
}
return ErrorCode::SERVER_FAILURE;
} catch (std::runtime_error &e) {
return ErrorCode::SERVER_ERROR;
}
auto response_begin = response_opt.value();
if (response_begin.has_success()) {
transaction = std::make_unique<Transaction>(std::make_unique<Transaction::Impl>(this, transport_, response_begin.success().transaction_handle()));
return ErrorCode::OK;
}
return ErrorCode::SERVER_FAILURE;
}

/**
Expand Down Expand Up @@ -207,19 +217,23 @@ ErrorCode Connection::Impl::prepare(std::string_view sql, const placeholders_typ
}
}

auto response_opt = transport_.send(request);
if (!response_opt) {
return ErrorCode::SERVER_FAILURE;
}
auto response_prepare = response_opt.value();
if (response_prepare.has_prepared_statement_handle()) {
auto& psh = response_prepare.prepared_statement_handle();
std::size_t id = psh.handle();
bool has_result_records = psh.has_result_records();
prepared = std::make_unique<PreparedStatement>(std::make_unique<PreparedStatement::Impl>(this, id, has_result_records));
return ErrorCode::OK;
try {
auto response_opt = transport_.send(request);
if (!response_opt) {
return ErrorCode::SERVER_FAILURE;
}
auto response_prepare = response_opt.value();
if (response_prepare.has_prepared_statement_handle()) {
auto& psh = response_prepare.prepared_statement_handle();
std::size_t id = psh.handle();
bool has_result_records = psh.has_result_records();
prepared = std::make_unique<PreparedStatement>(std::make_unique<PreparedStatement::Impl>(this, id, has_result_records));
return ErrorCode::OK;
}
return ErrorCode::SERVER_ERROR;
} catch (std::runtime_error &e) {
return ErrorCode::SERVER_ERROR;
}
return ErrorCode::SERVER_FAILURE;
}

static inline
Expand Down Expand Up @@ -448,6 +462,60 @@ ErrorCode Connection::Impl::end_ddl()
return ERROR_CODE::SERVER_FAILURE; // service returns std::nullopt
}

static inline bool handle_sql_error(ogawayama::stub::tsurugi_error_code& code, ::jogasaki::proto::sql::response::Error& sql_error) {
if (auto itr = ogawayama::transport::error_map.find(sql_error.code()); itr != ogawayama::transport::error_map.end()) {
code.type = tsurugi_error_code::tsurugi_error_type::sql_error;
code.code = itr->second.second;
code.name = itr->second.first;
code.detail = sql_error.detail();
code.supplemental_text = sql_error.supplemental_text();
return true;
}
return false;
}

static inline bool handle_framework_error(ogawayama::stub::tsurugi_error_code& code, ::tateyama::proto::diagnostics::Record& framework_error) {
if (auto itr = ogawayama::transport::framework_error_map.find(framework_error.code()); itr != ogawayama::transport::framework_error_map.end()) {
code.type = tsurugi_error_code::tsurugi_error_type::framework_error;
code.code = itr->second.second;
code.name = itr->second.first;
code.detail = framework_error.message();
return true;
}
return false;
}

/**
* @brief get the error of the last SQL executed
*/
ErrorCode Connection::Impl::tsurugi_error(tsurugi_error_code& code)
{
switch(transport_.last_header().payload_type()) {
case ::tateyama::proto::framework::response::Header_PayloadType::Header_PayloadType_UNKNOWN:
break;
case ::tateyama::proto::framework::response::Header_PayloadType::Header_PayloadType_SERVER_DIAGNOSTICS:
{
auto frame_error = transport_.last_framework_error();
if (handle_framework_error(code, frame_error)) {
return ErrorCode::OK;
}
break;
}
case ::tateyama::proto::framework::response::Header_PayloadType::Header_PayloadType_SERVICE_RESULT:
{
auto sql_error = transport_.last_sql_error();
if (sql_error.code() == ::jogasaki::proto::sql::error::Code::CODE_UNSPECIFIED) {
code.type = tsurugi_error_code::tsurugi_error_type::none;
return ErrorCode::OK;
}
if (handle_sql_error(code, sql_error)) {
return ErrorCode::OK;
}
break;
}
}
return ErrorCode::UNKNOWN;
}

/**
* @brief constructor of Connection class
Expand Down Expand Up @@ -528,4 +596,12 @@ manager::message::Status Connection::receive_drop_index(const manager::metadata:
return {reply == ErrorCode::OK ? manager::message::ErrorCode::SUCCESS : manager::message::ErrorCode::FAILURE, static_cast<int>(reply)};
}

/**
* @brief get the error of the last SQL executed
*/
ErrorCode Connection::tsurugi_error(tsurugi_error_code& code)
{
return impl_->tsurugi_error(code);
}

} // namespace ogawayama::stub
9 changes: 8 additions & 1 deletion src/ogawayama/stub/connectionImpl.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2023 Project Tsurugi.
* Copyright 2019-2024 Project Tsurugi.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -99,6 +99,13 @@ class Connection::Impl
*/
ErrorCode end_ddl();

/**
* @brief get the error of the last SQL executed
* @param code returns the error code reported by the tsurugidb
* @return error code defined in error_code.h
*/
ErrorCode tsurugi_error(tsurugi_error_code& code);

private:
Stub::Impl* manager_;
std::string session_id_;
Expand Down
Loading