2
0
mirror of https://github.com/boostorg/mysql.git synced 2026-02-15 01:02:17 +00:00

Prepared statement methods

This commit is contained in:
Ruben Perez
2022-07-30 17:25:45 +02:00
parent d7833401a0
commit 9d39d72ef3
11 changed files with 202 additions and 317 deletions

View File

@@ -521,7 +521,7 @@ public:
* The handler signature for this operation is
* `void(boost::mysql::error_code, boost::mysql::resultset<Stream>)`.
*/
template <
template<
class ValueCollection,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
CompletionToken

View File

@@ -30,8 +30,8 @@ async_connect(
channel<Stream>& chan,
const typename Stream::lowest_layer_type::endpoint_type& endpoint,
const connection_params& params,
CompletionToken&& token,
error_info& info
error_info& info,
CompletionToken&& token
);
} // detail

View File

@@ -11,6 +11,8 @@
#include <boost/mysql/detail/network_algorithms/common.hpp>
#include <boost/mysql/resultset.hpp>
#include <boost/mysql/value.hpp>
#include <boost/mysql/prepared_statement.hpp>
#include <boost/mysql/execute_params.hpp>
namespace boost {
namespace mysql {
@@ -19,9 +21,7 @@ namespace detail {
template <class Stream, class ValueForwardIterator>
void execute_statement(
channel<Stream>& channel,
std::uint32_t statement_id,
ValueForwardIterator params_begin,
ValueForwardIterator params_end,
const execute_params<ValueForwardIterator>& params,
resultset& output,
error_code& err,
error_info& info
@@ -31,9 +31,7 @@ template <class Stream, class ValueForwardIterator, class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_execute_statement(
channel<Stream>& chan,
std::uint32_t statement_id,
ValueForwardIterator params_begin,
ValueForwardIterator params_end,
const execute_params<ValueForwardIterator>& params,
resultset& output,
error_info& info,
CompletionToken&& token

View File

@@ -32,8 +32,8 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_handshake(
channel<Stream>& channel,
const connection_params& params,
CompletionToken&& token,
error_info& info
error_info& info,
CompletionToken&& token
);
} // detail

View File

@@ -110,8 +110,8 @@ boost::mysql::detail::async_connect(
channel<Stream>& chan,
const typename Stream::lowest_layer_type::endpoint_type& endpoint,
const connection_params& params,
CompletionToken&& token,
error_info& info
error_info& info,
CompletionToken&& token
)
{
return boost::asio::async_compose<CompletionToken, void(error_code)>(

View File

@@ -11,6 +11,7 @@
#pragma once
#include <boost/mysql/resultset.hpp>
#include <boost/mysql/execute_params.hpp>
#include <boost/mysql/detail/network_algorithms/execute_statement.hpp>
#include <boost/mysql/detail/protocol/binary_deserialization.hpp>
#include <boost/mysql/detail/protocol/prepared_statement_messages.hpp>
@@ -22,21 +23,20 @@ namespace detail {
template <class ValueForwardIterator>
com_stmt_execute_packet<ValueForwardIterator> make_stmt_execute_packet(
std::uint32_t statement_id,
ValueForwardIterator params_begin,
ValueForwardIterator params_end
const execute_params<ValueForwardIterator>& params
)
{
return com_stmt_execute_packet<ValueForwardIterator> {
statement_id,
params.statement_id(),
std::uint8_t(0), // flags
std::uint32_t(1), // iteration count
std::uint8_t(1), // new params flag: set
params_begin,
params_end
params.first(),
params.last()
};
}
} // detail
} // mysql
} // boost
@@ -44,9 +44,7 @@ com_stmt_execute_packet<ValueForwardIterator> make_stmt_execute_packet(
template <class Stream, class ValueForwardIterator>
void boost::mysql::detail::execute_statement(
channel<Stream>& chan,
std::uint32_t statement_id,
ValueForwardIterator params_begin,
ValueForwardIterator params_end,
const execute_params<ValueForwardIterator>& params,
resultset& output,
error_code& err,
error_info& info
@@ -55,7 +53,7 @@ void boost::mysql::detail::execute_statement(
execute_generic(
&deserialize_binary_row,
chan,
make_stmt_execute_packet(statement_id, params_begin, params_end),
make_stmt_execute_packet(params),
output,
err,
info
@@ -69,9 +67,7 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
)
boost::mysql::detail::async_execute_statement(
channel<Stream>& chan,
std::uint32_t statement_id,
ValueForwardIterator params_begin,
ValueForwardIterator params_end,
const execute_params<ValueForwardIterator>& params,
resultset& output,
error_info& info,
CompletionToken&& token
@@ -80,7 +76,7 @@ boost::mysql::detail::async_execute_statement(
return async_execute_generic(
&deserialize_binary_row,
chan,
make_stmt_execute_packet(statement_id, params_begin, params_end),
make_stmt_execute_packet(params),
output,
info,
std::forward<CompletionToken>(token)

View File

@@ -551,8 +551,8 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
boost::mysql::detail::async_handshake(
channel<Stream>& chan,
const connection_params& params,
CompletionToken&& token,
error_info& info
error_info& info,
CompletionToken&& token
)
{
chan.reset();

View File

@@ -10,13 +10,35 @@
#include <boost/mysql/value.hpp>
#include <boost/mysql/prepared_statement.hpp>
#include <boost/mysql/detail/auxiliar/stringize.hpp>
#include <boost/mysql/detail/auxiliar/value_type_traits.hpp>
#include <iterator>
#include <stdexcept>
#include <type_traits>
namespace boost {
namespace mysql {
// TODO: move this to impl file
namespace detail {
template <class ValueForwardIterator>
void check_num_params(
ValueForwardIterator first,
ValueForwardIterator last,
const prepared_statement& stmt
)
{
auto param_count = std::distance(first, last);
if (param_count != stmt.num_params())
{
throw std::domain_error(detail::stringize(
"prepared_statement::execute: expected ", stmt.num_params(), " params, but got ", param_count));
}
}
} // detail
/**
* \brief Represents the parameters required to execute a [reflink prepared_statement].
@@ -41,53 +63,27 @@ class execute_params
"ValueForwardIterator requirements not met");
public:
/// Constructor.
constexpr execute_params(
std::uint32_t statement_id,
execute_params(
const prepared_statement& stmt,
ValueForwardIterator first,
ValueForwardIterator last
) :
statement_id_(statement_id),
statement_id_(stmt.id()),
first_(first),
last_(last)
{
detail::check_num_params(first, last, stmt);
}
constexpr std::uint32_t statement_id() const noexcept { return statement_id_; }
void set_statement_id(std::uint32_t v) noexcept { statement_id_ = v; }
/// Retrieves the parameter value range's begin.
constexpr ValueForwardIterator first() const { return first_; }
/// Retrieves the parameter value range's end.
constexpr ValueForwardIterator last() const { return last_; }
/// Sets the parameter value range's begin.
void set_first(ValueForwardIterator v) { first_ = v;}
/// Sets the parameter value range's end.
void set_last(ValueForwardIterator v) { last_ = v; }
};
/**
* \relates execute_params
* \brief Creates an instance of [reflink execute_params] from a pair of iterators.
* \details ValueForwardIterator should meet the [reflink ValueForwardIterator] type requirements.
*/
template <
class ValueForwardIterator,
class EnableIf = detail::enable_if_value_forward_iterator<ValueForwardIterator>
>
constexpr execute_params<ValueForwardIterator>
make_execute_params(
std::uint32_t statement_id,
ValueForwardIterator first,
ValueForwardIterator last
)
{
return execute_params<ValueForwardIterator>(statement_id, first, last);
}
template <
class ValueForwardIterator,
class EnableIf = detail::enable_if_value_forward_iterator<ValueForwardIterator>
@@ -99,23 +95,7 @@ make_execute_params(
ValueForwardIterator last
)
{
return execute_params<ValueForwardIterator>(stmt.id(), first, last);
}
/**
* \relates execute_params
* \brief Creates an instance of [reflink execute_params] from a collection.
* \details ValueCollection should meet the [reflink ValueCollection] type requirements.
*/
template <
class ValueCollection,
class EnableIf = detail::enable_if_value_collection<ValueCollection>
>
constexpr auto make_execute_params(
const ValueCollection& col
) -> execute_params<decltype(std::begin(col))>
{
return make_execute_params(std::begin(col), std::end(col));
return execute_params<ValueForwardIterator>(stmt, first, last);
}
template <
@@ -127,7 +107,7 @@ constexpr auto make_execute_params(
const ValueCollection& col
) -> execute_params<decltype(std::begin(col))>
{
return make_execute_params(stmt.id(), std::begin(col), std::end(col));
return make_execute_params(stmt, std::begin(col), std::end(col));
}
} // mysql

View File

@@ -11,15 +11,22 @@
#pragma once
#include <boost/mysql/connection.hpp>
#include <boost/mysql/prepared_statement.hpp>
#include <boost/mysql/resultset.hpp>
#include <boost/mysql/detail/network_algorithms/connect.hpp>
#include <boost/mysql/detail/network_algorithms/handshake.hpp>
#include <boost/mysql/detail/network_algorithms/execute_query.hpp>
#include <boost/mysql/detail/network_algorithms/prepare_statement.hpp>
#include <boost/mysql/detail/network_algorithms/execute_statement.hpp>
#include <boost/mysql/detail/network_algorithms/close_statement.hpp>
#include <boost/mysql/detail/network_algorithms/read_one_row.hpp>
#include <boost/mysql/detail/network_algorithms/quit_connection.hpp>
#include <boost/mysql/detail/network_algorithms/close_connection.hpp>
#include <boost/asio/buffer.hpp>
#include <utility>
// connect
template <class Stream>
template <class EndpointType>
void boost::mysql::connection<Stream>::connect(
@@ -66,11 +73,13 @@ boost::mysql::connection<Stream>::async_connect(
this->get_channel(),
endpoint,
params,
std::forward<CompletionToken>(token),
output_info
output_info,
std::forward<CompletionToken>(token)
);
}
// handshake
template <class Stream>
void boost::mysql::connection<Stream>::handshake(
const connection_params& params,
@@ -108,47 +117,46 @@ boost::mysql::connection<Stream>::async_handshake(
return detail::async_handshake(
get_channel(),
params,
std::forward<CompletionToken>(token),
output_info
output_info,
std::forward<CompletionToken>(token)
);
}
// Query
template <class Stream>
boost::mysql::resultset<Stream> boost::mysql::connection<Stream>::query(
void boost::mysql::connection<Stream>::query(
boost::string_view query_string,
resultset& result,
error_code& err,
error_info& info
)
{
detail::clear_errors(err, info);
resultset<Stream> res;
detail::execute_query(get_channel(), query_string, res, err, info);
return res;
detail::execute_query(get_channel(), query_string, result, err, info);
}
template <class Stream>
boost::mysql::resultset<Stream> boost::mysql::connection<Stream>::query(
boost::string_view query_string
void boost::mysql::connection<Stream>::query(
boost::string_view query_string,
resultset& result
)
{
resultset<Stream> res;
detail::error_block blk;
detail::execute_query(get_channel(), query_string, res, blk.err, blk.info);
detail::execute_query(get_channel(), query_string, result, blk.err, blk.info);
blk.check();
return res;
}
template <class Stream>
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code, ::boost::mysql::resultset<Stream>)
void(::boost::mysql::error_code)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code, boost::mysql::resultset<Stream>)
void(boost::mysql::error_code)
)
boost::mysql::connection<Stream>::async_query(
boost::string_view query_string,
resultset& result,
error_info& output_info,
CompletionToken&& token
)
@@ -157,46 +165,48 @@ boost::mysql::connection<Stream>::async_query(
return detail::async_execute_query(
get_channel(),
query_string,
std::forward<CompletionToken>(token),
output_info
result,
output_info,
std::forward<CompletionToken>(token)
);
}
// Prepare statement
template <class Stream>
boost::mysql::prepared_statement<Stream> boost::mysql::connection<Stream>::prepare_statement(
void boost::mysql::connection<Stream>::prepare_statement(
boost::string_view statement,
prepared_statement& output,
error_code& err,
error_info& info
)
{
mysql::prepared_statement<Stream> res;
detail::clear_errors(err, info);
detail::prepare_statement(get_channel(), statement, err, info, res);
return res;
detail::prepare_statement(get_channel(), statement, output, err, info);
}
template <class Stream>
boost::mysql::prepared_statement<Stream> boost::mysql::connection<Stream>::prepare_statement(
boost::string_view statement
void boost::mysql::connection<Stream>::prepare_statement(
boost::string_view statement,
prepared_statement& output
)
{
mysql::prepared_statement<Stream> res;
detail::error_block blk;
detail::prepare_statement(get_channel(), statement, blk.err, blk.info, res);
detail::prepare_statement(get_channel(), statement, output, blk.err, blk.info);
blk.check();
return res;
}
template <class Stream>
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code, ::boost::mysql::prepared_statement<Stream>)
void(::boost::mysql::error_code)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code, boost::mysql::prepared_statement<Stream>)
void(boost::mysql::error_code)
)
boost::mysql::connection<Stream>::async_prepare_statement(
boost::string_view statement,
prepared_statement& output,
error_info& output_info,
CompletionToken&& token
)
@@ -205,12 +215,125 @@ boost::mysql::connection<Stream>::async_prepare_statement(
return detail::async_prepare_statement(
get_channel(),
statement,
output,
output_info,
std::forward<CompletionToken>(token)
);
}
// Execute statement
template <class Stream>
template <class ValueForwardIterator>
void boost::mysql::connection<Stream>::execute_statement(
const execute_params<ValueForwardIterator>& params,
resultset& result,
error_code& err,
error_info& info
)
{
detail::clear_errors(err, info);
detail::execute_statement(
get_channel(),
params,
result,
err,
info
);
}
template <class Stream>
template <class ValueForwardIterator>
void boost::mysql::connection<Stream>::execute_statement(
const execute_params<ValueForwardIterator>& params,
resultset& result
)
{
detail::error_block blk;
detail::execute_statement(
get_channel(),
params,
result,
blk.err,
blk.info
);
blk.check();
}
template <class Stream>
template <class ValueForwardIterator, BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code)
)
boost::mysql::connection<Stream>::async_execute_statement(
const execute_params<ValueForwardIterator>& params,
resultset& result,
error_info& output_info,
CompletionToken&& token
)
{
output_info.clear();
detail::async_execute_statement(
get_channel(),
params,
result,
output_info,
std::forward<CompletionToken>(token)
);
}
// Close statement
template <class Stream>
void boost::mysql::connection<Stream>::close_statement(
const prepared_statement& stmt,
error_code& code,
error_info& info
)
{
detail::clear_errors(code, info);
detail::close_statement(get_channel(), stmt.id(), code, info);
}
template <class Stream>
void boost::mysql::connection<Stream>::close_statement(
const prepared_statement& stmt
)
{
detail::error_block blk;
detail::close_statement(get_channel(), stmt.id(), blk.err, blk.info);
blk.check();
}
template <class Stream>
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code)
)
boost::mysql::connection<Stream>::async_close_statement(
const prepared_statement& stmt,
error_info& output_info,
CompletionToken&& token
)
{
output_info.clear();
return detail::async_close_statement(
get_channel(),
stmt.id(),
std::forward<CompletionToken>(token),
output_info
);
}
// Close
template <class Stream>
void boost::mysql::connection<Stream>::close(
error_code& err,

View File

@@ -1,208 +0,0 @@
//
// Copyright (c) 2019-2022 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MYSQL_IMPL_PREPARED_STATEMENT_HPP
#define BOOST_MYSQL_IMPL_PREPARED_STATEMENT_HPP
#pragma once
#include <boost/mysql/prepared_statement.hpp>
#include <boost/mysql/detail/network_algorithms/execute_statement.hpp>
#include <boost/mysql/detail/network_algorithms/close_statement.hpp>
#include <boost/mysql/detail/auxiliar/stringize.hpp>
#include <boost/asio/bind_executor.hpp>
template <class Stream>
template <class ValueForwardIterator>
void boost::mysql::prepared_statement<Stream>::check_num_params(
ValueForwardIterator first,
ValueForwardIterator last,
error_code& err,
error_info& info
) const
{
auto param_count = std::distance(first, last);
if (param_count != num_params())
{
err = make_error_code(errc::wrong_num_params);
info.set_message(detail::stringize(
"prepared_statement::execute: expected ", num_params(), " params, but got ", param_count));
}
}
template <class Stream>
template <class ValueForwardIterator>
boost::mysql::resultset<Stream> boost::mysql::prepared_statement<Stream>::execute(
const execute_params<ValueForwardIterator>& params,
error_code& err,
error_info& info
)
{
assert(valid());
mysql::resultset<Stream> res;
detail::clear_errors(err, info);
// Verify we got passed the right number of params
check_num_params(params.first(), params.last(), err, info);
if (!err)
{
detail::execute_statement(
*channel_,
stmt_msg_.statement_id,
params.first(),
params.last(),
res,
err,
info
);
}
return res;
}
template <class Stream>
template <class ValueForwardIterator>
boost::mysql::resultset<Stream> boost::mysql::prepared_statement<Stream>::execute(
const execute_params<ValueForwardIterator>& params
)
{
detail::error_block blk;
auto res = execute(params, blk.err, blk.info);
blk.check();
return res;
}
// Helper for async_execute
template <class Stream>
struct boost::mysql::prepared_statement<Stream>::async_execute_initiation
{
template <class HandlerType>
struct error_handler
{
error_code err;
HandlerType h;
void operator()()
{
std::forward<HandlerType>(h)(err, resultset<Stream>());
}
};
template <class HandlerType, class ValueForwardIterator>
void operator()(
HandlerType&& handler,
error_code err,
error_info& info,
prepared_statement<Stream>& stmt,
ValueForwardIterator params_first,
ValueForwardIterator params_last
) const
{
if (err)
{
auto executor = boost::asio::get_associated_executor(
handler,
stmt.next_layer().get_executor()
);
boost::asio::post(boost::asio::bind_executor(
executor,
error_handler<HandlerType>{err, std::forward<HandlerType>(handler)}
));
}
else
{
// Actually execute the statement
detail::async_execute_statement(
*stmt.channel_,
stmt.stmt_msg_.statement_id,
params_first,
params_last,
std::forward<HandlerType>(handler),
info
);
}
}
};
template <class Stream>
template <class ValueForwardIterator, BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code, ::boost::mysql::resultset<Stream>)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code, boost::mysql::resultset<Stream>)
)
boost::mysql::prepared_statement<Stream>::async_execute(
const execute_params<ValueForwardIterator>& params,
error_info& output_info,
CompletionToken&& token
)
{
output_info.clear();
assert(valid());
// Check we got passed the right number of params
error_code err;
check_num_params(params.first(), params.last(), err, output_info);
return boost::asio::async_initiate<CompletionToken, void(error_code, resultset<Stream>)>(
async_execute_initiation(),
token,
err,
std::ref(output_info),
std::ref(*this),
params.first(),
params.last()
);
}
template <class Stream>
void boost::mysql::prepared_statement<Stream>::close(
error_code& code,
error_info& info
)
{
assert(valid());
detail::clear_errors(code, info);
detail::close_statement(*channel_, id(), code, info);
}
template <class Stream>
void boost::mysql::prepared_statement<Stream>::close()
{
assert(valid());
detail::error_block blk;
detail::close_statement(*channel_, id(), blk.err, blk.info);
blk.check();
}
template <class Stream>
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code)
)
boost::mysql::prepared_statement<Stream>::async_close(
error_info& output_info,
CompletionToken&& token
)
{
assert(valid());
output_info.clear();
return detail::async_close_statement(
*channel_,
id(),
std::forward<CompletionToken>(token),
output_info
);
}
#endif /* INCLUDE_BOOST_MYSQL_IMPL_PREPARED_STATEMENT_HPP_ */

View File

@@ -43,10 +43,6 @@ class prepared_statement
{
bool valid_ {false};
detail::com_stmt_prepare_ok_packet stmt_msg_;
template <class ValueForwardIterator>
void check_num_params(ValueForwardIterator first, ValueForwardIterator last, error_code& err, error_info& info) const;
public:
/**
* \brief Default constructor.