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

ClickHouse Integration #376

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion include/boost/mysql/connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ class connection
* If the final handler has an associated immediate executor, and the operation
* completes immediately, the final handler is dispatched to it.
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
* and is never be called inline from within this function.
* and is never to be called inline from within this function.
*/
template <
typename EndpointType,
Expand Down
16 changes: 10 additions & 6 deletions include/boost/mysql/impl/internal/auth/auth.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,17 @@ struct authentication_plugin

BOOST_INLINE_CONSTEXPR authentication_plugin all_authentication_plugins[] = {
{
make_string_view("mysql_native_password"),
&mnp_compute_response,
},
make_string_view("mysql_native_password"),
&mnp_compute_response,
},
{
make_string_view("caching_sha2_password"),
&csha2p_compute_response,
},
make_string_view("caching_sha2_password"),
&csha2p_compute_response,
},
{
make_string_view("double_sha1_password"),
&mnp_compute_response,
},
};

inline const authentication_plugin* find_plugin(string_view name)
Expand Down
3 changes: 2 additions & 1 deletion include/boost/mysql/impl/internal/protocol/db_flavor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ namespace detail {
enum class db_flavor
{
mysql,
mariadb
mariadb,
clickhouse
};

} // namespace detail
Expand Down
58 changes: 47 additions & 11 deletions include/boost/mysql/impl/internal/protocol/deserialization.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace mysql {
namespace detail {

// OK packets (views because strings are non-owning)
inline error_code deserialize_ok_packet(span<const std::uint8_t> msg, ok_view& output); // for testing
inline error_code deserialize_ok_packet(span<const std::uint8_t> msg, ok_view& output, db_flavor flavor); // for testing

// Error packets (exposed for testing)
struct err_view
Expand All @@ -71,6 +71,12 @@ BOOST_ATTRIBUTE_NODISCARD inline error_code process_error_packet(
// Applicable for commands like ping and reset connection.
// If the response is an OK packet, sets backslash_escapes according to the
// OK packet's server status flags
BOOST_ATTRIBUTE_NODISCARD inline deserialize_errc get_info_value(
deserialization_context& ctx,
string_view& output,
db_flavor flavor
);

BOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_ok_response(
span<const std::uint8_t> message,
db_flavor flavor,
Expand Down Expand Up @@ -267,9 +273,32 @@ BOOST_INLINE_CONSTEXPR std::uint8_t ok_packet_header = 0x00;
//

// OK packets
boost::mysql::detail::deserialize_errc boost::mysql::detail::get_info_value(
deserialization_context& ctx,
string_view& output,
db_flavor flavor
)
{
boost::mysql::detail::deserialize_errc err;
if (flavor == db_flavor::clickhouse)
{
string_eof info;
err = info.deserialize(ctx);
output = info.value;

} else
{
string_lenenc info;
err = info.deserialize(ctx);
output = info.value;
}
return err;
}

boost::mysql::error_code boost::mysql::detail::deserialize_ok_packet(
span<const std::uint8_t> msg,
ok_view& output
ok_view& output,
db_flavor flavor
)
{
struct ok_packet
Expand All @@ -279,18 +308,19 @@ boost::mysql::error_code boost::mysql::detail::deserialize_ok_packet(
int_lenenc last_insert_id;
int2 status_flags; // server_status_flags
int2 warnings;
// CLIENT_SESSION_TRACK: not implemented
string_lenenc info;
} pack{};

string_view info_value;

deserialization_context ctx(msg);
auto err = ctx.deserialize(pack.affected_rows, pack.last_insert_id, pack.status_flags, pack.warnings);
if (err != deserialize_errc::ok)
return to_error_code(err);

if (ctx.enough_size(1)) // message is optional, may be omitted
{
err = pack.info.deserialize(ctx);
// CLIENT_SESSION_TRACK: not implemented
err = get_info_value(ctx, info_value, flavor);
if (err != deserialize_errc::ok)
return to_error_code(err);
}
Expand All @@ -300,7 +330,7 @@ boost::mysql::error_code boost::mysql::detail::deserialize_ok_packet(
pack.last_insert_id.value,
pack.status_flags.value,
pack.warnings.value,
pack.info.value,
info_value,
};

return ctx.check_extra_bytes();
Expand Down Expand Up @@ -473,7 +503,7 @@ boost::mysql::error_code boost::mysql::detail::deserialize_ok_response(
{
// Verify that the ok_packet is correct
ok_view ok{};
err = deserialize_ok_packet(ctx.to_span(), ok);
err = deserialize_ok_packet(ctx.to_span(), ok, flavor);
if (err)
return err;
backslash_escapes = ok.backslash_escapes();
Expand Down Expand Up @@ -574,7 +604,7 @@ boost::mysql::detail::execute_response boost::mysql::detail::deserialize_execute
if (msg_type.value == ok_packet_header)
{
ok_view ok{};
err = deserialize_ok_packet(ctx.to_span(), ok);
err = deserialize_ok_packet(ctx.to_span(), ok, flavor);
if (err)
return err;
return ok;
Expand Down Expand Up @@ -630,7 +660,7 @@ boost::mysql::detail::row_message boost::mysql::detail::deserialize_row_message(
{
// end of resultset => this is a ok_packet, not a row
ok_view ok{};
auto err = deserialize_ok_packet(ctx.to_span(), ok);
auto err = deserialize_ok_packet(ctx.to_span(), ok, flavor);
if (err)
return err;
return ok;
Expand Down Expand Up @@ -762,7 +792,13 @@ inline capabilities compose_capabilities(string_fixed<2> low, string_fixed<2> hi

inline db_flavor parse_db_version(string_view version_string)
{
return version_string.find("MariaDB") != string_view::npos ? db_flavor::mariadb : db_flavor::mysql;
if (version_string.find("MariaDB") != std::string_view::npos) {
return db_flavor::mariadb;
} else if (version_string.find("ClickHouse") != std::string_view::npos) {
return db_flavor::clickhouse;
} else {
return db_flavor::mysql;
}
}

} // namespace detail
Expand Down Expand Up @@ -940,7 +976,7 @@ boost::mysql::detail::handhake_server_response boost::mysql::detail::deserialize
if (msg_type.value == ok_packet_header)
{
ok_view ok{};
err = deserialize_ok_packet(ctx.to_span(), ok);
err = deserialize_ok_packet(ctx.to_span(), ok, flavor);
if (err)
return err;
return ok;
Expand Down
2 changes: 1 addition & 1 deletion include/boost/mysql/impl/internal/sansio/handshake.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ class handshake_algo
error_code process_ok(connection_state_data& st)
{
ok_view res{};
auto ec = deserialize_ok_packet(st.reader.message(), res);
auto ec = deserialize_ok_packet(st.reader.message(), res, st.flavor);
if (ec)
return ec;
on_success(st, res);
Expand Down
3 changes: 2 additions & 1 deletion test/fuzzing/fuzz_ok_packet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ using namespace boost::mysql::detail;
static bool parse_ok_packet(const uint8_t* data, size_t size) noexcept
{
ok_view msg{};
auto ec = deserialize_ok_packet({data, size}, msg);
db_flavor flavor{db::mysql};
auto ec = deserialize_ok_packet({data, size}, msg, flavor);
return !ec.failed() && msg.is_out_params();
}

Expand Down
6 changes: 4 additions & 2 deletions test/unit/test/protocol/deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ BOOST_AUTO_TEST_CASE(ok_view_success)
BOOST_TEST_CONTEXT(tc.name)
{
ok_view actual{};
error_code err = deserialize_ok_packet(tc.serialized, actual);
db_flavor flavor{db_flavor::mysql};
error_code err = deserialize_ok_packet(tc.serialized, actual, flavor);

// No error
BOOST_TEST(err == error_code());
Expand Down Expand Up @@ -153,7 +154,8 @@ BOOST_AUTO_TEST_CASE(ok_view_error)
BOOST_TEST_CONTEXT(tc.name)
{
ok_view value{};
error_code err = deserialize_ok_packet(tc.serialized, value);
db_flavor flavor{db_flavor::mysql};
error_code err = deserialize_ok_packet(tc.serialized, value, flavor);
BOOST_TEST(err == tc.expected_err);
}
}
Expand Down