mirror of
https://github.com/boostorg/mysql.git
synced 2025-05-12 14:11:41 +00:00
Generic execute and start_execution functions
Added execute, start_execution, ExecutionRequest and statement::bind. Deprecated query, execute_statement, start_query and start_statement_execution. Statements can now be executed specifying parameters as iterator ranges. Fixed a bug that caused build problems when FieldViewForwardIterator's reference is convertible to field_view, but not field_view. Close #111 Close #137 Close #138
This commit is contained in:
parent
ed007e31ae
commit
0571e4b886
@ -47,6 +47,7 @@ docca.reference reference.qbk
|
||||
\"BOOST_CXX14_CONSTEXPR=constexpr\" \\
|
||||
\"BOOST_MYSQL_FIELD_LIKE_TUPLE=class\" \\
|
||||
\"BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR=class\" \\
|
||||
\"BOOST_MYSQL_EXECUTION_REQUEST=class\" \\
|
||||
"
|
||||
<doxygen:param>SKIP_FUNCTION_MACROS=NO
|
||||
<doxygen:param>OUTPUT_LANGUAGE=English
|
||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 29 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
@ -40,6 +40,7 @@
|
||||
[def __CompletionToken__ [@boost:/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.completion_tokens_and_handlers ['CompletionToken]]]
|
||||
[def __FieldViewFwdIterator__ [reflink2 FieldViewFwdIterator ['FieldViewFwdIterator]]]
|
||||
[def __FieldLikeTuple__ [reflink2 FieldLikeTuple ['FieldLikeTuple]]]
|
||||
[def __ExecutionRequest__ [reflink2 ExecutionRequest ['ExecutionRequest]]]
|
||||
|
||||
[def __Boost__ [@https://www.boost.org/ Boost]]
|
||||
[def __Asio__ [@boost:/libs/asio/index.html Boost.Asio]]
|
||||
@ -115,5 +116,6 @@
|
||||
[include helpers/SocketStream.qbk]
|
||||
[include helpers/FieldViewFwdIterator.qbk]
|
||||
[include helpers/FieldLikeTuple.qbk]
|
||||
[include helpers/ExecutionRequest.qbk]
|
||||
[block'''</part>''']
|
||||
[endsect]
|
||||
|
@ -62,7 +62,7 @@ which accepts two parameters:
|
||||
[heading Issuing the SQL query]
|
||||
|
||||
The next step is to issue the query to the server. We will use
|
||||
[reflink2 connection.query tcp_ssl_connection::query],
|
||||
[reflink2 connection.execute tcp_ssl_connection::execute],
|
||||
which accepts a string containing a single SQL query and instructs
|
||||
the server to run it. It returns a [reflink results]
|
||||
object, containing the rows returned by the query:
|
||||
|
@ -57,7 +57,8 @@ read [link mysql.other_streams.non_sockets this section] for more info.
|
||||
|
||||
[section:queries_stmts Text queries and prepared statements]
|
||||
|
||||
The two main ways to use a connection are text queries and prepared statements:
|
||||
The two main ways to use a connection are text queries and prepared statements.
|
||||
You can access both using [refmem connection execute]:
|
||||
|
||||
[table
|
||||
[
|
||||
@ -67,7 +68,7 @@ The two main ways to use a connection are text queries and prepared statements:
|
||||
]
|
||||
[
|
||||
[
|
||||
Text queries: [refmem connection query].
|
||||
Text queries
|
||||
]
|
||||
[
|
||||
Simple queries, without parameters:
|
||||
@ -83,9 +84,7 @@ The two main ways to use a connection are text queries and prepared statements:
|
||||
]
|
||||
[
|
||||
[
|
||||
Prepared statements:[br]
|
||||
[refmem connection prepare_statement][br]
|
||||
[refmem connection execute_statement]
|
||||
Prepared statements
|
||||
]
|
||||
[
|
||||
Queries with parameters unknown at compile-time.
|
||||
@ -117,8 +116,8 @@ We can see that a resultset is composed of three pieces of information:
|
||||
* Additional information about the query execution, like the number of affected rows ([refmem results affected_rows])
|
||||
or the number of warnings generated by the query ([refmem results warning_count]).
|
||||
|
||||
You can obtain a `results` object by executing a text query ([refmem connection query]) or a prepared statement
|
||||
([refmem connection execute_statement]).
|
||||
You can obtain a `results` object by executing a text query or a prepared statement, by calling
|
||||
[refmem connection execute].
|
||||
|
||||
All SQL statements generate resultsets. Statements that generate no rows, like `INSERT`s, generate empty resultsets
|
||||
(i.e. `result.rows().empty() == true`). The interface to execute `SELECT`s and `INSERT`s is the same.
|
||||
@ -309,7 +308,7 @@ Until now, we've used simple text queries that did not contain any user-provided
|
||||
In the real world, most queries will contain some piece of user-provided input.
|
||||
|
||||
One approach could be to use string concatenation to construct a SQL query from user input,
|
||||
and then execute it using `query()`. Avoid this approach as much as possible, as it can lead
|
||||
and then pass it to `execute()`. Avoid this approach as much as possible, as it can lead
|
||||
to [*SQL injection vulnerabilities]. Instead, [*use prepared statements].
|
||||
|
||||
Prepared statements are server-side objects that represent a parameterized query. A statement is
|
||||
@ -321,17 +320,16 @@ by ID. You've got the following table definition:
|
||||
|
||||
[overview_statements_setup]
|
||||
|
||||
You can prepare a statement to retrieve products by ID using:
|
||||
You can prepare a statement to retrieve products by ID using [refmem connection prepare_statement]:
|
||||
|
||||
[overview_statements_prepare]
|
||||
|
||||
You can execute the statement using [refmem connection execute_statement]:
|
||||
You can execute the statement using [refmem connection execute]:
|
||||
|
||||
[overview_statements_execute]
|
||||
|
||||
The `statement` object is passed as first parameter, which tells the server which
|
||||
statement it should execute. Actual parameters are passed as the second argument,
|
||||
as a `std::tuple`. You must pass as many parameters as `?` placeholders the statement has.
|
||||
We used [refmem statement bind] to provide actual parameters to the statement.
|
||||
You must pass as many parameters to `bind` as `?` placeholders the statement has.
|
||||
|
||||
To learn more about prepared statements, please refer to [link mysql.prepared_statements this section].
|
||||
|
||||
@ -339,8 +337,8 @@ To learn more about prepared statements, please refer to [link mysql.prepared_st
|
||||
|
||||
[section Multi-function operations]
|
||||
|
||||
Until now, we've been using [refmem connection query] and [refmem connection execute_statement], which
|
||||
execute some SQL and read all generated data into an in-memory `results` object.
|
||||
Until now, we've been using [refmem connection execute], which
|
||||
executes some SQL and reads all generated data into an in-memory `results` object.
|
||||
|
||||
Some use cases may not fit in this simple pattern. For example:
|
||||
|
||||
@ -349,14 +347,14 @@ Some use cases may not fit in this simple pattern. For example:
|
||||
* If rows contain very long `TEXT` or `BLOB` fields, it may not be adequate to copy these values
|
||||
from the network buffer into the `results` object. A view-based approach may be better.
|
||||
|
||||
For these cases, we can break the `query()` or `execute_statement()` operation into several steps,
|
||||
For these cases, we can break the `execute()` operation into several steps,
|
||||
using a ['multi-function operation] (the term is coined by this library). This example reads an entire
|
||||
table in batches, which can be the case in an ETL process:
|
||||
|
||||
[overview_multifn]
|
||||
|
||||
[warning
|
||||
Once you start a multi-function operation with [refmem connection start_query] or [refmem connection start_statement_execution],
|
||||
Once you start a multi-function operation with [refmem connection start_execution],
|
||||
the server immediately sends all rows to the client. [*You must read all rows] before engaging in further operations.
|
||||
Otherwise, you will encounter packet mismatches, which can lead to bugs and vulnerabilities!
|
||||
]
|
||||
@ -404,8 +402,7 @@ This is because the connection uses the underlying `Stream` object directly, wit
|
||||
or queueing. If you perform several async operations concurrently on a single connection without any
|
||||
serialization, the stream may interleave reads and writes from different operations, leading to undefined behavior.
|
||||
|
||||
For example, [refmem connection async_query] performs both reads and writes.
|
||||
Doing this is illegal and should be avoided:
|
||||
For example, doing the following is illegal and should be avoided:
|
||||
|
||||
[overview_async_dont]
|
||||
|
||||
|
@ -7,12 +7,13 @@
|
||||
|
||||
[section:queries Text queries]
|
||||
|
||||
To run a text query, use any of the following functions:
|
||||
To run a text query, use any of the following functions, passing a string-like
|
||||
object (convertible to [reflink string_view]) containing valid SQL as the first parameter:
|
||||
|
||||
* [refmem connection query] or [refmem connection async_query], which execute the query and
|
||||
read the generated results.
|
||||
* [refmem connection start_query] and [refmem connection async_start_query], which initiate a
|
||||
text query as a multi-function operation.
|
||||
* [refmem connection execute] or [refmem connection async_execute]: these functions run the query and
|
||||
read the generated results into memory.
|
||||
* [refmem connection start_execution] and [refmem connection async_start_execution]: these functions
|
||||
initiate a text query as a multi-function operation.
|
||||
|
||||
Almost any query that may be issued in the `mysql` command line
|
||||
can be executed using this method. This includes `SELECT`s,
|
||||
@ -36,7 +37,7 @@ instead, which perform composition server-side in a safe way.
|
||||
|
||||
[heading Running multiple queries at once]
|
||||
|
||||
You can run several semicolon-separated queries in a single call by enabling
|
||||
You can run several semicolon-separated queries in a single `execute()` call by enabling
|
||||
the [refmem handshake_params multi_queries] option. You can find an example
|
||||
[link mysql.multi_resultset.multi_queries here].
|
||||
|
||||
|
@ -29,9 +29,9 @@ will use these values to run the statement.
|
||||
|
||||
To execute a statement, use any of the following functions:
|
||||
|
||||
* [refmem connection execute_statement] or [refmem connection async_execute_statement],
|
||||
* [refmem connection execute] or [refmem connection async_execute],
|
||||
which execute the statement and read the generated rows.
|
||||
* [refmem connection start_statement_execution] and [refmem connection async_start_statement_execution], which initiate a
|
||||
* [refmem connection start_execution] and [refmem connection async_start_execution], which initiate a
|
||||
statement execution as a multi-function operation.
|
||||
|
||||
For example:
|
||||
@ -47,9 +47,9 @@ Some observations:
|
||||
* Parameters are passed as a `std::tuple`. You can pass in built-in integers,
|
||||
`float`, `double`, [reflink date], [reflink datetime], [reflink time],
|
||||
[reflink field_view] and [reflink field] objects as parameters.
|
||||
* `show_in_store` is passed as an `int` to `execute_statement()`, but is defined as a `TINYINT`
|
||||
* `show_in_store` is passed as an `int` to `statement::bind()`, but is defined as a `TINYINT`
|
||||
(1 byte integer) in the table. As long as the passed integer is in range, MySQL
|
||||
will perform the required conversions. Otherwise, `execute_statement()` will fail with an error
|
||||
will perform the required conversions. Otherwise, `execute()` will fail with an error
|
||||
(no undefined behavior is invoked).
|
||||
|
||||
You can also pass [reflink field_view]s and [reflink field]s as parameters. This is handy
|
||||
@ -60,6 +60,14 @@ to insert `NULL` values:
|
||||
For a full reference on the types you can pass as parameters when
|
||||
executing a statement, see [link mysql.fields.cpp_to_mysql this section].
|
||||
|
||||
[heading Executing a statement with a variable number of parameters]
|
||||
|
||||
The above approach works when you know at compile time how many parameters the statement has.
|
||||
In some scenarios (e.g. a graphical interface), this may not be the case. For these cases, you can
|
||||
`bind` a statement to a `field` or `field_view` iterator range:
|
||||
|
||||
[prepared_statements_execute_iterator_range]
|
||||
|
||||
[heading Closing a statement]
|
||||
|
||||
Prepared statements are created server-side, and thus consume server resources. If you don't need a
|
||||
|
@ -86,7 +86,7 @@ To simplify things, you can use [refmem results out_params] to retrieve them:
|
||||
|
||||
[heading:multi_queries Semicolon-separated queries]
|
||||
|
||||
It is possible to run several semicolon-separated text queries in a single [refmem connection query] call.
|
||||
It is possible to run several semicolon-separated text queries in a single [refmem connection execute] call.
|
||||
For security, this capability is disabled by default. Enabling it requires setting [refmem handshake_params multi_queries]
|
||||
before connecting:
|
||||
|
||||
|
@ -28,9 +28,6 @@ executions. Each arrow represents a message.
|
||||
[$mysql/images/protocol.svg [align center]]
|
||||
|
||||
|
||||
The message exchange is similar for text queries and prepared statements. The wire format varies, but the semantics
|
||||
are the same.
|
||||
|
||||
There are two separate cases:
|
||||
|
||||
* If your query retrieved at least one column (even if no rows were generated), we're in ['case 1]. The server sends:
|
||||
@ -43,8 +40,8 @@ There are two separate cases:
|
||||
* If your query didn't retrieve any column, we're in ['case 2]. The server will just send an OK packet,
|
||||
with the same information as in ['case 1].
|
||||
|
||||
[refmem connection query] and [refmem connection execute_statement] handle the full message exchange. In contrast,
|
||||
[refmem connection start_query] and [refmem connection start_statement_execution] will not read the rows, if any.
|
||||
[refmem connection execute] handles the full message exchange. In contrast,
|
||||
[refmem connection start_execution] will not read the rows, if any.
|
||||
|
||||
Some takeaways:
|
||||
|
||||
@ -63,8 +60,7 @@ Given the following setup:
|
||||
|
||||
[multi_function_setup]
|
||||
|
||||
You can start a multi-function operation using [refmem connection start_query]
|
||||
or [refmem connection start_statement_execution]:
|
||||
You can start a multi-function operation using [refmem connection start_execution]:
|
||||
|
||||
[table
|
||||
[
|
||||
@ -72,8 +68,8 @@ or [refmem connection start_statement_execution]:
|
||||
[Prepared statements]
|
||||
]
|
||||
[
|
||||
[[multi_function_start_query]]
|
||||
[[multi_function_start_statement_execution]]
|
||||
[[multi_function_text_queries]]
|
||||
[[multi_function_statements]]
|
||||
]
|
||||
]
|
||||
|
||||
@ -138,7 +134,7 @@ while `should_read_rows()` will return false once an individual result has been
|
||||
describes which reading function should be invoked next:
|
||||
|
||||
* [refmem execution_state should_start_op]: the initial state, after you default-construct an `execution_state`.
|
||||
You should call functions like `start_query` or `start_statement_execution` to start the operation.
|
||||
You should call [refmem connection start_execution] or [refmem connection async_start_execution] to start the operation.
|
||||
* [refmem execution_state should_read_rows]: the next operation should be [refmem connection read_some_rows],
|
||||
to read the generated rows.
|
||||
* [refmem execution_state should_read_head]: the next operation should be [refmem connection read_resultset_head],
|
||||
|
@ -492,7 +492,7 @@ column shows what [refmem metadata type] would return for a column of that type.
|
||||
|
||||
[section:cpp_to_mysql C++ to MySQL type mapping reference]
|
||||
|
||||
This section shows how a parameter `v` in a expression `conn.execute_statement(stmt, std::make_tuple(v), result)`
|
||||
This section shows how a parameter `v` in a expression `conn.execute(stmt.bind(v), result)`
|
||||
is interpreted by MySQL, depeding on `v`'s type:
|
||||
|
||||
[table
|
||||
|
@ -46,13 +46,9 @@ character set and collation. You can specify this in two ways:
|
||||
* At any time, issuing a __SET_NAMES__ SQL statement. For example, `"SET NAMES utf8mb4"` will set the current
|
||||
connection's character set to `utf8mb4` and the connection's collation to utf8mb4's default collation.
|
||||
If the character set is unknown, the `SET NAMES` statement will fail.
|
||||
You can use [refmem connection query] to issue the statement:
|
||||
You can use [refmem connection execute] to issue the statement:
|
||||
|
||||
```
|
||||
results result;
|
||||
conn.query("SET NAMES utf8mb4", result);
|
||||
// Further operations can assume utf8mb4 as conn's charset
|
||||
```
|
||||
[charsets_set_names]
|
||||
|
||||
[endsect]
|
||||
|
||||
@ -63,14 +59,14 @@ The ones that impact this library's behavior are:
|
||||
|
||||
* [mysqllink server-system-variables.html#sysvar_character_set_client character_set_client]
|
||||
determines the encoding that SQL statements sent to the server should have. This includes
|
||||
the SQL strings in [refmem connection query], [refmem connection prepare_statement], and
|
||||
string parameters passed to [refmem connection execute_statement].
|
||||
the SQL strings passed to [refmem connection execute] and [refmem connection prepare_statement], and
|
||||
string parameters passed to [refmem statement bind].
|
||||
|
||||
Not all character sets are permissible in `character_set_client`. The server will accept setting
|
||||
this variable to any UTF-8 character set, but won't accept UTF-16.
|
||||
* [mysqllink server-system-variables.html#sysvar_character_set_results character_set_results]
|
||||
determines the encoding that the server will use to send any kind of result, including
|
||||
string fields retrieved by [refmem connection query] and [refmem connection execute_statement], metadata
|
||||
string fields retrieved by [refmem connection execute], metadata
|
||||
like [refmem metadata column_name] and error messages.
|
||||
|
||||
Note that, when you define a string column with a character set (e.g.
|
||||
@ -90,16 +86,16 @@ The table below summarizes the encoding used by each piece of functionality in t
|
||||
[Encoding given by...]
|
||||
]
|
||||
[
|
||||
[SQL query strings passed to [refmem connection query] and [refmem connection prepare_statement]]
|
||||
[SQL query strings passed to [refmem connection execute] and [refmem connection prepare_statement]]
|
||||
[`character_set_client`]
|
||||
]
|
||||
[
|
||||
[String values passed as parameters to [refmem connection execute_statement]]
|
||||
[String values passed as parameters to [refmem statement bind]]
|
||||
[`character_set_client`]
|
||||
]
|
||||
[
|
||||
[
|
||||
String fields retrieved by [refmem connection query] or [refmem connection execute_statement]:[br][br]
|
||||
String fields retrieved by [refmem connection execute] or [refmem connection read_some_rows]:[br][br]
|
||||
[refmem field_view as_string][br]
|
||||
[refmem field_view get_string]
|
||||
]
|
||||
|
25
doc/qbk/helpers/ExecutionRequest.qbk
Normal file
25
doc/qbk/helpers/ExecutionRequest.qbk
Normal file
@ -0,0 +1,25 @@
|
||||
[/
|
||||
Copyright (c) 2019-2023 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)
|
||||
]
|
||||
|
||||
[section:boost__mysql__ExecutionRequest ExecutionRequest concept]
|
||||
|
||||
An execution request represents a SQL statement to be executed by the
|
||||
server, plus any parameters required to run the query. It may model
|
||||
a plain text query, or a prepared statement handle with bound parameters.
|
||||
|
||||
Formally, a type `T` is a `ExecutionRequest` if it fulfills any of the following:
|
||||
|
||||
* It is convertible to [reflink string_view]. In this case, the execution request
|
||||
contains a text query to be run by the server.
|
||||
* An instantiation of the [reflink bound_statement_tuple] class, or a (possibly cv-qualified)
|
||||
reference to it.
|
||||
* An instantiation of the [reflink bound_statement_iterator_range] class, or a (possibly cv-qualified)
|
||||
reference to it.
|
||||
|
||||
This definition may be extended in future versions, but the above types will still satisfy `ExecutionRequest`.
|
||||
|
||||
[endsect]
|
@ -16,6 +16,8 @@
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="mysql.ref.boost__mysql__bad_field_access">bad_field_access</link></member>
|
||||
<member><link linkend="mysql.ref.boost__mysql__bound_statement_tuple">bound_statement_tuple</link></member>
|
||||
<member><link linkend="mysql.ref.boost__mysql__bound_statement_iterator_range">bound_statement_iterator_range</link></member>
|
||||
<member><link linkend="mysql.ref.boost__mysql__buffer_params">buffer_params</link></member>
|
||||
<member><link linkend="mysql.ref.boost__mysql__connection">connection</link></member>
|
||||
<member><link linkend="mysql.ref.boost__mysql__date">date</link></member>
|
||||
@ -87,6 +89,7 @@
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="mysql.ref.boost__mysql__ExecutionRequest">ExecutionRequest</link></member>
|
||||
<member><link linkend="mysql.ref.boost__mysql__FieldLikeTuple">FieldLikeTuple</link></member>
|
||||
<member><link linkend="mysql.ref.boost__mysql__FieldViewFwdIterator">FieldViewFwdIterator</link></member>
|
||||
<member><link linkend="mysql.ref.boost__mysql__SocketStream">SocketStream</link></member>
|
||||
|
@ -7,9 +7,7 @@
|
||||
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
exclude-result-prefixes="xs"
|
||||
expand-text="yes">
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" expand-text="yes">
|
||||
|
||||
<xsl:variable name="doc-ns" select="'boost::mysql'"/>
|
||||
<xsl:variable name="doc-ref" select="'mysql.ref'"/>
|
||||
@ -36,7 +34,8 @@
|
||||
'SocketStream',
|
||||
'Executor',
|
||||
'FieldLikeTuple',
|
||||
'FieldViewFwdIterator'
|
||||
'FieldViewFwdIterator',
|
||||
'ExecutionRequest'
|
||||
"/>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
@ -85,7 +85,7 @@ public:
|
||||
|
||||
void query_employees()
|
||||
{
|
||||
conn.async_execute_statement(stmt, std::make_tuple(company_id), result, diag, [this](error_code err) {
|
||||
conn.async_execute(stmt.bind(company_id), result, diag, [this](error_code err) {
|
||||
boost::mysql::throw_on_error(err, diag);
|
||||
for (boost::mysql::row_view employee : result.rows())
|
||||
{
|
||||
|
@ -90,7 +90,7 @@ void main_impl(int argc, char** argv)
|
||||
|
||||
// Execute the statement
|
||||
boost::mysql::results result;
|
||||
conn.async_execute_statement(stmt, std::make_tuple(company_id), result, diag, yield[ec]);
|
||||
conn.async_execute(stmt.bind(company_id), result, diag, yield[ec]);
|
||||
boost::mysql::throw_on_error(ec, diag);
|
||||
|
||||
// Print the employees
|
||||
|
@ -91,9 +91,7 @@ boost::asio::awaitable<void> coro_main(
|
||||
|
||||
// Execute the statement
|
||||
boost::mysql::results result;
|
||||
std::tie(ec
|
||||
) = co_await conn
|
||||
.async_execute_statement(stmt, std::make_tuple(company_id), result, diag, tuple_awaitable);
|
||||
std::tie(ec) = co_await conn.async_execute(stmt.bind(company_id), result, diag, tuple_awaitable);
|
||||
boost::mysql::throw_on_error(ec, diag);
|
||||
|
||||
// Print all employees
|
||||
|
@ -109,7 +109,7 @@ void main_impl(int argc, char** argv)
|
||||
|
||||
// Execute the statement
|
||||
boost::mysql::results result;
|
||||
fut = conn.async_execute_statement(stmt, std::make_tuple(company_id), result, use_future);
|
||||
fut = conn.async_execute(stmt.bind(company_id), result, use_future);
|
||||
fut.get();
|
||||
|
||||
// Print employees
|
||||
|
@ -69,7 +69,7 @@ boost::asio::awaitable<void> coro_main(
|
||||
|
||||
// Execute it
|
||||
boost::mysql::results result;
|
||||
std::tie(ec) = co_await conn.async_execute_statement(stmt, std::make_tuple(company_id), result, diag);
|
||||
std::tie(ec) = co_await conn.async_execute(stmt.bind(company_id), result, diag);
|
||||
boost::mysql::throw_on_error(ec, diag);
|
||||
|
||||
// Use the received rows
|
||||
|
@ -59,7 +59,7 @@ void main_impl(int argc, char** argv)
|
||||
JOIN company comp ON (comp.id = emp.company_id)
|
||||
)";
|
||||
boost::mysql::results result;
|
||||
conn.query(sql, result);
|
||||
conn.execute(sql, result);
|
||||
|
||||
/**
|
||||
* results objects allow you to access metadata about the columns in the query
|
||||
|
@ -95,12 +95,13 @@ void main_impl(int argc, char** argv)
|
||||
|
||||
/*
|
||||
* Once a statement has been prepared, it can be executed by calling
|
||||
* connection::execute_statement(). Parameter actual values are provided
|
||||
* as a std::tuple. Executing a statement yields a results object.
|
||||
* connection::execute(). Parameters are provided to statement::bind(),
|
||||
* which creates a bound statement object that can be passed to execute().
|
||||
* Executing a statement yields a results object.
|
||||
*/
|
||||
//[prepared_statements_execute
|
||||
boost::mysql::results select_result, update_result;
|
||||
conn.execute_statement(salary_getter, std::make_tuple(first_name), select_result);
|
||||
conn.execute(salary_getter.bind(first_name), select_result);
|
||||
//]
|
||||
|
||||
// First row, first column, cast to double
|
||||
@ -109,7 +110,7 @@ void main_impl(int argc, char** argv)
|
||||
|
||||
// Run the update. In this case, we must pass in two parameters.
|
||||
double payrise = generate_random_payrise();
|
||||
conn.execute_statement(salary_updater, std::make_tuple(payrise, first_name), update_result);
|
||||
conn.execute(salary_updater.bind(payrise, first_name), update_result);
|
||||
ASSERT(update_result.rows().empty()); // an UPDATE never returns rows
|
||||
|
||||
/**
|
||||
@ -117,7 +118,7 @@ void main_impl(int argc, char** argv)
|
||||
* as many times as we want. We do NOT need to call
|
||||
* connection::prepare_statement() again.
|
||||
*/
|
||||
conn.execute_statement(salary_getter, std::make_tuple(first_name), select_result);
|
||||
conn.execute(salary_getter.bind(first_name), select_result);
|
||||
double new_salary = select_result.rows().at(0).at(0).as_double();
|
||||
ASSERT(new_salary > old_salary); // Our update took place
|
||||
std::cout << "The salary after the payrise was: " << new_salary << std::endl;
|
||||
|
@ -91,11 +91,7 @@ void insert_product(
|
||||
)
|
||||
{
|
||||
results result;
|
||||
conn.execute_statement(
|
||||
stmt,
|
||||
std::make_tuple(description, price, static_cast<int>(show_in_store)),
|
||||
result
|
||||
);
|
||||
conn.execute(stmt.bind(description, price, static_cast<int>(show_in_store)), result);
|
||||
}
|
||||
//]
|
||||
|
||||
@ -117,15 +113,19 @@ void insert_product(
|
||||
|
||||
// Execute the insert
|
||||
results result;
|
||||
conn.execute_statement(
|
||||
stmt,
|
||||
std::make_tuple(description_param, price, static_cast<int>(show_in_store)),
|
||||
result
|
||||
);
|
||||
conn.execute(stmt.bind(description_param, price, static_cast<int>(show_in_store)), result);
|
||||
}
|
||||
//]
|
||||
#endif
|
||||
|
||||
//[prepared_statements_execute_iterator_range
|
||||
void exec_statement(tcp_ssl_connection& conn, const statement& stmt, const std::vector<field>& params)
|
||||
{
|
||||
results result;
|
||||
conn.execute(stmt.bind(params.begin(), params.end()), result);
|
||||
}
|
||||
//]
|
||||
|
||||
#ifdef BOOST_ASIO_HAS_CO_AWAIT
|
||||
boost::asio::awaitable<void> overview_coro(tcp_ssl_connection& conn)
|
||||
{
|
||||
@ -137,7 +137,7 @@ boost::asio::awaitable<void> overview_coro(tcp_ssl_connection& conn)
|
||||
// Run our query as a coroutine
|
||||
diagnostics diag;
|
||||
results result;
|
||||
auto [ec] = co_await conn.async_query("SELECT 'Hello world!'", result, diag, token);
|
||||
auto [ec] = co_await conn.async_execute("SELECT 'Hello world!'", result, diag, token);
|
||||
|
||||
// This will throw an error_with_diagnostics in case of failure
|
||||
boost::mysql::throw_on_error(ec, diag);
|
||||
@ -172,8 +172,8 @@ boost::asio::awaitable<void> dont_run()
|
||||
// DO NOT DO THIS!!!!
|
||||
results result1, result2;
|
||||
co_await (
|
||||
conn.async_query("SELECT 1", result1, boost::asio::use_awaitable) &&
|
||||
conn.async_query("SELECT 2", result2, boost::asio::use_awaitable)
|
||||
conn.async_execute("SELECT 1", result1, boost::asio::use_awaitable) &&
|
||||
conn.async_execute("SELECT 2", result2, boost::asio::use_awaitable)
|
||||
);
|
||||
//]
|
||||
}
|
||||
@ -218,7 +218,7 @@ void main_impl(int argc, char** argv)
|
||||
{
|
||||
//[overview_query_use_case
|
||||
results result;
|
||||
conn.query("START TRANSACTION", result);
|
||||
conn.execute("START TRANSACTION", result);
|
||||
//]
|
||||
}
|
||||
{
|
||||
@ -228,14 +228,14 @@ void main_impl(int argc, char** argv)
|
||||
);
|
||||
|
||||
results result;
|
||||
conn.execute_statement(stmt, std::make_tuple("HGS", 30000), result);
|
||||
conn.execute(stmt.bind("HGS", 30000), result);
|
||||
//]
|
||||
}
|
||||
{
|
||||
//[overview_views
|
||||
// Populate a results object
|
||||
results result;
|
||||
conn.query("SELECT 'Hello world'", result);
|
||||
conn.execute("SELECT 'Hello world'", result);
|
||||
|
||||
// results::rows() returns a rows_view. The underlying memory is owned by the results object
|
||||
rows_view all_rows = result.rows();
|
||||
@ -263,7 +263,7 @@ void main_impl(int argc, char** argv)
|
||||
{
|
||||
//[overview_using_fields
|
||||
results result;
|
||||
conn.query("SELECT 'abc', 42", result);
|
||||
conn.execute("SELECT 'abc', 42", result);
|
||||
|
||||
// Obtain a field's underlying value using the is_xxx and get_xxx accessors
|
||||
field_view f = result.rows().at(0).at(0); // f points to the string "abc"
|
||||
@ -290,7 +290,7 @@ void main_impl(int argc, char** argv)
|
||||
results result;
|
||||
|
||||
// Create some test data
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"%(
|
||||
CREATE TEMPORARY TABLE products (
|
||||
id VARCHAR(50) PRIMARY KEY,
|
||||
@ -299,10 +299,10 @@ void main_impl(int argc, char** argv)
|
||||
)%",
|
||||
result
|
||||
);
|
||||
conn.query("INSERT INTO products VALUES ('PTT', 'Potatoes'), ('CAR', NULL)", result);
|
||||
conn.execute("INSERT INTO products VALUES ('PTT', 'Potatoes'), ('CAR', NULL)", result);
|
||||
|
||||
// Retrieve the data. Note that some fields are NULL
|
||||
conn.query("SELECT id, description FROM products", result);
|
||||
conn.execute("SELECT id, description FROM products", result);
|
||||
|
||||
for (row_view r : result.rows())
|
||||
{
|
||||
@ -327,12 +327,12 @@ void main_impl(int argc, char** argv)
|
||||
}
|
||||
//]
|
||||
|
||||
conn.query("DROP TABLE products", result);
|
||||
conn.execute("DROP TABLE products", result);
|
||||
}
|
||||
{
|
||||
//[overview_statements_setup
|
||||
results result;
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"%(
|
||||
CREATE TEMPORARY TABLE products (
|
||||
id VARCHAR(50) PRIMARY KEY,
|
||||
@ -341,7 +341,7 @@ void main_impl(int argc, char** argv)
|
||||
)%",
|
||||
result
|
||||
);
|
||||
conn.query("INSERT INTO products VALUES ('PTT', 'Potatoes'), ('CAR', 'Carrots')", result);
|
||||
conn.execute("INSERT INTO products VALUES ('PTT', 'Potatoes'), ('CAR', 'Carrots')", result);
|
||||
//]
|
||||
}
|
||||
{
|
||||
@ -355,19 +355,19 @@ void main_impl(int argc, char** argv)
|
||||
|
||||
// Execute the statement
|
||||
results result;
|
||||
conn.execute_statement(stmt, std::make_tuple(product_id), result);
|
||||
conn.execute(stmt.bind(product_id), result);
|
||||
|
||||
// Use result as required
|
||||
//]
|
||||
|
||||
conn.query("DROP TABLE products", result);
|
||||
conn.execute("DROP TABLE products", result);
|
||||
}
|
||||
{
|
||||
//[overview_multifn
|
||||
// Create the table and some sample data
|
||||
// In a real system, body may be megabaytes long.
|
||||
results result;
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"%(
|
||||
CREATE TEMPORARY TABLE posts (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
@ -377,7 +377,7 @@ void main_impl(int argc, char** argv)
|
||||
)%",
|
||||
result
|
||||
);
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"%(
|
||||
INSERT INTO posts (title, body) VALUES
|
||||
('Post 1', 'A very long post body'),
|
||||
@ -390,7 +390,7 @@ void main_impl(int argc, char** argv)
|
||||
execution_state st;
|
||||
|
||||
// Writes the query request and reads the server response, but not the rows
|
||||
conn.start_query("SELECT title, body FROM posts", st);
|
||||
conn.start_execution("SELECT title, body FROM posts", st);
|
||||
|
||||
// Reads all the returned rows, in batches.
|
||||
// st.complete() returns true once there are no more rows to read
|
||||
@ -407,7 +407,7 @@ void main_impl(int argc, char** argv)
|
||||
}
|
||||
//]
|
||||
|
||||
conn.query("DROP TABLE posts", result);
|
||||
conn.execute("DROP TABLE posts", result);
|
||||
}
|
||||
{
|
||||
//[overview_errors_sync_errc
|
||||
@ -417,7 +417,7 @@ void main_impl(int argc, char** argv)
|
||||
|
||||
// The provided SQL is invalid. The server will return an error.
|
||||
// ec will be set to a non-zero value
|
||||
conn.query("this is not SQL!", result, ec, diag);
|
||||
conn.execute("this is not SQL!", result, ec, diag);
|
||||
|
||||
if (ec)
|
||||
{
|
||||
@ -437,7 +437,7 @@ void main_impl(int argc, char** argv)
|
||||
{
|
||||
// The provided SQL is invalid. This function will throw an exception.
|
||||
results result;
|
||||
conn.query("this is not SQL!", result);
|
||||
conn.execute("this is not SQL!", result);
|
||||
}
|
||||
catch (const error_with_diagnostics& err)
|
||||
{
|
||||
@ -459,7 +459,7 @@ void main_impl(int argc, char** argv)
|
||||
//[prepared_statements_prepare
|
||||
// Table setup
|
||||
results result;
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"%(
|
||||
CREATE TEMPORARY TABLE products (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
@ -482,16 +482,17 @@ void main_impl(int argc, char** argv)
|
||||
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
|
||||
insert_product(conn, stmt, std::optional<string_view>(), 2000, true);
|
||||
#endif
|
||||
conn.query("DROP TABLE products", result);
|
||||
exec_statement(conn, stmt, {field_view("abc"), field_view(2000), field_view(1)});
|
||||
conn.execute("DROP TABLE products", result);
|
||||
}
|
||||
|
||||
// multi-resultset
|
||||
{
|
||||
results result;
|
||||
conn.query("DROP PROCEDURE IF EXISTS get_employee", result);
|
||||
conn.execute("DROP PROCEDURE IF EXISTS get_employee", result);
|
||||
|
||||
//[multi_resultset_procedure
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"(
|
||||
CREATE PROCEDURE get_employee(IN pin_employee_id INT)
|
||||
BEGIN
|
||||
@ -511,7 +512,7 @@ void main_impl(int argc, char** argv)
|
||||
std::int64_t employee_id = get_employee_id();
|
||||
|
||||
// Call the statement
|
||||
conn.execute_statement(get_employee_stmt, std::make_tuple(employee_id), result);
|
||||
conn.execute(get_employee_stmt.bind(employee_id), result);
|
||||
//]
|
||||
|
||||
//[multi_resultset_first_resultset
|
||||
@ -523,11 +524,11 @@ void main_impl(int argc, char** argv)
|
||||
}
|
||||
{
|
||||
results result;
|
||||
conn.query("DROP PROCEDURE IF EXISTS create_employee", result);
|
||||
conn.execute("DROP PROCEDURE IF EXISTS create_employee", result);
|
||||
|
||||
//[multi_resultset_out_params
|
||||
// Setup the stored procedure
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"(
|
||||
CREATE PROCEDURE create_employee(
|
||||
IN pin_company_id CHAR(10),
|
||||
@ -554,7 +555,7 @@ void main_impl(int argc, char** argv)
|
||||
// When executing the statement, we provide an actual value for the IN parameters,
|
||||
// and a dummy value for the OUT parameter. This value will be ignored, but it's required by the
|
||||
// protocol
|
||||
conn.execute_statement(stmt, std::make_tuple("HGS", "John", "Doe", nullptr), result);
|
||||
conn.execute(stmt.bind("HGS", "John", "Doe", nullptr), result);
|
||||
|
||||
// Retrieve output parameters. This row_view has an element per
|
||||
// OUT or INOUT parameter that used a ? placeholder
|
||||
@ -586,7 +587,7 @@ void main_impl(int argc, char** argv)
|
||||
// We can now use the multi-query feature.
|
||||
// This will result in three resultsets, one per query.
|
||||
results result;
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"(
|
||||
CREATE TEMPORARY TABLE posts (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
@ -627,7 +628,7 @@ void main_impl(int argc, char** argv)
|
||||
{
|
||||
//[multi_function_setup
|
||||
results result;
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"%(
|
||||
CREATE TEMPORARY TABLE posts (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
@ -637,7 +638,7 @@ void main_impl(int argc, char** argv)
|
||||
)%",
|
||||
result
|
||||
);
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"%(
|
||||
INSERT INTO posts (title, body) VALUES
|
||||
('Post 1', 'A very long post body'),
|
||||
@ -667,35 +668,34 @@ void main_impl(int argc, char** argv)
|
||||
};
|
||||
|
||||
{
|
||||
//[multi_function_start_query
|
||||
//[multi_function_text_queries
|
||||
execution_state st;
|
||||
conn.start_query("SELECT title, body FROM posts", st);
|
||||
conn.start_execution("SELECT title, body FROM posts", st);
|
||||
//]
|
||||
|
||||
read_all_rows(st); // don't compromise further operations
|
||||
}
|
||||
|
||||
{
|
||||
//[multi_function_start_statement_execution
|
||||
//[multi_function_statements
|
||||
execution_state st;
|
||||
conn.start_statement_execution(
|
||||
stmt,
|
||||
std::make_tuple(), // The statement has no params, so an empty tuple is passed
|
||||
conn.start_execution(
|
||||
stmt.bind(), // The statement has no params, so an empty bind is performed
|
||||
st
|
||||
);
|
||||
//]
|
||||
|
||||
read_all_rows(st); // don't compromise further operations
|
||||
conn.query("DROP TABLE posts", result);
|
||||
conn.execute("DROP TABLE posts", result);
|
||||
}
|
||||
|
||||
{
|
||||
results result;
|
||||
conn.query("DROP PROCEDURE IF EXISTS get_company", result);
|
||||
conn.execute("DROP PROCEDURE IF EXISTS get_company", result);
|
||||
|
||||
//[multi_function_stored_procedure
|
||||
// Setup the stored procedure
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"(
|
||||
CREATE PROCEDURE get_company(IN pin_company_id CHAR(10))
|
||||
BEGIN
|
||||
@ -714,7 +714,7 @@ void main_impl(int argc, char** argv)
|
||||
// Call the procedure
|
||||
execution_state st;
|
||||
statement stmt = conn.prepare_statement("CALL get_company(?)");
|
||||
conn.start_statement_execution(stmt, std::make_tuple(company_id), st);
|
||||
conn.start_execution(stmt.bind(company_id), st);
|
||||
|
||||
// The above code will generate 3 resultsets
|
||||
// Read the 1st one, which contains the matched companies
|
||||
@ -750,7 +750,7 @@ void main_impl(int argc, char** argv)
|
||||
{
|
||||
//[fields_field_views
|
||||
results result;
|
||||
conn.query("SELECT 'Hello world!'", result);
|
||||
conn.execute("SELECT 'Hello world!'", result);
|
||||
|
||||
// fv doesn't own its memory; if result goes out of scope, fv becomes invalid
|
||||
field_view fv = result.rows().at(0).at(0);
|
||||
@ -764,7 +764,7 @@ void main_impl(int argc, char** argv)
|
||||
{
|
||||
//[fields_field_views_scalars
|
||||
results result;
|
||||
conn.query("SELECT 42", result);
|
||||
conn.execute("SELECT 42", result);
|
||||
|
||||
// fv doesn't own its memory; if result goes out of scope, fv becomes invalid
|
||||
field_view fv = result.rows().at(0).at(0);
|
||||
@ -778,7 +778,7 @@ void main_impl(int argc, char** argv)
|
||||
{
|
||||
//[fields_taking_ownership
|
||||
results result;
|
||||
conn.query("SELECT 'Hello world!'", result);
|
||||
conn.execute("SELECT 'Hello world!'", result);
|
||||
|
||||
// fv doesn't own its memory; if result goes out of scope, fv becomes invalid
|
||||
field_view fv = result.rows().at(0).at(0);
|
||||
@ -864,7 +864,7 @@ void main_impl(int argc, char** argv)
|
||||
{
|
||||
//[field_timestamp_setup
|
||||
results result;
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"%(
|
||||
CREATE TEMPORARY TABLE events (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
@ -885,7 +885,7 @@ void main_impl(int argc, char** argv)
|
||||
// This change has session scope. All operations after this query
|
||||
// will now use UTC for TIMESTAMPs. Other sessions will not see the change.
|
||||
// If you need to reconnect the connection, you need to run this again.
|
||||
conn.query("SET @time_zone = 'UTC'", result);
|
||||
conn.execute("SET @time_zone = 'UTC'", result);
|
||||
//]
|
||||
|
||||
//[fields_timestamp_insert
|
||||
@ -894,7 +894,7 @@ void main_impl(int argc, char** argv)
|
||||
datetime event_timestamp = datetime::now();
|
||||
|
||||
// event_timestamp will be interpreted as UTC if you have run SET @time_zone
|
||||
conn.execute_statement(insert_stmt, std::make_tuple(event_timestamp, "Something happened"), result);
|
||||
conn.execute(insert_stmt.bind(event_timestamp, "Something happened"), result);
|
||||
//]
|
||||
|
||||
//[fields_timestamp_select
|
||||
@ -903,14 +903,14 @@ void main_impl(int argc, char** argv)
|
||||
|
||||
// threshold will be interpreted as UTC. The retrieved events will have their
|
||||
// `t` column in UTC
|
||||
conn.execute_statement(select_stmt, std::make_tuple(threshold), result);
|
||||
conn.execute(select_stmt.bind(threshold), result);
|
||||
//]
|
||||
}
|
||||
{
|
||||
//[metadata
|
||||
// By default, a connection has metadata_mode::minimal
|
||||
results result;
|
||||
conn.query("SELECT 1 AS my_field", result);
|
||||
conn.execute("SELECT 1 AS my_field", result);
|
||||
string_view colname = result.meta()[0].column_name();
|
||||
|
||||
// colname will be empty because conn.meta_mode() == metadata_mode::minimal
|
||||
@ -918,11 +918,18 @@ void main_impl(int argc, char** argv)
|
||||
|
||||
// If you are using metadata names, set the connection's metadata_mode
|
||||
conn.set_meta_mode(metadata_mode::full);
|
||||
conn.query("SELECT 1 AS my_field", result);
|
||||
conn.execute("SELECT 1 AS my_field", result);
|
||||
colname = result.meta()[0].column_name();
|
||||
ASSERT(colname == "my_field");
|
||||
//]
|
||||
}
|
||||
{
|
||||
//[charsets_set_names
|
||||
results result;
|
||||
conn.execute("SET NAMES utf8mb4", result);
|
||||
// Further operations can assume utf8mb4 as conn's charset
|
||||
//]
|
||||
}
|
||||
|
||||
// Close
|
||||
conn.close();
|
||||
|
@ -123,9 +123,9 @@ void main_impl(int argc, char** argv)
|
||||
conn.connect(*endpoints.begin(), params);
|
||||
|
||||
// The executed commands may generate a lot of output, so we're going to
|
||||
// use multi-function operations (i.e. start_query) to read it in batches.
|
||||
// use multi-function operations (i.e. start_execution) to read it in batches.
|
||||
boost::mysql::execution_state st;
|
||||
conn.start_query(script_contents, st);
|
||||
conn.start_execution(script_contents, st);
|
||||
|
||||
// The main read loop. Each executed command will yield a resultset.
|
||||
// st.comoplete() returns true once all resultsets have been read.
|
||||
|
@ -109,7 +109,7 @@ void main_impl(int argc, char** argv)
|
||||
// We can now use the connection as we would normally do.
|
||||
const char* sql = "SELECT first_name, last_name, salary FROM employee";
|
||||
boost::mysql::results result;
|
||||
conn.query(sql, result);
|
||||
conn.execute(sql, result);
|
||||
|
||||
for (auto employee : result.rows())
|
||||
{
|
||||
|
@ -273,7 +273,7 @@ struct visitor
|
||||
auto stmt = conn.prepare_statement("CALL get_products(?)");
|
||||
|
||||
boost::mysql::results result;
|
||||
conn.execute_statement(stmt, std::make_tuple(args.search), result);
|
||||
conn.execute(stmt.bind(args.search), result);
|
||||
auto products = result.front();
|
||||
std::cout << "Your search returned the following products:\n";
|
||||
for (auto product : products.rows())
|
||||
@ -289,9 +289,9 @@ struct visitor
|
||||
// create-order: creates a new order
|
||||
void operator()(const create_order_args&) const
|
||||
{
|
||||
// Since create_order doesn't have user-supplied params, we can use query()
|
||||
// Since create_order doesn't have user-supplied params, we can use a text query
|
||||
boost::mysql::results result;
|
||||
conn.query("CALL create_order()", result);
|
||||
conn.execute("CALL create_order()", result);
|
||||
|
||||
// Print the result to stdout. create_order() returns a resultset for
|
||||
// the newly created order, with only 1 row.
|
||||
@ -307,12 +307,12 @@ struct visitor
|
||||
|
||||
// Execute the statement
|
||||
boost::mysql::results result;
|
||||
conn.execute_statement(stmt, std::make_tuple(args.order_id), result);
|
||||
conn.execute(stmt.bind(args.order_id), result);
|
||||
|
||||
// Print the result to stdout. get_order() returns a resultset for
|
||||
// the retrieved order and another for the line items. If the order can't
|
||||
// be found, get_order() raises an error using SIGNAL, which will make
|
||||
// execute_statement() fail with an exception.
|
||||
// execute() fail with an exception.
|
||||
std::cout << "Retrieved order\n";
|
||||
print_order_with_items(result.at(0), result.at(1));
|
||||
}
|
||||
@ -320,9 +320,9 @@ struct visitor
|
||||
// get-orders: lists all orders
|
||||
void operator()(const get_orders_args&) const
|
||||
{
|
||||
// Since get_orders doesn't have user-supplied params, we can use query()
|
||||
// Since get_orders doesn't have user-supplied params, we can use a text query
|
||||
boost::mysql::results result;
|
||||
conn.query("CALL get_orders()", result);
|
||||
conn.execute("CALL get_orders()", result);
|
||||
|
||||
// Print results to stdout. get_orders() succeeds even if no order is found.
|
||||
// get_orders() only lists orders, not line items.
|
||||
@ -351,11 +351,7 @@ struct visitor
|
||||
// We still have to pass a value to the 4th argument, even if it's an OUT parameter.
|
||||
// The value will be ignored, so we can pass nullptr.
|
||||
boost::mysql::results result;
|
||||
conn.execute_statement(
|
||||
stmt,
|
||||
std::make_tuple(args.order_id, args.product_id, args.quantity, nullptr),
|
||||
result
|
||||
);
|
||||
conn.execute(stmt.bind(args.order_id, args.product_id, args.quantity, nullptr), result);
|
||||
|
||||
// We can use results::out_params() to access the extra resultset containing
|
||||
// the OUT parameter
|
||||
@ -374,7 +370,7 @@ struct visitor
|
||||
|
||||
// Run the procedure
|
||||
boost::mysql::results result;
|
||||
conn.execute_statement(stmt, std::make_tuple(args.line_item_id), result);
|
||||
conn.execute(stmt.bind(args.line_item_id), result);
|
||||
|
||||
// Print results to stdout
|
||||
std::cout << "Removed line item from order\n";
|
||||
@ -390,7 +386,7 @@ struct visitor
|
||||
|
||||
// Execute the statement
|
||||
boost::mysql::results result;
|
||||
conn.execute_statement(stmt, std::make_tuple(args.order_id, nullptr), result);
|
||||
conn.execute(stmt.bind(args.order_id, nullptr), result);
|
||||
|
||||
// We can use results::out_params() to access the extra resultset containing
|
||||
// the OUT parameter
|
||||
@ -409,7 +405,7 @@ struct visitor
|
||||
|
||||
// Execute the statement
|
||||
boost::mysql::results result;
|
||||
conn.execute_statement(stmt, std::make_tuple(args.order_id), result);
|
||||
conn.execute(stmt.bind(args.order_id), result);
|
||||
|
||||
// Print the results to stdout
|
||||
std::cout << "Completed order\n";
|
||||
|
@ -83,14 +83,14 @@ void main_impl(int argc, char** argv)
|
||||
conn.connect(*endpoints.begin(), params);
|
||||
|
||||
/**
|
||||
* To issue a SQL query to the database server, use tcp_ssl_connection::query, which takes
|
||||
* the SQL to be executed as parameter and returns a results object by lvalue reference.
|
||||
* Resultset objects contain the retrieved rows, among other info.
|
||||
* We will get all employees working for 'High Growth Startup'.
|
||||
* To issue a SQL query to the database server, use tcp_ssl_connection::execute, passing
|
||||
* a string with the SQL to be executed as first parameter. execute returns a results object by lvalue
|
||||
* reference. Resultset objects contain the retrieved rows, among other info. We will get all employees
|
||||
* working for 'High Growth Startup'.
|
||||
*/
|
||||
const char* sql = "SELECT first_name, last_name, salary FROM employee WHERE company_id = 'HGS'";
|
||||
boost::mysql::results result;
|
||||
conn.query(sql, result);
|
||||
conn.execute(sql, result);
|
||||
|
||||
// We can access the rows using results::rows
|
||||
for (boost::mysql::row_view employee : result.rows())
|
||||
@ -101,11 +101,11 @@ void main_impl(int argc, char** argv)
|
||||
// We can issue any SQL statement, not only SELECTs. In this case, the returned
|
||||
// results will have no fields and no rows
|
||||
sql = "UPDATE employee SET salary = 10000 WHERE first_name = 'Underpaid'";
|
||||
conn.query(sql, result);
|
||||
conn.execute(sql, result);
|
||||
ASSERT(result.rows().empty()); // UPDATEs don't retrieve rows
|
||||
|
||||
// Check we have updated our poor intern salary
|
||||
conn.query("SELECT salary FROM employee WHERE first_name = 'Underpaid'", result);
|
||||
conn.execute("SELECT salary FROM employee WHERE first_name = 'Underpaid'", result);
|
||||
double salary = result.rows().at(0).at(0).as_double();
|
||||
ASSERT(salary == 10000.0);
|
||||
|
||||
|
@ -135,9 +135,7 @@ boost::asio::awaitable<void> coro_main(
|
||||
// Execute the statement
|
||||
boost::mysql::results result;
|
||||
timer.expires_after(TIMEOUT);
|
||||
op_result = co_await (
|
||||
timer.async_wait() || conn.async_execute_statement(stmt, std::make_tuple(company_id), result, diag)
|
||||
);
|
||||
op_result = co_await (timer.async_wait() || conn.async_execute(stmt.bind(company_id), result, diag));
|
||||
check_error(op_result, diag);
|
||||
|
||||
// Print all the obtained rows
|
||||
|
@ -64,7 +64,7 @@ void main_impl(int argc, char** argv)
|
||||
// Issue the SQL query to the server
|
||||
const char* sql = "SELECT 'Hello world!'";
|
||||
boost::mysql::results result;
|
||||
conn.query(sql, result);
|
||||
conn.execute(sql, result);
|
||||
//]
|
||||
|
||||
//[tutorial_results
|
||||
|
@ -78,7 +78,7 @@ void main_impl(int argc, char** argv)
|
||||
|
||||
// Execute the statement
|
||||
boost::mysql::results result;
|
||||
conn.execute_statement(stmt, std::make_tuple(company_id), result);
|
||||
conn.execute(stmt.bind(company_id), result);
|
||||
|
||||
// Print employees
|
||||
for (boost::mysql::row_view employee : result.rows())
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <boost/mysql/string_view.hpp>
|
||||
|
||||
#include <boost/mysql/detail/auxiliar/access_fwd.hpp>
|
||||
#include <boost/mysql/detail/auxiliar/execution_request.hpp>
|
||||
#include <boost/mysql/detail/auxiliar/field_type_traits.hpp>
|
||||
#include <boost/mysql/detail/auxiliar/rebind_executor.hpp>
|
||||
#include <boost/mysql/detail/channel/channel.hpp>
|
||||
@ -307,7 +308,152 @@ public:
|
||||
);
|
||||
|
||||
/**
|
||||
* \brief Executes a SQL text query.
|
||||
* \brief Executes a text query or prepared statement.
|
||||
* \details
|
||||
* Sends `req` to the server for execution and reads the response into `result`.
|
||||
* `req` should may be either a type convertible to \ref string_view containing valid SQL
|
||||
* or a bound prepared statement, obtained by calling \ref statement::bind.
|
||||
* If a string, it must be encoded using the connection's character set.
|
||||
* Any string parameters provided to \ref statement::bind should also be encoded
|
||||
* using the connection's character set.
|
||||
* \n
|
||||
* After this operation completes successfully, `result.has_value() == true`.
|
||||
* \n
|
||||
* Metadata in `result` will be populated according to `this->meta_mode()`.
|
||||
*/
|
||||
template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest>
|
||||
void execute(const ExecutionRequest& req, results& result, error_code&, diagnostics&);
|
||||
|
||||
/// \copydoc execute
|
||||
template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest>
|
||||
void execute(const ExecutionRequest& req, results& result);
|
||||
|
||||
/**
|
||||
* \copydoc execute
|
||||
* \par Object lifetimes
|
||||
* If `CompletionToken` is a deferred completion token (e.g. `use_awaitable`), the caller is
|
||||
* responsible for managing `req`'s validity following these rules:
|
||||
* \n
|
||||
* \li If `req` is `string_view`, the string pointed to by `req`
|
||||
* must be kept alive by the caller until the operation is initiated.
|
||||
* \li If `req` is a \ref bound_statement_tuple, and any of the parameters is a reference
|
||||
* type (like `string_view`), the caller must keep the values pointed by these references alive
|
||||
* until the operation is initiated.
|
||||
* \li If `req` is a \ref bound_statement_iterator_range, the caller must keep objects in
|
||||
* the iterator range passed to \ref statement::bind alive until the operation is initiated.
|
||||
*
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*/
|
||||
template <
|
||||
BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_execute(
|
||||
ExecutionRequest&& req,
|
||||
results& result,
|
||||
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
|
||||
)
|
||||
{
|
||||
return async_execute(
|
||||
std::forward<ExecutionRequest>(req),
|
||||
result,
|
||||
shared_diag(),
|
||||
std::forward<CompletionToken>(token)
|
||||
);
|
||||
}
|
||||
|
||||
/// \copydoc async_execute
|
||||
template <
|
||||
BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_execute(
|
||||
ExecutionRequest&& req,
|
||||
results& result,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
|
||||
);
|
||||
|
||||
/**
|
||||
* \brief Starts a SQL execution as a multi-function operation.
|
||||
* \details
|
||||
* Writes the execution request and reads the initial server response and the column
|
||||
* metadata, but not the generated rows or subsequent resultsets, if any.
|
||||
* After this operation completes, `st` will have
|
||||
* \ref execution_state::meta populated.
|
||||
* Metadata will be populated according to `this->meta_mode()`.
|
||||
* \n
|
||||
* If the operation generated any rows or more than one resultset, these <b>must</b> be read (by using
|
||||
* \ref read_some_rows and \ref read_resultset_head) before engaging in any further network operation.
|
||||
* Otherwise, the results are undefined.
|
||||
* \n
|
||||
* req may be either a type convertible to \ref string_view containing valid SQL
|
||||
* or a bound prepared statement, obtained by calling \ref statement::bind.
|
||||
* If a string, it must be encoded using the connection's character set.
|
||||
* Any string parameters provided to \ref statement::bind should also be encoded
|
||||
* using the connection's character set.
|
||||
*/
|
||||
template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest>
|
||||
void start_execution(const ExecutionRequest& req, execution_state& st, error_code&, diagnostics&);
|
||||
|
||||
/// \copydoc start_execution
|
||||
template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest>
|
||||
void start_execution(const ExecutionRequest& req, execution_state& st);
|
||||
|
||||
/**
|
||||
* \copydoc start_execution
|
||||
* \par Object lifetimes
|
||||
* If `CompletionToken` is a deferred completion token (e.g. `use_awaitable`), the caller is
|
||||
* responsible for managing `req`'s validity following these rules:
|
||||
* \n
|
||||
* \li If `req` is `string_view`, the string pointed to by `req`
|
||||
* must be kept alive by the caller until the operation is initiated.
|
||||
* \li If `req` is a \ref bound_statement_tuple, and any of the parameters is a reference
|
||||
* type (like `string_view`), the caller must keep the values pointed by these references alive
|
||||
* until the operation is initiated.
|
||||
* \li If `req` is a \ref bound_statement_iterator_range, the caller must keep objects in
|
||||
* the iterator range passed to \ref statement::bind alive until the operation is initiated.
|
||||
*
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*/
|
||||
template <
|
||||
BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_start_execution(
|
||||
ExecutionRequest&& req,
|
||||
execution_state& st,
|
||||
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
|
||||
)
|
||||
{
|
||||
return async_start_execution(
|
||||
std::forward<ExecutionRequest>(req),
|
||||
st,
|
||||
shared_diag(),
|
||||
std::forward<CompletionToken>(token)
|
||||
);
|
||||
}
|
||||
|
||||
/// \copydoc async_start_execution
|
||||
template <
|
||||
BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_start_execution(
|
||||
ExecutionRequest&& req,
|
||||
execution_state& st,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
|
||||
);
|
||||
|
||||
/**
|
||||
* \brief (Deprecated) Executes a SQL text query.
|
||||
* \details
|
||||
* Sends `query_string` to the server for execution and reads the response into `result`.
|
||||
* query_string should be encoded using the connection's character set.
|
||||
@ -320,6 +466,10 @@ public:
|
||||
* If you compose `query_string` by concatenating strings manually, <b>your code is
|
||||
* vulnerable to SQL injection attacks</b>. If your query contains patameters unknown at
|
||||
* compile time, use prepared statements instead of this function.
|
||||
*
|
||||
* \par Deprecation notice
|
||||
* This function is only provided for backwards-compatibility. For new code, please
|
||||
* use \ref execute or \ref async_execute instead.
|
||||
*/
|
||||
void query(string_view query_string, results& result, error_code&, diagnostics&);
|
||||
|
||||
@ -361,7 +511,7 @@ public:
|
||||
);
|
||||
|
||||
/**
|
||||
* \brief Starts a text query as a multi-function operation.
|
||||
* \brief (Deprecated) Starts a text query as a multi-function operation.
|
||||
* \details
|
||||
* Writes the query request and reads the initial server response and the column
|
||||
* metadata, but not the generated rows or subsequent resultsets, if any.
|
||||
@ -374,6 +524,10 @@ public:
|
||||
* Otherwise, the results are undefined.
|
||||
* \n
|
||||
* `query_string` should be encoded using the connection's character set.
|
||||
*
|
||||
* \par Deprecation notice
|
||||
* This function is only provided for backwards-compatibility. For new code, please
|
||||
* use \ref start_execution or \ref async_start_execution instead.
|
||||
*/
|
||||
void start_query(string_view query_string, execution_state& st, error_code&, diagnostics&);
|
||||
|
||||
@ -459,7 +613,7 @@ public:
|
||||
);
|
||||
|
||||
/**
|
||||
* \brief Executes a prepared statement.
|
||||
* \brief (Deprecated) Executes a prepared statement.
|
||||
* \details
|
||||
* Executes a statement with the given parameters and reads the response into `result`.
|
||||
* \n
|
||||
@ -473,6 +627,10 @@ public:
|
||||
* Metadata in `result` will be populated according to `conn.meta_mode()`, where `conn`
|
||||
* is the connection that prepared this statement.
|
||||
*
|
||||
* \par Deprecation notice
|
||||
* This function is only provided for backwards-compatibility. For new code, please
|
||||
* use \ref execute or \ref async_execute instead.
|
||||
*
|
||||
* \par Preconditions
|
||||
* `stmt.valid() == true`
|
||||
*/
|
||||
@ -542,7 +700,7 @@ public:
|
||||
);
|
||||
|
||||
/**
|
||||
* \brief Starts a statement execution as a multi-function operation.
|
||||
* \brief (Deprecated) Starts a statement execution as a multi-function operation.
|
||||
* \details
|
||||
* Writes the execute request and reads the initial server response and the column
|
||||
* metadata, but not the generated rows or subsequent resultsets, if any. After this operation completes,
|
||||
@ -556,6 +714,10 @@ public:
|
||||
* The statement actual parameters (`params`) are passed as a `std::tuple` of elements.
|
||||
* String parameters should be encoded using the connection's character set.
|
||||
*
|
||||
* \par Deprecation notice
|
||||
* This function is only provided for backwards-compatibility. For new code, please
|
||||
* use \ref start_execution or \ref async_start_execution instead.
|
||||
*
|
||||
* \par Preconditions
|
||||
* `stmt.valid() == true`
|
||||
*/
|
||||
@ -626,7 +788,7 @@ public:
|
||||
);
|
||||
|
||||
/**
|
||||
* \brief Starts a statement execution as a multi-function operation.
|
||||
* \brief (Deprecated) Starts a statement execution as a multi-function operation.
|
||||
* \details
|
||||
* Writes the execute request and reads the initial server response and the column
|
||||
* metadata, but not the generated rows or any subsequent resultsets, if any. After this operation
|
||||
@ -639,6 +801,10 @@ public:
|
||||
* The statement actual parameters are passed as an iterator range.
|
||||
* String parameters should be encoded using the connection's character set.
|
||||
*
|
||||
* \par Deprecation notice
|
||||
* This function is only provided for backwards-compatibility. For new code, please
|
||||
* use \ref start_execution or \ref async_start_execution instead.
|
||||
*
|
||||
* \par Preconditions
|
||||
* `stmt.valid() == true`
|
||||
*/
|
||||
|
68
include/boost/mysql/detail/auxiliar/execution_request.hpp
Normal file
68
include/boost/mysql/detail/auxiliar/execution_request.hpp
Normal file
@ -0,0 +1,68 @@
|
||||
//
|
||||
// Copyright (c) 2019-2023 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_DETAIL_AUXILIAR_EXECUTION_REQUEST_HPP
|
||||
#define BOOST_MYSQL_DETAIL_AUXILIAR_EXECUTION_REQUEST_HPP
|
||||
|
||||
#include <boost/mysql/statement.hpp>
|
||||
#include <boost/mysql/string_view.hpp>
|
||||
|
||||
#include <boost/mysql/detail/config.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
struct is_bound_statement_tuple : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_bound_statement_tuple<bound_statement_tuple<T>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_bound_statement_range : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_bound_statement_range<bound_statement_iterator_range<T>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_execution_request
|
||||
{
|
||||
using without_cvref = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||
static constexpr bool value = std::is_convertible<T, string_view>::value ||
|
||||
is_bound_statement_tuple<without_cvref>::value ||
|
||||
is_bound_statement_range<without_cvref>::value;
|
||||
};
|
||||
|
||||
#ifdef BOOST_MYSQL_HAS_CONCEPTS
|
||||
|
||||
template <class T>
|
||||
concept execution_request = is_execution_request<T>::value;
|
||||
|
||||
#define BOOST_MYSQL_EXECUTION_REQUEST ::boost::mysql::detail::execution_request
|
||||
|
||||
#else // BOOST_MYSQL_HAS_CONCEPTS
|
||||
|
||||
#define BOOST_MYSQL_EXECUTION_REQUEST class
|
||||
|
||||
#endif // BOOST_MYSQL_HAS_CONCEPTS
|
||||
|
||||
} // namespace detail
|
||||
} // namespace mysql
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
@ -5,8 +5,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_EXECUTE_HPP
|
||||
#define BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_EXECUTE_HPP
|
||||
#ifndef BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_EXECUTE_IMPL_HPP
|
||||
#define BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_EXECUTE_IMPL_HPP
|
||||
|
||||
#include <boost/mysql/diagnostics.hpp>
|
||||
#include <boost/mysql/error_code.hpp>
|
||||
@ -25,7 +25,7 @@ namespace detail {
|
||||
// before calling these
|
||||
|
||||
template <class Stream>
|
||||
void execute(
|
||||
void execute_impl(
|
||||
channel<Stream>& channel,
|
||||
resultset_encoding enc,
|
||||
results& output,
|
||||
@ -35,7 +35,7 @@ void execute(
|
||||
|
||||
template <class Stream, BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_execute(
|
||||
async_execute_impl(
|
||||
channel<Stream>& chan,
|
||||
resultset_encoding enc,
|
||||
results& output,
|
||||
@ -47,6 +47,6 @@ async_execute(
|
||||
} // namespace mysql
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/mysql/detail/network_algorithms/impl/execute.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/impl/execute_impl.hpp>
|
||||
|
||||
#endif
|
@ -10,9 +10,11 @@
|
||||
|
||||
#include <boost/mysql/diagnostics.hpp>
|
||||
#include <boost/mysql/error_code.hpp>
|
||||
#include <boost/mysql/execution_state.hpp>
|
||||
#include <boost/mysql/results.hpp>
|
||||
#include <boost/mysql/statement.hpp>
|
||||
|
||||
#include <boost/mysql/detail/auxiliar/execution_request.hpp>
|
||||
#include <boost/mysql/detail/auxiliar/field_type_traits.hpp>
|
||||
#include <boost/mysql/detail/channel/channel.hpp>
|
||||
|
||||
@ -22,43 +24,10 @@ namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
|
||||
template <class Stream>
|
||||
void query(channel<Stream>& channel, string_view query, results& output, error_code& err, diagnostics& diag);
|
||||
|
||||
template <class Stream, BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_query(
|
||||
channel<Stream>& chan,
|
||||
string_view query,
|
||||
results& output,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token
|
||||
);
|
||||
|
||||
template <class Stream>
|
||||
void start_query(
|
||||
template <class Stream, BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest>
|
||||
void execute(
|
||||
channel<Stream>& channel,
|
||||
string_view query,
|
||||
execution_state& output,
|
||||
error_code& err,
|
||||
diagnostics& diag
|
||||
);
|
||||
|
||||
template <class Stream, BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_start_query(
|
||||
channel<Stream>& chan,
|
||||
string_view query,
|
||||
execution_state& output,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token
|
||||
);
|
||||
|
||||
template <class Stream, BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple>
|
||||
void execute_statement(
|
||||
channel<Stream>& channel,
|
||||
const statement& stmt,
|
||||
const FieldLikeTuple& params,
|
||||
const ExecutionRequest& req,
|
||||
results& output,
|
||||
error_code& err,
|
||||
diagnostics& diag
|
||||
@ -66,64 +35,35 @@ void execute_statement(
|
||||
|
||||
template <
|
||||
class Stream,
|
||||
BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple,
|
||||
BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_execute_statement(
|
||||
async_execute(
|
||||
channel<Stream>& chan,
|
||||
const statement& stmt,
|
||||
FieldLikeTuple&& params,
|
||||
ExecutionRequest&& req,
|
||||
results& output,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token
|
||||
);
|
||||
|
||||
template <class Stream, BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator>
|
||||
void start_statement_execution(
|
||||
template <class Stream, BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest>
|
||||
void start_execution(
|
||||
channel<Stream>& channel,
|
||||
const statement& stmt,
|
||||
FieldViewFwdIterator params_first,
|
||||
FieldViewFwdIterator params_last,
|
||||
execution_state& output,
|
||||
const ExecutionRequest& req,
|
||||
execution_state& st,
|
||||
error_code& err,
|
||||
diagnostics& diag
|
||||
);
|
||||
|
||||
template <
|
||||
class Stream,
|
||||
BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator,
|
||||
BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_start_statement_execution(
|
||||
async_start_execution(
|
||||
channel<Stream>& chan,
|
||||
const statement& stmt,
|
||||
FieldViewFwdIterator params_first,
|
||||
FieldViewFwdIterator params_last,
|
||||
execution_state& output,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token
|
||||
);
|
||||
|
||||
template <class Stream, BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple>
|
||||
void start_statement_execution(
|
||||
channel<Stream>& channel,
|
||||
const statement& stmt,
|
||||
const FieldLikeTuple& params,
|
||||
execution_state& output,
|
||||
error_code& err,
|
||||
diagnostics& diag
|
||||
);
|
||||
|
||||
template <
|
||||
class Stream,
|
||||
BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_start_statement_execution(
|
||||
channel<Stream>& chan,
|
||||
const statement& stmt,
|
||||
FieldLikeTuple&& params,
|
||||
execution_state& output,
|
||||
ExecutionRequest&& req,
|
||||
execution_state& st,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token
|
||||
);
|
||||
|
@ -5,15 +5,14 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_IMPL_EXECUTE_HPP
|
||||
#define BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_IMPL_EXECUTE_HPP
|
||||
#ifndef BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_IMPL_EXECUTE_IMPL_HPP
|
||||
#define BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_IMPL_EXECUTE_IMPL_HPP
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/mysql/detail/network_algorithms/execute.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/execute_impl.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/helpers.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/read_resultset_head.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/start_execution.hpp>
|
||||
#include <boost/mysql/detail/protocol/deserialize_row.hpp>
|
||||
#include <boost/mysql/detail/protocol/execution_state_impl.hpp>
|
||||
|
||||
@ -24,14 +23,14 @@ namespace mysql {
|
||||
namespace detail {
|
||||
|
||||
template <class Stream>
|
||||
struct execute_op : boost::asio::coroutine
|
||||
struct execute_impl_op : boost::asio::coroutine
|
||||
{
|
||||
channel<Stream>& chan_;
|
||||
resultset_encoding enc_;
|
||||
execution_state_impl& st_;
|
||||
diagnostics& diag_;
|
||||
|
||||
execute_op(
|
||||
execute_impl_op(
|
||||
channel<Stream>& chan,
|
||||
resultset_encoding enc,
|
||||
execution_state_impl& st,
|
||||
@ -94,7 +93,7 @@ struct execute_op : boost::asio::coroutine
|
||||
} // namespace boost
|
||||
|
||||
template <class Stream>
|
||||
void boost::mysql::detail::execute(
|
||||
void boost::mysql::detail::execute_impl(
|
||||
channel<Stream>& channel,
|
||||
resultset_encoding enc,
|
||||
results& result,
|
||||
@ -141,7 +140,7 @@ void boost::mysql::detail::execute(
|
||||
|
||||
template <class Stream, 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::detail::async_execute(
|
||||
boost::mysql::detail::async_execute_impl(
|
||||
channel<Stream>& chan,
|
||||
resultset_encoding enc,
|
||||
results& result,
|
||||
@ -150,7 +149,7 @@ boost::mysql::detail::async_execute(
|
||||
)
|
||||
{
|
||||
return boost::asio::async_compose<CompletionToken, void(boost::mysql::error_code)>(
|
||||
execute_op<Stream>(chan, enc, results_access::get_impl(result), diag),
|
||||
execute_impl_op<Stream>(chan, enc, results_access::get_impl(result), diag),
|
||||
token,
|
||||
chan
|
||||
);
|
@ -9,9 +9,13 @@
|
||||
#define BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_IMPL_HIGH_LEVEL_EXECUTION_HPP
|
||||
|
||||
#pragma once
|
||||
#include <boost/mysql/detail/network_algorithms/execute.hpp>
|
||||
|
||||
#include <boost/mysql/execution_state.hpp>
|
||||
|
||||
#include <boost/mysql/detail/auxiliar/execution_request.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/execute_impl.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/high_level_execution.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/start_execution.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/start_execution_impl.hpp>
|
||||
#include <boost/mysql/detail/protocol/prepared_statement_messages.hpp>
|
||||
#include <boost/mysql/detail/protocol/query_messages.hpp>
|
||||
#include <boost/mysql/detail/protocol/resultset_encoding.hpp>
|
||||
@ -25,13 +29,33 @@ namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
|
||||
// Helpers
|
||||
inline void serialize_query_exec_req(channel_base& chan, string_view query)
|
||||
// Text queries
|
||||
template <
|
||||
typename T,
|
||||
typename EnableIf = typename std::enable_if<std::is_convertible<T, string_view>::value>::type>
|
||||
resultset_encoding get_encoding(const T&)
|
||||
{
|
||||
com_query_packet request{string_eof(query)};
|
||||
return resultset_encoding::text;
|
||||
}
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename EnableIf = typename std::enable_if<std::is_convertible<T, string_view>::value>::type>
|
||||
void serialize_execution_request(const T& req, channel_base& chan)
|
||||
{
|
||||
com_query_packet request{string_eof(string_view(req))};
|
||||
serialize_message(request, chan.current_capabilities(), chan.shared_buffer());
|
||||
}
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename EnableIf = typename std::enable_if<std::is_convertible<T, string_view>::value>::type>
|
||||
error_code check_client_errors(const T&)
|
||||
{
|
||||
return error_code();
|
||||
}
|
||||
|
||||
// Helpers for statements
|
||||
template <BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator>
|
||||
void serialize_stmt_exec_req(
|
||||
channel_base& chan,
|
||||
@ -63,32 +87,57 @@ std::array<field_view, sizeof...(T)> tuple_to_array(const std::tuple<T...>& t) n
|
||||
return tuple_to_array_impl(t, boost::mp11::make_index_sequence<sizeof...(T)>());
|
||||
}
|
||||
|
||||
template <BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple>
|
||||
void serialize_stmt_exec_req(channel_base& chan, const statement& stmt, const FieldLikeTuple& params)
|
||||
{
|
||||
auto arr = tuple_to_array(params);
|
||||
serialize_stmt_exec_req(chan, stmt, arr.begin(), arr.end());
|
||||
}
|
||||
|
||||
inline error_code check_num_params(const statement& stmt, std::size_t param_count)
|
||||
{
|
||||
return param_count == stmt.num_params() ? error_code() : make_error_code(client_errc::wrong_num_params);
|
||||
}
|
||||
|
||||
template <BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator>
|
||||
error_code check_num_params_it(
|
||||
const statement& stmt,
|
||||
FieldViewFwdIterator params_first,
|
||||
FieldViewFwdIterator params_last
|
||||
)
|
||||
// Statement, tuple
|
||||
template <BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple>
|
||||
resultset_encoding get_encoding(const bound_statement_tuple<FieldLikeTuple>&)
|
||||
{
|
||||
return check_num_params(stmt, std::distance(params_first, params_last));
|
||||
return resultset_encoding::binary;
|
||||
}
|
||||
|
||||
template <BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple>
|
||||
error_code check_num_params_tuple(const statement& stmt, const FieldLikeTuple&)
|
||||
void serialize_execution_request(const bound_statement_tuple<FieldLikeTuple>& req, channel_base& chan)
|
||||
{
|
||||
return check_num_params(stmt, std::tuple_size<FieldLikeTuple>::value);
|
||||
const auto& impl = statement_access::get_impl_tuple(req);
|
||||
auto arr = tuple_to_array(impl.params);
|
||||
serialize_stmt_exec_req(chan, impl.stmt, arr.begin(), arr.end());
|
||||
}
|
||||
|
||||
template <BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple>
|
||||
error_code check_client_errors(const bound_statement_tuple<FieldLikeTuple>& req)
|
||||
{
|
||||
return check_num_params(
|
||||
statement_access::get_impl_tuple(req).stmt,
|
||||
std::tuple_size<FieldLikeTuple>::value
|
||||
);
|
||||
}
|
||||
|
||||
// Statement, iterators
|
||||
template <BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator>
|
||||
resultset_encoding get_encoding(const bound_statement_iterator_range<FieldViewFwdIterator>&)
|
||||
{
|
||||
return resultset_encoding::binary;
|
||||
}
|
||||
|
||||
template <BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator>
|
||||
void serialize_execution_request(
|
||||
const bound_statement_iterator_range<FieldViewFwdIterator>& req,
|
||||
channel_base& chan
|
||||
)
|
||||
{
|
||||
const auto& impl = statement_access::get_impl_range(req);
|
||||
serialize_stmt_exec_req(chan, impl.stmt, impl.first, impl.last);
|
||||
}
|
||||
|
||||
template <BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator>
|
||||
error_code check_client_errors(const bound_statement_iterator_range<FieldViewFwdIterator>& req)
|
||||
{
|
||||
const auto& impl = statement_access::get_impl_range(req);
|
||||
return check_num_params(impl.stmt, std::distance(impl.first, impl.last));
|
||||
}
|
||||
|
||||
template <class Stream, class Handler>
|
||||
@ -101,51 +150,18 @@ void fast_fail(channel<Stream>& chan, Handler&& handler, error_code ec)
|
||||
}
|
||||
|
||||
// Async initiations
|
||||
struct initiate_query
|
||||
struct initiate_execute
|
||||
{
|
||||
template <class Handler, class Stream>
|
||||
template <class Handler, BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest, class Stream>
|
||||
void operator()(
|
||||
Handler&& handler,
|
||||
std::reference_wrapper<channel<Stream>> chan,
|
||||
string_view query,
|
||||
const ExecutionRequest& req,
|
||||
results& result,
|
||||
diagnostics& diag
|
||||
)
|
||||
{
|
||||
serialize_query_exec_req(chan, query);
|
||||
async_execute(chan.get(), resultset_encoding::text, result, diag, std::forward<Handler>(handler));
|
||||
}
|
||||
};
|
||||
|
||||
struct initiate_start_query
|
||||
{
|
||||
template <class Handler, class Stream>
|
||||
void operator()(
|
||||
Handler&& handler,
|
||||
std::reference_wrapper<channel<Stream>> chan,
|
||||
string_view query,
|
||||
execution_state& st,
|
||||
diagnostics& diag
|
||||
)
|
||||
{
|
||||
serialize_query_exec_req(chan, query);
|
||||
async_start_execution(chan.get(), resultset_encoding::text, st, diag, std::forward<Handler>(handler));
|
||||
}
|
||||
};
|
||||
|
||||
struct initiate_execute_statement
|
||||
{
|
||||
template <class Handler, class Stream, BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple>
|
||||
void operator()(
|
||||
Handler&& handler,
|
||||
std::reference_wrapper<channel<Stream>> chan,
|
||||
const statement& stmt,
|
||||
const FieldLikeTuple& params,
|
||||
results& result,
|
||||
diagnostics& diag
|
||||
)
|
||||
{
|
||||
auto ec = check_num_params_tuple(stmt, params);
|
||||
auto ec = check_client_errors(req);
|
||||
if (ec)
|
||||
{
|
||||
diag.clear();
|
||||
@ -153,31 +169,24 @@ struct initiate_execute_statement
|
||||
}
|
||||
else
|
||||
{
|
||||
serialize_stmt_exec_req(chan, stmt, params);
|
||||
async_execute(
|
||||
chan.get(),
|
||||
resultset_encoding::binary,
|
||||
result,
|
||||
diag,
|
||||
std::forward<Handler>(handler)
|
||||
);
|
||||
serialize_execution_request(req, chan);
|
||||
async_execute_impl(chan.get(), get_encoding(req), result, diag, std::forward<Handler>(handler));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct initiate_start_statement_execution
|
||||
struct initiate_start_execution
|
||||
{
|
||||
template <class Handler, class Stream, BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple>
|
||||
template <class Handler, BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest, class Stream>
|
||||
void operator()(
|
||||
Handler&& handler,
|
||||
std::reference_wrapper<channel<Stream>> chan,
|
||||
const statement& stmt,
|
||||
const FieldLikeTuple& params,
|
||||
const ExecutionRequest& req,
|
||||
execution_state& st,
|
||||
diagnostics& diag
|
||||
)
|
||||
{
|
||||
auto ec = check_num_params_tuple(stmt, params);
|
||||
auto ec = check_client_errors(req);
|
||||
if (ec)
|
||||
{
|
||||
diag.clear();
|
||||
@ -185,40 +194,10 @@ struct initiate_start_statement_execution
|
||||
}
|
||||
else
|
||||
{
|
||||
serialize_stmt_exec_req(chan, stmt, params);
|
||||
async_start_execution(
|
||||
serialize_execution_request(req, chan);
|
||||
async_start_execution_impl(
|
||||
chan.get(),
|
||||
resultset_encoding::binary,
|
||||
st,
|
||||
diag,
|
||||
std::forward<Handler>(handler)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Handler, class Stream, BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FwdIt>
|
||||
void operator()(
|
||||
Handler&& handler,
|
||||
std::reference_wrapper<channel<Stream>> chan,
|
||||
const statement& stmt,
|
||||
FwdIt first,
|
||||
FwdIt last,
|
||||
execution_state& st,
|
||||
diagnostics& diag
|
||||
)
|
||||
{
|
||||
auto ec = check_num_params_it(stmt, first, last);
|
||||
if (ec)
|
||||
{
|
||||
diag.clear();
|
||||
fast_fail(chan.get(), std::forward<Handler>(handler), ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
serialize_stmt_exec_req(chan, stmt, first, last);
|
||||
async_start_execution(
|
||||
chan.get(),
|
||||
resultset_encoding::binary,
|
||||
get_encoding(req),
|
||||
st,
|
||||
diag,
|
||||
std::forward<Handler>(handler)
|
||||
@ -231,199 +210,81 @@ struct initiate_start_statement_execution
|
||||
} // namespace mysql
|
||||
} // namespace boost
|
||||
|
||||
template <class Stream>
|
||||
void boost::mysql::detail::query(
|
||||
template <class Stream, BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest>
|
||||
void boost::mysql::detail::execute(
|
||||
channel<Stream>& channel,
|
||||
string_view query,
|
||||
const ExecutionRequest& req,
|
||||
results& result,
|
||||
error_code& err,
|
||||
diagnostics& diag
|
||||
)
|
||||
{
|
||||
serialize_query_exec_req(channel, query);
|
||||
execute(channel, resultset_encoding::text, result, err, diag);
|
||||
err = check_client_errors(req);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
serialize_execution_request(req, channel);
|
||||
execute_impl(channel, get_encoding(req), result, err, diag);
|
||||
}
|
||||
|
||||
template <class Stream, BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken>
|
||||
template <
|
||||
class Stream,
|
||||
BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
|
||||
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::detail::async_query(
|
||||
boost::mysql::detail::async_execute(
|
||||
channel<Stream>& chan,
|
||||
string_view query,
|
||||
ExecutionRequest&& req,
|
||||
results& result,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
return boost::asio::async_initiate<CompletionToken, void(boost::mysql::error_code)>(
|
||||
initiate_query(),
|
||||
initiate_execute(),
|
||||
token,
|
||||
std::ref(chan),
|
||||
query,
|
||||
std::forward<ExecutionRequest>(req),
|
||||
std::ref(result),
|
||||
std::ref(diag)
|
||||
);
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
void boost::mysql::detail::start_query(
|
||||
template <class Stream, BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest>
|
||||
void boost::mysql::detail::start_execution(
|
||||
channel<Stream>& channel,
|
||||
string_view query,
|
||||
const ExecutionRequest& req,
|
||||
execution_state& st,
|
||||
error_code& err,
|
||||
diagnostics& diag
|
||||
)
|
||||
{
|
||||
serialize_query_exec_req(channel, query);
|
||||
start_execution(channel, resultset_encoding::text, st, err, diag);
|
||||
}
|
||||
|
||||
template <class Stream, 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::detail::async_start_query(
|
||||
channel<Stream>& chan,
|
||||
string_view query,
|
||||
execution_state& st,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
return boost::asio::async_initiate<CompletionToken, void(boost::mysql::error_code)>(
|
||||
initiate_start_query(),
|
||||
token,
|
||||
std::ref(chan),
|
||||
query,
|
||||
std::ref(st),
|
||||
std::ref(diag)
|
||||
);
|
||||
}
|
||||
|
||||
template <class Stream, BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple>
|
||||
void boost::mysql::detail::execute_statement(
|
||||
channel<Stream>& channel,
|
||||
const statement& stmt,
|
||||
const FieldLikeTuple& params,
|
||||
results& result,
|
||||
error_code& err,
|
||||
diagnostics& diag
|
||||
)
|
||||
{
|
||||
err = check_num_params_tuple(stmt, params);
|
||||
err = check_client_errors(req);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
serialize_stmt_exec_req(channel, stmt, params);
|
||||
execute(channel, resultset_encoding::binary, result, err, diag);
|
||||
serialize_execution_request(req, channel);
|
||||
start_execution_impl(channel, get_encoding(req), st, err, diag);
|
||||
}
|
||||
|
||||
template <
|
||||
class Stream,
|
||||
BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple,
|
||||
BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
|
||||
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::detail::async_execute_statement(
|
||||
boost::mysql::detail::async_start_execution(
|
||||
channel<Stream>& chan,
|
||||
const statement& stmt,
|
||||
FieldLikeTuple&& params,
|
||||
results& result,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
return boost::asio::async_initiate<CompletionToken, void(boost::mysql::error_code)>(
|
||||
initiate_execute_statement(),
|
||||
token,
|
||||
std::ref(chan),
|
||||
stmt,
|
||||
std::forward<FieldLikeTuple>(params),
|
||||
std::ref(result),
|
||||
std::ref(diag)
|
||||
);
|
||||
}
|
||||
|
||||
template <class Stream, BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple>
|
||||
void boost::mysql::detail::start_statement_execution(
|
||||
channel<Stream>& channel,
|
||||
const statement& stmt,
|
||||
const FieldLikeTuple& params,
|
||||
execution_state& st,
|
||||
error_code& err,
|
||||
diagnostics& diag
|
||||
)
|
||||
{
|
||||
err = check_num_params_tuple(stmt, params);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
serialize_stmt_exec_req(channel, stmt, params);
|
||||
start_execution(channel, resultset_encoding::binary, st, err, diag);
|
||||
}
|
||||
|
||||
template <
|
||||
class Stream,
|
||||
BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple,
|
||||
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::detail::async_start_statement_execution(
|
||||
channel<Stream>& chan,
|
||||
const statement& stmt,
|
||||
FieldLikeTuple&& params,
|
||||
execution_state& output,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
return boost::asio::async_initiate<CompletionToken, void(boost::mysql::error_code)>(
|
||||
initiate_start_statement_execution(),
|
||||
token,
|
||||
std::ref(chan),
|
||||
stmt,
|
||||
std::forward<FieldLikeTuple>(params),
|
||||
std::ref(output),
|
||||
std::ref(diag)
|
||||
);
|
||||
}
|
||||
|
||||
template <class Stream, BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator>
|
||||
void boost::mysql::detail::start_statement_execution(
|
||||
channel<Stream>& chan,
|
||||
const statement& stmt,
|
||||
FieldViewFwdIterator params_first,
|
||||
FieldViewFwdIterator params_last,
|
||||
execution_state& st,
|
||||
error_code& err,
|
||||
diagnostics& diag
|
||||
)
|
||||
{
|
||||
err = check_num_params_it(stmt, params_first, params_last);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
serialize_stmt_exec_req(chan, stmt, params_first, params_last);
|
||||
start_execution(chan, resultset_encoding::binary, st, err, diag);
|
||||
}
|
||||
|
||||
template <
|
||||
class Stream,
|
||||
BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator,
|
||||
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::detail::async_start_statement_execution(
|
||||
channel<Stream>& chan,
|
||||
const statement& stmt,
|
||||
FieldViewFwdIterator params_first,
|
||||
FieldViewFwdIterator params_last,
|
||||
ExecutionRequest&& req,
|
||||
execution_state& st,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
return boost::asio::async_initiate<CompletionToken, void(boost::mysql::error_code)>(
|
||||
initiate_start_statement_execution(),
|
||||
initiate_start_execution(),
|
||||
token,
|
||||
std::ref(chan),
|
||||
stmt,
|
||||
params_first,
|
||||
params_last,
|
||||
std::forward<ExecutionRequest>(req),
|
||||
std::ref(st),
|
||||
std::ref(diag)
|
||||
);
|
||||
|
@ -5,13 +5,13 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_IMPL_START_EXECUTION_HPP
|
||||
#define BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_IMPL_START_EXECUTION_HPP
|
||||
#ifndef BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_IMPL_START_EXECUTION_IMPL_HPP
|
||||
#define BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_IMPL_START_EXECUTION_IMPL_HPP
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/mysql/detail/network_algorithms/read_resultset_head.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/start_execution.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/start_execution_impl.hpp>
|
||||
#include <boost/mysql/detail/protocol/execution_state_impl.hpp>
|
||||
|
||||
#include <boost/asio/coroutine.hpp>
|
||||
@ -21,14 +21,14 @@ namespace mysql {
|
||||
namespace detail {
|
||||
|
||||
template <class Stream>
|
||||
struct start_execution_op : boost::asio::coroutine
|
||||
struct start_execution_impl_op : boost::asio::coroutine
|
||||
{
|
||||
channel<Stream>& chan_;
|
||||
resultset_encoding enc_;
|
||||
execution_state_impl& st_;
|
||||
diagnostics& diag_;
|
||||
|
||||
start_execution_op(
|
||||
start_execution_impl_op(
|
||||
channel<Stream>& chan,
|
||||
resultset_encoding enc,
|
||||
execution_state_impl& st,
|
||||
@ -73,7 +73,7 @@ struct start_execution_op : boost::asio::coroutine
|
||||
} // namespace boost
|
||||
|
||||
template <class Stream>
|
||||
void boost::mysql::detail::start_execution(
|
||||
void boost::mysql::detail::start_execution_impl(
|
||||
channel<Stream>& channel,
|
||||
resultset_encoding enc,
|
||||
execution_state& st,
|
||||
@ -100,7 +100,7 @@ void boost::mysql::detail::start_execution(
|
||||
|
||||
template <class Stream, 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::detail::async_start_execution(
|
||||
boost::mysql::detail::async_start_execution_impl(
|
||||
channel<Stream>& channel,
|
||||
resultset_encoding enc,
|
||||
execution_state& st,
|
||||
@ -109,7 +109,7 @@ boost::mysql::detail::async_start_execution(
|
||||
)
|
||||
{
|
||||
return boost::asio::async_compose<CompletionToken, void(error_code)>(
|
||||
start_execution_op<Stream>(channel, enc, execution_state_access::get_impl(st), diag),
|
||||
start_execution_impl_op<Stream>(channel, enc, execution_state_access::get_impl(st), diag),
|
||||
token,
|
||||
channel
|
||||
);
|
@ -5,8 +5,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_START_EXECUTION_HPP
|
||||
#define BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_START_EXECUTION_HPP
|
||||
#ifndef BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_START_EXECUTION_IMPL_HPP
|
||||
#define BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_START_EXECUTION_IMPL_HPP
|
||||
|
||||
#include <boost/mysql/diagnostics.hpp>
|
||||
#include <boost/mysql/error_code.hpp>
|
||||
@ -25,7 +25,7 @@ namespace detail {
|
||||
// before calling these
|
||||
|
||||
template <class Stream>
|
||||
void start_execution(
|
||||
void start_execution_impl(
|
||||
channel<Stream>& channel,
|
||||
resultset_encoding encoding,
|
||||
execution_state& st,
|
||||
@ -35,7 +35,7 @@ void start_execution(
|
||||
|
||||
template <class Stream, BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_start_execution(
|
||||
async_start_execution_impl(
|
||||
channel<Stream>& chan,
|
||||
resultset_encoding encoding,
|
||||
execution_state& st,
|
||||
@ -47,6 +47,6 @@ async_start_execution(
|
||||
} // namespace mysql
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/mysql/detail/network_algorithms/impl/start_execution.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/impl/start_execution_impl.hpp>
|
||||
|
||||
#endif /* INCLUDE_MYSQL_IMPL_NETWORK_ALGORITHMS_READ_RESULTSET_HEAD_HPP_ */
|
@ -82,7 +82,7 @@ inline std::size_t boost::mysql::detail::serialization_traits<
|
||||
res += get_size(ctx, com_stmt_execute_param_meta_packet{}) * num_params;
|
||||
for (auto it = value.params_begin; it != value.params_end; ++it)
|
||||
{
|
||||
res += get_size(ctx, *it);
|
||||
res += get_size(ctx, field_view(*it));
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,7 +113,8 @@ inline void boost::mysql::detail::serialization_traits<
|
||||
std::memset(ctx.first(), 0, traits.byte_count()); // Initialize to zeroes
|
||||
for (auto it = input.params_begin; it != input.params_end; ++it, ++i)
|
||||
{
|
||||
if (it->is_null())
|
||||
field_view fv(*it);
|
||||
if (fv.is_null())
|
||||
{
|
||||
traits.set_null(ctx.first(), i);
|
||||
}
|
||||
@ -135,7 +136,7 @@ inline void boost::mysql::detail::serialization_traits<
|
||||
// actual values
|
||||
for (auto it = input.params_begin; it != input.params_end; ++it)
|
||||
{
|
||||
serialize(ctx, *it);
|
||||
serialize(ctx, field_view(*it));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ public:
|
||||
/**
|
||||
* \brief Returns whether `*this` is in the initial state.
|
||||
* \details
|
||||
* Call `start_query`, `start_statement_execution` or their async countrparts to move
|
||||
* Call \ref connection::start_execution or \ref connection::async_start_execution to move
|
||||
* forward. No data is available in this state.
|
||||
*
|
||||
* \par Exception safety
|
||||
|
@ -50,7 +50,7 @@ public:
|
||||
* \param mode The \ref ssl_mode to use with this connection; ignored if
|
||||
* the connection's `Stream` does not support SSL.
|
||||
* \param multi_queries Whether to enable support for executing semicolon-separated
|
||||
* queries using \ref connection::query. Disabled by default.
|
||||
* queries using \ref connection::execute and \ref connection::start_execution. Disabled by default.
|
||||
*/
|
||||
handshake_params(
|
||||
string_view username,
|
||||
|
@ -113,14 +113,14 @@ void boost::mysql::connection<Stream>::start_query(
|
||||
)
|
||||
{
|
||||
detail::clear_errors(err, diag);
|
||||
detail::start_query(get_channel(), query_string, result, err, diag);
|
||||
detail::start_execution(get_channel(), query_string, result, err, diag);
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
void boost::mysql::connection<Stream>::start_query(string_view query_string, execution_state& result)
|
||||
{
|
||||
detail::error_block blk;
|
||||
detail::start_query(get_channel(), query_string, result, blk.err, blk.diag);
|
||||
detail::start_execution(get_channel(), query_string, result, blk.err, blk.diag);
|
||||
blk.check(BOOST_CURRENT_LOCATION);
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ boost::mysql::connection<Stream>::async_start_query(
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
return detail::async_start_query(
|
||||
return detail::async_start_execution(
|
||||
get_channel(),
|
||||
query_string,
|
||||
result,
|
||||
@ -152,14 +152,14 @@ void boost::mysql::connection<Stream>::query(
|
||||
)
|
||||
{
|
||||
detail::clear_errors(err, diag);
|
||||
detail::query(get_channel(), query_string, result, err, diag);
|
||||
detail::execute(get_channel(), query_string, result, err, diag);
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
void boost::mysql::connection<Stream>::query(string_view query_string, results& result)
|
||||
{
|
||||
detail::error_block blk;
|
||||
detail::query(get_channel(), query_string, result, blk.err, blk.diag);
|
||||
detail::execute(get_channel(), query_string, result, blk.err, blk.diag);
|
||||
blk.check(BOOST_CURRENT_LOCATION);
|
||||
}
|
||||
|
||||
@ -173,7 +173,7 @@ boost::mysql::connection<Stream>::async_query(
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
return detail::async_query(
|
||||
return detail::async_execute(
|
||||
get_channel(),
|
||||
query_string,
|
||||
result,
|
||||
@ -182,6 +182,92 @@ boost::mysql::connection<Stream>::async_query(
|
||||
);
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest>
|
||||
void boost::mysql::connection<Stream>::execute(
|
||||
const ExecutionRequest& req,
|
||||
results& result,
|
||||
error_code& err,
|
||||
diagnostics& diag
|
||||
)
|
||||
{
|
||||
detail::clear_errors(err, diag);
|
||||
detail::execute(get_channel(), req, result, err, diag);
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest>
|
||||
void boost::mysql::connection<Stream>::execute(const ExecutionRequest& req, results& result)
|
||||
{
|
||||
detail::error_block blk;
|
||||
detail::execute(get_channel(), req, result, blk.err, blk.diag);
|
||||
blk.check(BOOST_CURRENT_LOCATION);
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
template <
|
||||
BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
|
||||
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(
|
||||
ExecutionRequest&& req,
|
||||
results& result,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
return detail::async_execute(
|
||||
get_channel(),
|
||||
std::forward<ExecutionRequest>(req),
|
||||
result,
|
||||
diag,
|
||||
std::forward<CompletionToken>(token)
|
||||
);
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest>
|
||||
void boost::mysql::connection<Stream>::start_execution(
|
||||
const ExecutionRequest& req,
|
||||
execution_state& st,
|
||||
error_code& err,
|
||||
diagnostics& diag
|
||||
)
|
||||
{
|
||||
detail::clear_errors(err, diag);
|
||||
detail::start_execution(get_channel(), req, st, err, diag);
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest>
|
||||
void boost::mysql::connection<Stream>::start_execution(const ExecutionRequest& req, execution_state& st)
|
||||
{
|
||||
detail::error_block blk;
|
||||
detail::start_execution(get_channel(), req, st, blk.err, blk.diag);
|
||||
blk.check(BOOST_CURRENT_LOCATION);
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
template <
|
||||
BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
|
||||
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_start_execution(
|
||||
ExecutionRequest&& req,
|
||||
execution_state& st,
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
return detail::async_start_execution(
|
||||
get_channel(),
|
||||
std::forward<ExecutionRequest>(req),
|
||||
st,
|
||||
diag,
|
||||
std::forward<CompletionToken>(token)
|
||||
);
|
||||
}
|
||||
|
||||
// Prepare statement
|
||||
template <class Stream>
|
||||
boost::mysql::statement boost::mysql::connection<Stream>::prepare_statement(
|
||||
@ -228,7 +314,7 @@ void boost::mysql::connection<Stream>::execute_statement(
|
||||
)
|
||||
{
|
||||
detail::clear_errors(err, diag);
|
||||
detail::execute_statement(get_channel(), stmt, params, result, err, diag);
|
||||
detail::execute(get_channel(), stmt.bind(params), result, err, diag);
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
@ -240,7 +326,7 @@ void boost::mysql::connection<Stream>::execute_statement(
|
||||
)
|
||||
{
|
||||
detail::error_block blk;
|
||||
detail::execute_statement(get_channel(), stmt, params, result, blk.err, blk.diag);
|
||||
detail::execute(get_channel(), stmt.bind(params), result, blk.err, blk.diag);
|
||||
blk.check(BOOST_CURRENT_LOCATION);
|
||||
}
|
||||
|
||||
@ -258,10 +344,9 @@ boost::mysql::connection<Stream>::async_execute_statement(
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
return detail::async_execute_statement(
|
||||
return detail::async_execute(
|
||||
get_channel(),
|
||||
stmt,
|
||||
std::forward<FieldLikeTuple>(params),
|
||||
stmt.bind(std::forward<FieldLikeTuple>(params)),
|
||||
result,
|
||||
diag,
|
||||
std::forward<CompletionToken>(token)
|
||||
@ -279,7 +364,7 @@ void boost::mysql::connection<Stream>::start_statement_execution(
|
||||
)
|
||||
{
|
||||
detail::clear_errors(err, diag);
|
||||
detail::start_statement_execution(get_channel(), stmt, params, result, err, diag);
|
||||
detail::start_execution(get_channel(), stmt.bind(params), result, err, diag);
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
@ -291,7 +376,7 @@ void boost::mysql::connection<Stream>::start_statement_execution(
|
||||
)
|
||||
{
|
||||
detail::error_block blk;
|
||||
detail::start_statement_execution(get_channel(), stmt, params, result, blk.err, blk.diag);
|
||||
detail::start_execution(get_channel(), stmt.bind(params), result, blk.err, blk.diag);
|
||||
blk.check(BOOST_CURRENT_LOCATION);
|
||||
}
|
||||
|
||||
@ -309,10 +394,9 @@ boost::mysql::connection<Stream>::async_start_statement_execution(
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
return detail::async_start_statement_execution(
|
||||
return detail::async_start_execution(
|
||||
get_channel(),
|
||||
stmt,
|
||||
std::forward<FieldLikeTuple>(params),
|
||||
stmt.bind(std::forward<FieldLikeTuple>(params)),
|
||||
result,
|
||||
diag,
|
||||
std::forward<CompletionToken>(token)
|
||||
@ -332,7 +416,7 @@ void boost::mysql::connection<Stream>::start_statement_execution(
|
||||
)
|
||||
{
|
||||
detail::clear_errors(err, diag);
|
||||
detail::start_statement_execution(get_channel(), stmt, params_first, params_last, result, err, diag);
|
||||
detail::start_execution(get_channel(), stmt.bind(params_first, params_last), result, err, diag);
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
@ -345,15 +429,7 @@ void boost::mysql::connection<Stream>::start_statement_execution(
|
||||
)
|
||||
{
|
||||
detail::error_block blk;
|
||||
detail::start_statement_execution(
|
||||
get_channel(),
|
||||
stmt,
|
||||
params_first,
|
||||
params_last,
|
||||
result,
|
||||
blk.err,
|
||||
blk.diag
|
||||
);
|
||||
detail::start_execution(get_channel(), stmt.bind(params_first, params_last), result, blk.err, blk.diag);
|
||||
blk.check(BOOST_CURRENT_LOCATION);
|
||||
}
|
||||
|
||||
@ -371,11 +447,9 @@ boost::mysql::connection<Stream>::async_start_statement_execution(
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
return detail::async_start_statement_execution(
|
||||
return detail::async_start_execution(
|
||||
get_channel(),
|
||||
stmt,
|
||||
params_first,
|
||||
params_last,
|
||||
stmt.bind(params_first, params_last),
|
||||
result,
|
||||
diag,
|
||||
std::forward<CompletionToken>(token)
|
||||
|
@ -15,6 +15,70 @@
|
||||
#include <boost/mysql/detail/auxiliar/access_fwd.hpp>
|
||||
#include <boost/mysql/detail/protocol/prepared_statement_messages.hpp>
|
||||
|
||||
template <BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple>
|
||||
class boost::mysql::bound_statement_tuple
|
||||
{
|
||||
friend class statement;
|
||||
friend struct detail::statement_access;
|
||||
|
||||
struct impl
|
||||
{
|
||||
statement stmt;
|
||||
FieldLikeTuple params;
|
||||
} impl_;
|
||||
|
||||
template <typename TupleType>
|
||||
bound_statement_tuple(const statement& stmt, TupleType&& t) : impl_{stmt, std::forward<TupleType>(t)}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator>
|
||||
class boost::mysql::bound_statement_iterator_range
|
||||
{
|
||||
friend class statement;
|
||||
friend struct detail::statement_access;
|
||||
|
||||
struct impl
|
||||
{
|
||||
statement stmt;
|
||||
FieldViewFwdIterator first;
|
||||
FieldViewFwdIterator last;
|
||||
} impl_;
|
||||
|
||||
bound_statement_iterator_range(
|
||||
const statement& stmt,
|
||||
FieldViewFwdIterator first,
|
||||
FieldViewFwdIterator last
|
||||
)
|
||||
: impl_{stmt, first, last}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple, typename EnableIf>
|
||||
boost::mysql::bound_statement_tuple<typename std::decay<FieldLikeTuple>::type> boost::mysql::statement::bind(
|
||||
FieldLikeTuple&& args
|
||||
) const
|
||||
|
||||
{
|
||||
assert(valid());
|
||||
return bound_statement_tuple<typename std::decay<FieldLikeTuple>::type>(
|
||||
*this,
|
||||
std::forward<FieldLikeTuple>(args)
|
||||
);
|
||||
}
|
||||
|
||||
template <BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator, typename EnableIf>
|
||||
boost::mysql::bound_statement_iterator_range<FieldViewFwdIterator> boost::mysql::statement::bind(
|
||||
FieldViewFwdIterator first,
|
||||
FieldViewFwdIterator last
|
||||
) const
|
||||
{
|
||||
assert(valid());
|
||||
return bound_statement_iterator_range<FieldViewFwdIterator>(*this, first, last);
|
||||
}
|
||||
|
||||
struct boost::mysql::detail::statement_access
|
||||
{
|
||||
static void reset(statement& stmt, const detail::com_stmt_prepare_ok_packet& msg) noexcept
|
||||
@ -23,6 +87,22 @@ struct boost::mysql::detail::statement_access
|
||||
stmt.id_ = msg.statement_id;
|
||||
stmt.num_params_ = msg.num_params;
|
||||
}
|
||||
|
||||
template <BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple>
|
||||
static const typename bound_statement_tuple<FieldLikeTuple>::impl get_impl_tuple(
|
||||
const bound_statement_tuple<FieldLikeTuple>& obj
|
||||
)
|
||||
{
|
||||
return obj.impl_;
|
||||
}
|
||||
|
||||
template <BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator>
|
||||
static const typename bound_statement_iterator_range<FieldViewFwdIterator>::impl get_impl_range(
|
||||
const bound_statement_iterator_range<FieldViewFwdIterator>& obj
|
||||
)
|
||||
{
|
||||
return obj.impl_;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -123,8 +123,8 @@ public:
|
||||
/**
|
||||
* \brief Returns whether the object holds a valid result.
|
||||
* \details Having `this->has_value()` is a precondition to call all data accessors.
|
||||
* Objects populated by \ref connection::query, \ref connection::execute_statement or their async
|
||||
* counterparts are guaranteed to have `this->has_value() == true`.
|
||||
* Objects populated by \ref connection::execute and \ref connection::async_execute
|
||||
* are guaranteed to have `this->has_value() == true`.
|
||||
*
|
||||
* \par Exception safety
|
||||
* No-throw guarantee.
|
||||
|
@ -9,13 +9,34 @@
|
||||
#define BOOST_MYSQL_STATEMENT_HPP
|
||||
|
||||
#include <boost/mysql/detail/auxiliar/access_fwd.hpp>
|
||||
#include <boost/mysql/detail/auxiliar/field_type_traits.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
|
||||
/**
|
||||
* \brief A statement with bound parameters, represented as a `std::tuple`.
|
||||
* \details
|
||||
* This class satisfies `ExecutionRequest`. You can pass instances of this class to \ref connection::execute,
|
||||
* \ref connection::start_execution or their async counterparts.
|
||||
*/
|
||||
template <BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple>
|
||||
class bound_statement_tuple;
|
||||
|
||||
/**
|
||||
* \brief A statement with bound parameters, represented as an iterator range.
|
||||
* \details
|
||||
* This class satisfies `ExecutionRequest`. You can pass instances of this class to \ref connection::execute,
|
||||
* \ref connection::start_execution or their async counterparts.
|
||||
*/
|
||||
template <BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator>
|
||||
class bound_statement_iterator_range;
|
||||
|
||||
/**
|
||||
* \brief Represents a server-side prepared statement.
|
||||
* \details
|
||||
@ -82,6 +103,84 @@ public:
|
||||
return num_params_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Binds parameters to a statement.
|
||||
* \details
|
||||
* Creates an object that packages `*this` and the statement actual parameters `params`.
|
||||
* This object can be passed to \ref connection::execute, \ref connection::start_execution
|
||||
* and their async counterparts.
|
||||
* \n
|
||||
* The parameters are copied into a `std::tuple` by using `std::make_tuple`. This function
|
||||
* only participates in overload resolution if `std::make_tuple(FWD(args)...)` yields a
|
||||
* `FieldLikeTuple`. Equivalent to `this->bind(std::make_tuple(std::forward<T>(params)...))`.
|
||||
* \n
|
||||
* This function doesn't involve communication with the server.
|
||||
*
|
||||
* \par Preconditions
|
||||
* `this->valid() == true`
|
||||
* \n
|
||||
* \par Exception safety
|
||||
* Strong guarantee. Only throws if constructing any of the internal tuple elements throws.
|
||||
*/
|
||||
template <class... T>
|
||||
#ifdef BOOST_MYSQL_DOXYGEN
|
||||
bound_statement_tuple<std::tuple<__see_below__>>
|
||||
#else
|
||||
auto
|
||||
#endif
|
||||
bind(T&&... params) const->typename std::enable_if<
|
||||
detail::is_field_like_tuple<decltype(std::make_tuple(std::forward<T>(params)...))>::value,
|
||||
bound_statement_tuple<decltype(std::make_tuple(std::forward<T>(params)...))>>::type
|
||||
{
|
||||
return bind(std::make_tuple(std::forward<T>(params)...));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Binds parameters to a statement.
|
||||
* \details
|
||||
* Creates an object that packages `*this` and the statement actual parameters `params`.
|
||||
* This object can be passed to \ref connection::execute, \ref connection::start_execution
|
||||
* or their async counterparts.
|
||||
* \n
|
||||
* The `params` tuple is decay-copied into the returned object.
|
||||
* \n
|
||||
* This function doesn't involve communication with the server.
|
||||
*
|
||||
* \par Preconditions
|
||||
* `this->valid() == true`
|
||||
* \n
|
||||
* \par Exception safety
|
||||
* Strong guarantee. Only throws if the decay-copy of the tuple throws.
|
||||
*/
|
||||
template <
|
||||
BOOST_MYSQL_FIELD_LIKE_TUPLE FieldLikeTuple,
|
||||
typename EnableIf = detail::enable_if_field_like_tuple<FieldLikeTuple>>
|
||||
bound_statement_tuple<typename std::decay<FieldLikeTuple>::type> bind(FieldLikeTuple&& params) const;
|
||||
|
||||
/**
|
||||
* \brief Binds parameters to a statement (iterator range overload).
|
||||
* \details
|
||||
* Creates an object that packages `*this` and the statement actual parameters, represented
|
||||
* as the iterator range `[params_first, params_last)`.
|
||||
* This object can be passed to \ref connection::execute, \ref connection::start_execution
|
||||
* or their async counterparts.
|
||||
* \n
|
||||
* This function doesn't involve communication with the server.
|
||||
*
|
||||
* \par Preconditions
|
||||
* `this->valid() == true`
|
||||
* \n
|
||||
* \par Exception safety
|
||||
* Strong guarantee. Only throws if copy-constructing iterators throws.
|
||||
*/
|
||||
template <
|
||||
BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator,
|
||||
typename EnableIf = detail::enable_if_field_view_forward_iterator<FieldViewFwdIterator>>
|
||||
bound_statement_iterator_range<FieldViewFwdIterator> bind(
|
||||
FieldViewFwdIterator params_first,
|
||||
FieldViewFwdIterator params_last
|
||||
) const;
|
||||
|
||||
private:
|
||||
bool valid_{false};
|
||||
std::uint32_t id_{0};
|
||||
|
@ -31,7 +31,7 @@ BOOST_FIXTURE_TEST_CASE(query_empty_select, tcp_network_fixture)
|
||||
|
||||
// Issue query
|
||||
results result;
|
||||
conn.query("SELECT * FROM empty_table", result);
|
||||
conn.execute("SELECT * FROM empty_table", result);
|
||||
|
||||
// Verify results
|
||||
BOOST_TEST(result.size() == 1u);
|
||||
@ -49,7 +49,7 @@ BOOST_FIXTURE_TEST_CASE(query_empty_select_multifn, tcp_network_fixture)
|
||||
|
||||
// Issue query
|
||||
boost::mysql::execution_state st;
|
||||
conn.start_query("SELECT * FROM empty_table", st);
|
||||
conn.start_execution("SELECT * FROM empty_table", st);
|
||||
BOOST_TEST_REQUIRE(st.should_read_rows());
|
||||
validate_2fields_meta(st.meta(), "empty_table");
|
||||
|
||||
@ -69,7 +69,7 @@ BOOST_FIXTURE_TEST_CASE(query_insert, tcp_network_fixture)
|
||||
|
||||
// Issue query
|
||||
results result;
|
||||
conn.query("INSERT INTO inserts_table (field_varchar, field_date) VALUES ('v0', '2010-10-11')", result);
|
||||
conn.execute("INSERT INTO inserts_table (field_varchar, field_date) VALUES ('v0', '2010-10-11')", result);
|
||||
|
||||
// Verify results
|
||||
BOOST_TEST(result.size() == 1u);
|
||||
@ -81,7 +81,7 @@ BOOST_FIXTURE_TEST_CASE(query_insert, tcp_network_fixture)
|
||||
BOOST_TEST(result.info() == "");
|
||||
|
||||
// Verify insertion took place
|
||||
conn.query("SELECT COUNT(*) FROM inserts_table", result);
|
||||
conn.execute("SELECT COUNT(*) FROM inserts_table", result);
|
||||
BOOST_TEST(result.rows().at(0).at(0).as_int64() == 1);
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ BOOST_FIXTURE_TEST_CASE(query_update, tcp_network_fixture)
|
||||
|
||||
// Issue the query
|
||||
results result;
|
||||
conn.query("UPDATE updates_table SET field_int = field_int+10", result);
|
||||
conn.execute("UPDATE updates_table SET field_int = field_int+10", result);
|
||||
|
||||
// Validate results
|
||||
BOOST_TEST(result.size() == 1u);
|
||||
@ -104,7 +104,7 @@ BOOST_FIXTURE_TEST_CASE(query_update, tcp_network_fixture)
|
||||
BOOST_TEST(result.info() == "Rows matched: 3 Changed: 2 Warnings: 0");
|
||||
|
||||
// Validate it took effect
|
||||
conn.query("SELECT field_int FROM updates_table WHERE field_varchar = 'f0'", result);
|
||||
conn.execute("SELECT field_int FROM updates_table WHERE field_varchar = 'f0'", result);
|
||||
BOOST_TEST(result.rows().at(0).at(0).as_int64() == 52); // initial value was 42
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ BOOST_FIXTURE_TEST_CASE(query_delete, tcp_network_fixture)
|
||||
|
||||
// Issue the query
|
||||
results result;
|
||||
conn.query("DELETE FROM updates_table", result);
|
||||
conn.execute("DELETE FROM updates_table", result);
|
||||
|
||||
// Validate results
|
||||
BOOST_TEST(result.size() == 1u);
|
||||
@ -127,7 +127,7 @@ BOOST_FIXTURE_TEST_CASE(query_delete, tcp_network_fixture)
|
||||
BOOST_TEST(result.info() == "");
|
||||
|
||||
// Validate it took effect
|
||||
conn.query("SELECT COUNT(*) FROM updates_table", result);
|
||||
conn.execute("SELECT COUNT(*) FROM updates_table", result);
|
||||
BOOST_TEST(result.rows().at(0).at(0).as_int64() == 0);
|
||||
}
|
||||
|
||||
@ -142,7 +142,7 @@ BOOST_FIXTURE_TEST_CASE(statement_update, tcp_network_fixture)
|
||||
|
||||
// Execute it
|
||||
results result;
|
||||
conn.execute_statement(stmt, std::make_tuple(200, "f0"), result);
|
||||
conn.execute(stmt.bind(200, "f0"), result);
|
||||
BOOST_TEST(result.size() == 1u);
|
||||
BOOST_TEST(result.meta().empty());
|
||||
BOOST_TEST(result.rows().empty());
|
||||
@ -152,7 +152,7 @@ BOOST_FIXTURE_TEST_CASE(statement_update, tcp_network_fixture)
|
||||
BOOST_TEST(result.info() == "Rows matched: 1 Changed: 1 Warnings: 0");
|
||||
|
||||
// Verify that it took effect
|
||||
conn.query("SELECT field_int FROM updates_table WHERE field_varchar = 'f0'", result);
|
||||
conn.execute("SELECT field_int FROM updates_table WHERE field_varchar = 'f0'", result);
|
||||
BOOST_TEST(result.rows().at(0).at(0).as_int64() == 200);
|
||||
|
||||
// Close the statement
|
||||
@ -170,7 +170,7 @@ BOOST_FIXTURE_TEST_CASE(statement_delete, tcp_network_fixture)
|
||||
|
||||
// Execute it
|
||||
results result;
|
||||
conn.execute_statement(stmt, std::make_tuple("f0"), result);
|
||||
conn.execute(stmt.bind("f0"), result);
|
||||
BOOST_TEST(result.size() == 1u);
|
||||
BOOST_TEST(result.meta().empty());
|
||||
BOOST_TEST(result.rows().empty());
|
||||
@ -180,7 +180,7 @@ BOOST_FIXTURE_TEST_CASE(statement_delete, tcp_network_fixture)
|
||||
BOOST_TEST(result.info() == "");
|
||||
|
||||
// Validate it took effect
|
||||
conn.query("SELECT COUNT(*) FROM updates_table", result);
|
||||
conn.execute("SELECT COUNT(*) FROM updates_table", result);
|
||||
BOOST_TEST(result.rows().at(0).at(0).as_int64() == 2);
|
||||
}
|
||||
|
||||
|
@ -65,13 +65,13 @@ struct database_types_fixture : tcp_network_fixture
|
||||
void set_time_zone()
|
||||
{
|
||||
results result;
|
||||
conn.query("SET session time_zone = '+02:00'", result);
|
||||
conn.execute("SET session time_zone = '+02:00'", result);
|
||||
}
|
||||
|
||||
void set_sql_mode()
|
||||
{
|
||||
results result;
|
||||
conn.query("SET session sql_mode = 'ALLOW_INVALID_DATES'", result);
|
||||
conn.execute("SET session sql_mode = 'ALLOW_INVALID_DATES'", result);
|
||||
}
|
||||
|
||||
database_types_fixture()
|
||||
@ -663,7 +663,7 @@ BOOST_FIXTURE_TEST_CASE(query_read, database_types_fixture)
|
||||
{
|
||||
// Execute the query
|
||||
results result;
|
||||
conn.query(table.select_sql(), result);
|
||||
conn.execute(table.select_sql(), result);
|
||||
|
||||
// Validate the received contents
|
||||
validate_meta(result.meta(), table.metas);
|
||||
@ -683,7 +683,7 @@ BOOST_FIXTURE_TEST_CASE(statement_read, database_types_fixture)
|
||||
|
||||
// Execute it with the provided parameters
|
||||
results result;
|
||||
conn.execute_statement(stmt, std::make_tuple(), result);
|
||||
conn.execute(stmt.bind(), result);
|
||||
|
||||
// Validate the received contents
|
||||
validate_meta(result.meta(), table.metas);
|
||||
@ -706,18 +706,18 @@ BOOST_FIXTURE_TEST_CASE(statement_write, database_types_fixture)
|
||||
|
||||
// Remove all contents from the table
|
||||
results result;
|
||||
conn.query(table.delete_sql(), result);
|
||||
conn.execute(table.delete_sql(), result);
|
||||
|
||||
// Insert all the contents again
|
||||
boost::mysql::execution_state st;
|
||||
for (const auto& row : table.rws)
|
||||
{
|
||||
conn.start_statement_execution(insert_stmt, row.begin(), row.end(), st);
|
||||
conn.start_execution(insert_stmt.bind(row.begin(), row.end()), st);
|
||||
BOOST_TEST_REQUIRE(st.complete());
|
||||
}
|
||||
|
||||
// Query them again and verify the insertion was okay
|
||||
conn.execute_statement(query_stmt, std::make_tuple(), result);
|
||||
conn.execute(query_stmt.bind(), result);
|
||||
validate_meta(result.meta(), table.metas);
|
||||
table.validate_rows(result.rows());
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ BOOST_FIXTURE_TEST_CASE(mysql_specific_error_code, tcp_network_fixture)
|
||||
results result;
|
||||
|
||||
// This is reported as a common, less desriptive error in MySQL5 and MariaDB
|
||||
conn.query("select * from one_row_table where field_varchar regexp '(('", result, ec, diag);
|
||||
conn.execute("select * from one_row_table where field_varchar regexp '(('", result, ec, diag);
|
||||
error_code expected_ec(
|
||||
boost::mysql::mysql_server_errc::er_regexp_mismatched_paren,
|
||||
boost::mysql::get_mysql_server_category()
|
||||
@ -51,7 +51,7 @@ BOOST_FIXTURE_TEST_CASE(mariadb_specific_error_code, tcp_network_fixture)
|
||||
results result;
|
||||
|
||||
// This is reported as a common error in MySQL5 and MySQL8
|
||||
conn.query("WITH abc AS (SELECT 1), abc as (SELECT 2) SELECT * FROM abc", result, ec, diag);
|
||||
conn.execute("WITH abc AS (SELECT 1), abc as (SELECT 2) SELECT * FROM abc", result, ec, diag);
|
||||
error_code expected_ec(
|
||||
boost::mysql::mariadb_server_errc::er_dup_query_name,
|
||||
boost::mysql::get_mariadb_server_category()
|
||||
|
@ -126,7 +126,7 @@ struct caching_sha2_fixture : handshake_fixture
|
||||
tcp_ssl_connection conn(ctx, ssl_ctx);
|
||||
boost::mysql::results result;
|
||||
conn.connect(get_endpoint<tcp_socket>(), handshake_params("root", ""));
|
||||
conn.query("FLUSH PRIVILEGES", result);
|
||||
conn.execute("FLUSH PRIVILEGES", result);
|
||||
conn.close();
|
||||
}
|
||||
};
|
||||
|
@ -31,7 +31,7 @@ BOOST_FIXTURE_TEST_CASE(empty_results, tcp_network_fixture)
|
||||
start_transaction();
|
||||
|
||||
results result;
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"%(
|
||||
INSERT INTO inserts_table (field_varchar) VALUES ('abc');
|
||||
INSERT INTO inserts_table (field_varchar) VALUES ('def');
|
||||
@ -75,7 +75,7 @@ BOOST_FIXTURE_TEST_CASE(data_results, tcp_network_fixture)
|
||||
start_transaction();
|
||||
|
||||
results result;
|
||||
conn.query(
|
||||
conn.execute(
|
||||
R"%(
|
||||
SELECT * FROM one_row_table;
|
||||
SELECT * FROM empty_table;
|
||||
@ -120,7 +120,7 @@ BOOST_FIXTURE_TEST_CASE(error_not_enabled, tcp_network_fixture)
|
||||
error_code err;
|
||||
diagnostics diag;
|
||||
|
||||
conn.query("SELECT 1; SELECT 2", result, err, diag);
|
||||
conn.execute("SELECT 1; SELECT 2", result, err, diag);
|
||||
BOOST_TEST(err == common_server_errc::er_parse_error);
|
||||
validate_string_contains(diag.server_message(), {"you have an error in your sql syntax"});
|
||||
}
|
||||
|
@ -41,13 +41,13 @@ BOOST_FIXTURE_TEST_CASE(multiple_executions, tcp_network_fixture)
|
||||
|
||||
// Execute it. Only one row will be returned (because of the id)
|
||||
results result;
|
||||
conn.execute_statement(stmt, std::make_tuple(1, "non_existent"), result);
|
||||
conn.execute(stmt.bind(1, "non_existent"), result);
|
||||
validate_2fields_meta(result.meta(), "two_rows_table");
|
||||
BOOST_TEST_REQUIRE(result.rows().size() == 1u);
|
||||
BOOST_TEST((result.rows()[0] == makerow(1, "f0")));
|
||||
|
||||
// Execute it again, but with different values. This time, two rows are returned
|
||||
conn.execute_statement(stmt, std::make_tuple(1, "f1"), result);
|
||||
conn.execute(stmt.bind(1, "f1"), result);
|
||||
validate_2fields_meta(result.meta(), "two_rows_table");
|
||||
BOOST_TEST_REQUIRE(result.rows().size() == 2u);
|
||||
BOOST_TEST((result.rows()[0] == makerow(1, "f0")));
|
||||
@ -72,17 +72,17 @@ BOOST_FIXTURE_TEST_CASE(multiple_statements, tcp_network_fixture)
|
||||
BOOST_TEST(stmt_update.id() != stmt_select.id());
|
||||
|
||||
// Execute update
|
||||
conn.execute_statement(stmt_update, std::make_tuple(210, "f0"), result);
|
||||
conn.execute(stmt_update.bind(210, "f0"), result);
|
||||
BOOST_TEST(result.meta().size() == 0u);
|
||||
BOOST_TEST(result.affected_rows() == 1u);
|
||||
|
||||
// Execute select
|
||||
conn.execute_statement(stmt_select, std::make_tuple("f0"), result);
|
||||
conn.execute(stmt_select.bind("f0"), result);
|
||||
BOOST_TEST(result.rows().size() == 1u);
|
||||
BOOST_TEST(result.rows()[0] == makerow(210));
|
||||
|
||||
// Execute update again
|
||||
conn.execute_statement(stmt_update, std::make_tuple(220, "f0"), result);
|
||||
conn.execute(stmt_update.bind(220, "f0"), result);
|
||||
BOOST_TEST(result.meta().size() == 0u);
|
||||
BOOST_TEST(result.affected_rows() == 1u);
|
||||
|
||||
@ -90,7 +90,7 @@ BOOST_FIXTURE_TEST_CASE(multiple_statements, tcp_network_fixture)
|
||||
conn.close_statement(stmt_update);
|
||||
|
||||
// Execute select again
|
||||
conn.execute_statement(stmt_select, std::make_tuple("f0"), result);
|
||||
conn.execute(stmt_select.bind("f0"), result);
|
||||
BOOST_TEST(result.rows().size() == 1u);
|
||||
BOOST_TEST(result.rows()[0] == makerow(220));
|
||||
|
||||
@ -109,7 +109,7 @@ BOOST_FIXTURE_TEST_CASE(statement_without_params, tcp_network_fixture)
|
||||
|
||||
// Execute doesn't error
|
||||
results result;
|
||||
conn.execute_statement(stmt, std::make_tuple(), result);
|
||||
conn.execute(stmt.bind(), result);
|
||||
validate_2fields_meta(result.meta(), "empty_table");
|
||||
BOOST_TEST(result.rows().size() == 0u);
|
||||
}
|
||||
@ -124,7 +124,7 @@ BOOST_FIXTURE_TEST_CASE(multifn, tcp_network_fixture)
|
||||
|
||||
// Execute it
|
||||
execution_state st;
|
||||
conn.start_statement_execution(stmt, std::make_tuple(), st);
|
||||
conn.start_execution(stmt.bind(), st);
|
||||
BOOST_TEST_REQUIRE(st.should_read_rows());
|
||||
|
||||
// We don't know how many rows there will be in each batch,
|
||||
|
@ -33,7 +33,7 @@ struct reconnect_fixture : network_fixture
|
||||
void do_query_ok()
|
||||
{
|
||||
results result;
|
||||
conn->query("SELECT * FROM empty_table", result).get();
|
||||
conn->execute("SELECT * FROM empty_table", result).get();
|
||||
BOOST_TEST(result.rows().empty());
|
||||
}
|
||||
};
|
||||
|
@ -65,8 +65,8 @@ BOOST_MYSQL_NETWORK_TEST(connect_error, network_fixture, err_net_samples)
|
||||
BOOST_TEST(!conn->is_open());
|
||||
}
|
||||
|
||||
// Start query
|
||||
BOOST_MYSQL_NETWORK_TEST(start_query_success, network_fixture, all_network_samples())
|
||||
// Start query (legacy)
|
||||
BOOST_MYSQL_NETWORK_TEST(start_query_legacy_success, network_fixture, all_network_samples())
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
@ -76,7 +76,7 @@ BOOST_MYSQL_NETWORK_TEST(start_query_success, network_fixture, all_network_sampl
|
||||
validate_2fields_meta(st.meta(), "empty_table");
|
||||
}
|
||||
|
||||
BOOST_MYSQL_NETWORK_TEST(start_query_error, network_fixture, err_net_samples)
|
||||
BOOST_MYSQL_NETWORK_TEST(start_query_legacy_error, network_fixture, err_net_samples)
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
@ -85,8 +85,28 @@ BOOST_MYSQL_NETWORK_TEST(start_query_error, network_fixture, err_net_samples)
|
||||
.validate_error(common_server_errc::er_bad_field_error, {"unknown column", "field_bad"});
|
||||
}
|
||||
|
||||
// Query
|
||||
BOOST_MYSQL_NETWORK_TEST(query_success, network_fixture, all_network_samples())
|
||||
// Start execution (query)
|
||||
BOOST_MYSQL_NETWORK_TEST(start_execution_query_success, network_fixture, all_network_samples())
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
execution_state st;
|
||||
conn->start_execution("SELECT * FROM empty_table", st).get();
|
||||
BOOST_TEST(st.should_read_rows());
|
||||
validate_2fields_meta(st.meta(), "empty_table");
|
||||
}
|
||||
|
||||
BOOST_MYSQL_NETWORK_TEST(start_execution_query_error, network_fixture, err_net_samples)
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
execution_state st;
|
||||
conn->start_execution("SELECT field_varchar, field_bad FROM one_row_table", st)
|
||||
.validate_error(common_server_errc::er_bad_field_error, {"unknown column", "field_bad"});
|
||||
}
|
||||
|
||||
// Query (legacy)
|
||||
BOOST_MYSQL_NETWORK_TEST(query_legacy_success, network_fixture, all_network_samples())
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
@ -97,7 +117,7 @@ BOOST_MYSQL_NETWORK_TEST(query_success, network_fixture, all_network_samples())
|
||||
BOOST_TEST(result.meta().size() == 2u);
|
||||
}
|
||||
|
||||
BOOST_MYSQL_NETWORK_TEST(query_error, network_fixture, err_net_samples)
|
||||
BOOST_MYSQL_NETWORK_TEST(query_legacy_error, network_fixture, err_net_samples)
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
@ -106,6 +126,27 @@ BOOST_MYSQL_NETWORK_TEST(query_error, network_fixture, err_net_samples)
|
||||
.validate_error(common_server_errc::er_bad_field_error, {"unknown column", "field_bad"});
|
||||
}
|
||||
|
||||
// execute (query)
|
||||
BOOST_MYSQL_NETWORK_TEST(execute_query_success, network_fixture, all_network_samples())
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
results result;
|
||||
conn->execute("SELECT 'hello', 42", result).get();
|
||||
BOOST_TEST(result.rows().size() == 1u);
|
||||
BOOST_TEST(result.rows()[0] == makerow("hello", 42));
|
||||
BOOST_TEST(result.meta().size() == 2u);
|
||||
}
|
||||
|
||||
BOOST_MYSQL_NETWORK_TEST(execute_query_error, network_fixture, err_net_samples)
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
results result;
|
||||
conn->execute("SELECT field_varchar, field_bad FROM one_row_table", result)
|
||||
.validate_error(common_server_errc::er_bad_field_error, {"unknown column", "field_bad"});
|
||||
}
|
||||
|
||||
// Prepare statement
|
||||
BOOST_MYSQL_NETWORK_TEST(prepare_statement_success, network_fixture, all_network_samples())
|
||||
{
|
||||
@ -123,8 +164,8 @@ BOOST_MYSQL_NETWORK_TEST(prepare_statement_error, network_fixture, err_net_sampl
|
||||
.validate_error(common_server_errc::er_no_such_table, {"table", "doesn't exist", "bad_table"});
|
||||
}
|
||||
|
||||
// Start statement execution (iterator version)
|
||||
BOOST_MYSQL_NETWORK_TEST(start_statement_execution_it_success, network_fixture, all_network_samples())
|
||||
// Start statement execution (legacy, iterator)
|
||||
BOOST_MYSQL_NETWORK_TEST(start_statement_execution_legacy_it_success, network_fixture, all_network_samples())
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
@ -139,7 +180,7 @@ BOOST_MYSQL_NETWORK_TEST(start_statement_execution_it_success, network_fixture,
|
||||
BOOST_TEST(st.should_read_rows());
|
||||
}
|
||||
|
||||
BOOST_MYSQL_NETWORK_TEST(start_statement_execution_it_error, network_fixture, err_net_samples)
|
||||
BOOST_MYSQL_NETWORK_TEST(start_statement_execution_legacy_it_error, network_fixture, err_net_samples)
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
start_transaction();
|
||||
@ -158,8 +199,28 @@ BOOST_MYSQL_NETWORK_TEST(start_statement_execution_it_error, network_fixture, er
|
||||
);
|
||||
}
|
||||
|
||||
// Start statement execution (tuple version)
|
||||
BOOST_MYSQL_NETWORK_TEST(start_statement_execution_tuple_success, network_fixture, all_network_samples())
|
||||
// Start execution (statement, iterator). No error spotcheck, since it's the same underlying function
|
||||
BOOST_MYSQL_NETWORK_TEST(start_execution_stmt_it_success, network_fixture, all_network_samples())
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
// Prepare
|
||||
auto stmt = conn->prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)").get();
|
||||
|
||||
// Execute
|
||||
execution_state st;
|
||||
std::forward_list<field_view> params{field_view("item"), field_view(42)};
|
||||
conn->start_execution(stmt.bind(params.cbegin(), params.cend()), st).validate_no_error();
|
||||
validate_2fields_meta(st.meta(), "empty_table");
|
||||
BOOST_TEST(st.should_read_rows());
|
||||
}
|
||||
|
||||
// Start statement execution (legacy, tuple)
|
||||
BOOST_MYSQL_NETWORK_TEST(
|
||||
start_statement_execution_legacy_tuple_success,
|
||||
network_fixture,
|
||||
all_network_samples()
|
||||
)
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
@ -173,7 +234,7 @@ BOOST_MYSQL_NETWORK_TEST(start_statement_execution_tuple_success, network_fixtur
|
||||
BOOST_TEST(st.should_read_rows());
|
||||
}
|
||||
|
||||
BOOST_MYSQL_NETWORK_TEST(start_statement_execution_tuple_error, network_fixture, err_net_samples)
|
||||
BOOST_MYSQL_NETWORK_TEST(start_statement_execution_legacy_tuple_error, network_fixture, err_net_samples)
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
start_transaction();
|
||||
@ -191,8 +252,23 @@ BOOST_MYSQL_NETWORK_TEST(start_statement_execution_tuple_error, network_fixture,
|
||||
);
|
||||
}
|
||||
|
||||
// Execute statement
|
||||
BOOST_MYSQL_NETWORK_TEST(execute_statement_success, network_fixture, all_network_samples())
|
||||
// start execution (statement, tuple). No error spotcheck since it's the same underlying fn
|
||||
BOOST_MYSQL_NETWORK_TEST(start_execution_statement_tuple_success, network_fixture, all_network_samples())
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
// Prepare
|
||||
auto stmt = conn->prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)").get();
|
||||
|
||||
// Execute
|
||||
execution_state st;
|
||||
conn->start_execution(stmt.bind(field_view(42), field_view(40)), st).validate_no_error();
|
||||
validate_2fields_meta(st.meta(), "empty_table");
|
||||
BOOST_TEST(st.should_read_rows());
|
||||
}
|
||||
|
||||
// Execute statement (legacy)
|
||||
BOOST_MYSQL_NETWORK_TEST(execute_statement_legacy_success, network_fixture, all_network_samples())
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
@ -205,7 +281,7 @@ BOOST_MYSQL_NETWORK_TEST(execute_statement_success, network_fixture, all_network
|
||||
BOOST_TEST(result.rows().size() == 0u);
|
||||
}
|
||||
|
||||
BOOST_MYSQL_NETWORK_TEST(execute_statement_error, network_fixture, err_net_samples)
|
||||
BOOST_MYSQL_NETWORK_TEST(execute_statement_legacy_error, network_fixture, err_net_samples)
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
start_transaction();
|
||||
@ -223,6 +299,35 @@ BOOST_MYSQL_NETWORK_TEST(execute_statement_error, network_fixture, err_net_sampl
|
||||
);
|
||||
}
|
||||
|
||||
// Execute (statement, iterator). No error spotcheck since it's the same underlying fn
|
||||
BOOST_MYSQL_NETWORK_TEST(execute_statement_iterator_success, network_fixture, err_net_samples)
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
// Prepare
|
||||
auto stmt = conn->prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)").get();
|
||||
|
||||
// Execute
|
||||
results result;
|
||||
std::forward_list<field_view> params{field_view("item"), field_view(42)};
|
||||
conn->execute(stmt.bind(params.cbegin(), params.cend()), result).validate_no_error();
|
||||
BOOST_TEST(result.rows().size() == 0u);
|
||||
}
|
||||
|
||||
// Execute (statement, tuple). No error spotcheck since it's the same underlying fn
|
||||
BOOST_MYSQL_NETWORK_TEST(execute_statement_tuple_success, network_fixture, err_net_samples)
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
// Prepare
|
||||
auto stmt = conn->prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)").get();
|
||||
|
||||
// Execute
|
||||
results result;
|
||||
conn->execute(stmt.bind(field_view("item"), field_view(42)), result).validate_no_error();
|
||||
BOOST_TEST(result.rows().size() == 0u);
|
||||
}
|
||||
|
||||
// Close statement: no server error spotcheck
|
||||
BOOST_MYSQL_NETWORK_TEST(close_statement_success, network_fixture, all_network_samples())
|
||||
{
|
||||
|
@ -36,7 +36,7 @@ BOOST_FIXTURE_TEST_CASE(without_selects, tcp_network_fixture)
|
||||
|
||||
// Call the procedure
|
||||
results result;
|
||||
conn.execute_statement(stmt, std::make_tuple("abc"), result);
|
||||
conn.execute(stmt.bind("abc"), result);
|
||||
|
||||
// Verify results
|
||||
BOOST_TEST_REQUIRE(result.size() == 1u);
|
||||
@ -49,7 +49,7 @@ BOOST_FIXTURE_TEST_CASE(without_selects, tcp_network_fixture)
|
||||
BOOST_TEST(result.out_params() == row_view());
|
||||
|
||||
// Verify it took place
|
||||
conn.query("SELECT field_varchar FROM inserts_table", result);
|
||||
conn.execute("SELECT field_varchar FROM inserts_table", result);
|
||||
BOOST_TEST(result.rows().at(0).at(0).as_string() == "abc");
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ BOOST_FIXTURE_TEST_CASE(with_one_select, tcp_network_fixture)
|
||||
|
||||
// Call the procedure
|
||||
results result;
|
||||
conn.execute_statement(stmt, std::make_tuple("abc"), result);
|
||||
conn.execute(stmt.bind("abc"), result);
|
||||
|
||||
// Verify results
|
||||
BOOST_TEST_REQUIRE(result.size() == 2u);
|
||||
@ -90,7 +90,7 @@ BOOST_FIXTURE_TEST_CASE(with_two_selects, tcp_network_fixture)
|
||||
|
||||
// Call the procedure
|
||||
results result;
|
||||
conn.execute_statement(stmt, std::make_tuple("abc", 42), result);
|
||||
conn.execute(stmt.bind("abc", 42), result);
|
||||
|
||||
// Verify results
|
||||
BOOST_TEST_REQUIRE(result.size() == 3u);
|
||||
@ -124,7 +124,7 @@ BOOST_FIXTURE_TEST_CASE(with_two_selects_multifn, tcp_network_fixture)
|
||||
|
||||
// Call the procedure
|
||||
execution_state st;
|
||||
conn.start_statement_execution(stmt, std::make_tuple("abc", 42), st);
|
||||
conn.start_execution(stmt.bind("abc", 42), st);
|
||||
BOOST_TEST_REQUIRE(st.should_read_rows());
|
||||
validate_2fields_meta(st.meta(), "one_row_table");
|
||||
|
||||
@ -173,7 +173,7 @@ BOOST_FIXTURE_TEST_CASE(output_params_not_bound, tcp_network_fixture)
|
||||
|
||||
// Call the procedure
|
||||
results result;
|
||||
conn.execute_statement(stmt, std::make_tuple(10), result);
|
||||
conn.execute(stmt.bind(10), result);
|
||||
|
||||
// Verify results
|
||||
BOOST_TEST_REQUIRE(result.size() == 2u);
|
||||
@ -197,7 +197,7 @@ BOOST_FIXTURE_TEST_CASE(output_params_bound, tcp_network_fixture)
|
||||
|
||||
// Call the procedure
|
||||
results result;
|
||||
conn.execute_statement(stmt, std::make_tuple(10, nullptr, 30), result);
|
||||
conn.execute(stmt.bind(10, nullptr, 30), result);
|
||||
|
||||
// Verify results
|
||||
BOOST_TEST_REQUIRE(result.size() == 3u);
|
||||
@ -230,7 +230,7 @@ BOOST_FIXTURE_TEST_CASE(output_params_bound_multifn, tcp_network_fixture)
|
||||
|
||||
// Call the procedure
|
||||
execution_state st;
|
||||
conn.start_statement_execution(stmt, std::make_tuple(10, nullptr, 30), st);
|
||||
conn.start_execution(stmt.bind(10, nullptr, 30), st);
|
||||
BOOST_TEST_REQUIRE(st.should_read_rows());
|
||||
validate_2fields_meta(st.meta(), "one_row_table");
|
||||
|
||||
@ -277,7 +277,7 @@ BOOST_FIXTURE_TEST_CASE(with_signal, tcp_network_fixture)
|
||||
results result;
|
||||
error_code err;
|
||||
diagnostics diag;
|
||||
conn.execute_statement(stmt, std::make_tuple(), result, err, diag);
|
||||
conn.execute(stmt.bind(), result, err, diag);
|
||||
|
||||
// Verify results
|
||||
BOOST_TEST(err == common_server_errc::er_no);
|
||||
@ -290,7 +290,7 @@ BOOST_FIXTURE_TEST_CASE(with_query, tcp_network_fixture)
|
||||
|
||||
// Call the procedure
|
||||
results result;
|
||||
conn.query("CALL sp_outparams(42, @var1, @var2)", result);
|
||||
conn.execute("CALL sp_outparams(42, @var1, @var2)", result);
|
||||
|
||||
// Verify results
|
||||
BOOST_TEST_REQUIRE(result.size() == 2u);
|
||||
|
@ -64,6 +64,12 @@ public:
|
||||
fv_list_it params_last,
|
||||
execution_state& st
|
||||
) = 0;
|
||||
virtual network_result<void> execute(string_view, results&) = 0;
|
||||
virtual network_result<void> execute(bound_statement_tuple<std::tuple<field_view, field_view>>, results&) = 0;
|
||||
virtual network_result<void> execute(bound_statement_iterator_range<fv_list_it>, results&) = 0;
|
||||
virtual network_result<void> start_execution(string_view, execution_state&) = 0;
|
||||
virtual network_result<void> start_execution(bound_statement_tuple<std::tuple<field_view, field_view>>, execution_state&) = 0;
|
||||
virtual network_result<void> start_execution(bound_statement_iterator_range<fv_list_it>, execution_state&) = 0;
|
||||
virtual network_result<void> close_statement(statement&) = 0;
|
||||
virtual network_result<void> read_resultset_head(execution_state& st) = 0;
|
||||
virtual network_result<rows_view> read_some_rows(execution_state& st) = 0;
|
||||
|
@ -105,7 +105,7 @@ struct network_fixture : network_fixture_base
|
||||
void start_transaction()
|
||||
{
|
||||
results result;
|
||||
conn->query("START TRANSACTION", result).get();
|
||||
conn->execute("START TRANSACTION", result).get();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -31,7 +31,7 @@ struct tcp_network_fixture : network_fixture_base
|
||||
void start_transaction()
|
||||
{
|
||||
results result;
|
||||
conn.query("START TRANSACTION", result);
|
||||
conn.execute("START TRANSACTION", result);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -123,6 +123,12 @@ function_table<stream_type> create_table()
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_execute_statement),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_start_statement_execution),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_start_statement_execution),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_execute),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_execute),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_execute),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_start_execution),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_start_execution),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_start_execution),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_close_statement),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_read_resultset_head),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_read_some_rows),
|
||||
|
@ -45,19 +45,29 @@ template <class Stream>
|
||||
struct function_table
|
||||
{
|
||||
using conn_type = connection<Stream>;
|
||||
using stmt_tuple = bound_statement_tuple<std::tuple<field_view, field_view>>;
|
||||
using stmt_it = bound_statement_iterator_range<fv_list_it>;
|
||||
|
||||
using connect_sig = network_result<
|
||||
void>(conn_type&, const typename Stream::lowest_layer_type::endpoint_type&, const handshake_params&);
|
||||
using handshake_sig = network_result<void>(conn_type&, const handshake_params&);
|
||||
using query_sig = network_result<void>(conn_type&, string_view, results&);
|
||||
using start_query_sig = network_result<void>(conn_type&, string_view, execution_state&);
|
||||
using query_legacy_sig = network_result<void>(conn_type&, string_view, results&);
|
||||
using start_query_legacy_sig = network_result<void>(conn_type&, string_view, execution_state&);
|
||||
using prepare_statement_sig = network_result<statement>(conn_type&, string_view);
|
||||
using execute_stmt_sig = network_result<
|
||||
using execute_stmt_legacy_sig = network_result<
|
||||
void>(conn_type&, const statement&, const std::tuple<field_view, field_view>&, results&);
|
||||
using start_stmt_execution_tuple_sig = network_result<
|
||||
using start_stmt_execution_legacy_tuple_sig = network_result<
|
||||
void>(conn_type&, const statement&, const std::tuple<field_view, field_view>&, execution_state&);
|
||||
using start_stmt_execution_it_sig =
|
||||
using start_stmt_execution_legacy_it_sig =
|
||||
network_result<void>(conn_type&, const statement&, fv_list_it, fv_list_it, execution_state&);
|
||||
using execute_query_sig = network_result<void>(conn_type&, const string_view&, results&);
|
||||
using execute_stmt_tuple_sig = network_result<void>(conn_type&, const stmt_tuple&, results&);
|
||||
using execute_stmt_it_sig = network_result<void>(conn_type&, const stmt_it&, results&);
|
||||
using start_execution_query_sig = network_result<void>(conn_type&, const string_view&, execution_state&);
|
||||
using start_execution_stmt_tuple_sig =
|
||||
network_result<void>(conn_type&, const stmt_tuple&, execution_state&);
|
||||
using start_execution_stmt_it_sig = network_result<void>(conn_type&, const stmt_it&, execution_state&);
|
||||
|
||||
using close_stmt_sig = network_result<void>(conn_type&, const statement&);
|
||||
using read_resultset_head_sig = network_result<void>(conn_type&, execution_state&);
|
||||
using read_some_rows_sig = network_result<rows_view>(conn_type&, execution_state&);
|
||||
@ -67,12 +77,18 @@ struct function_table
|
||||
|
||||
std::function<connect_sig> connect;
|
||||
std::function<handshake_sig> handshake;
|
||||
std::function<query_sig> query;
|
||||
std::function<start_query_sig> start_query;
|
||||
std::function<query_legacy_sig> query_legacy;
|
||||
std::function<start_query_legacy_sig> start_query_legacy;
|
||||
std::function<prepare_statement_sig> prepare_statement;
|
||||
std::function<execute_stmt_sig> execute_stmt;
|
||||
std::function<start_stmt_execution_tuple_sig> start_stmt_execution_tuple;
|
||||
std::function<start_stmt_execution_it_sig> start_stmt_execution_it;
|
||||
std::function<execute_stmt_legacy_sig> execute_stmt_legacy;
|
||||
std::function<start_stmt_execution_legacy_tuple_sig> start_stmt_execution_legacy_tuple;
|
||||
std::function<start_stmt_execution_legacy_it_sig> start_stmt_execution_legacy_it;
|
||||
std::function<execute_query_sig> execute_query;
|
||||
std::function<execute_stmt_tuple_sig> execute_stmt_tuple;
|
||||
std::function<execute_stmt_it_sig> execute_stmt_it;
|
||||
std::function<start_execution_query_sig> start_execution_query;
|
||||
std::function<start_execution_stmt_tuple_sig> start_execution_stmt_tuple;
|
||||
std::function<start_execution_stmt_it_sig> start_execution_stmt_it;
|
||||
std::function<close_stmt_sig> close_stmt;
|
||||
std::function<read_resultset_head_sig> read_resultset_head;
|
||||
std::function<read_some_rows_sig> read_some_rows;
|
||||
@ -96,12 +112,18 @@ function_table<Stream> create_sync_table()
|
||||
return function_table<Stream>{
|
||||
Netmaker::template type<typename table_t::connect_sig>::call(&conn_type::connect),
|
||||
Netmaker::template type<typename table_t::handshake_sig>::call(&conn_type::handshake),
|
||||
Netmaker::template type<typename table_t::query_sig>::call(&conn_type::query),
|
||||
Netmaker::template type<typename table_t::start_query_sig>::call(&conn_type::start_query),
|
||||
Netmaker::template type<typename table_t::query_legacy_sig>::call(&conn_type::query),
|
||||
Netmaker::template type<typename table_t::start_query_legacy_sig>::call(&conn_type::start_query),
|
||||
Netmaker::template type<typename table_t::prepare_statement_sig>::call(&conn_type::prepare_statement),
|
||||
Netmaker::template type<typename table_t::execute_stmt_sig>::call(&conn_type::execute_statement),
|
||||
Netmaker::template type<typename table_t::start_stmt_execution_tuple_sig>::call(&conn_type::start_statement_execution),
|
||||
Netmaker::template type<typename table_t::start_stmt_execution_it_sig>::call(&conn_type::start_statement_execution),
|
||||
Netmaker::template type<typename table_t::execute_stmt_legacy_sig>::call(&conn_type::execute_statement),
|
||||
Netmaker::template type<typename table_t::start_stmt_execution_legacy_tuple_sig>::call(&conn_type::start_statement_execution),
|
||||
Netmaker::template type<typename table_t::start_stmt_execution_legacy_it_sig>::call(&conn_type::start_statement_execution),
|
||||
Netmaker::template type<typename table_t::execute_query_sig>::call(&conn_type::execute),
|
||||
Netmaker::template type<typename table_t::execute_stmt_tuple_sig>::call(&conn_type::execute),
|
||||
Netmaker::template type<typename table_t::execute_stmt_it_sig>::call(&conn_type::execute),
|
||||
Netmaker::template type<typename table_t::start_execution_query_sig>::call(&conn_type::start_execution),
|
||||
Netmaker::template type<typename table_t::start_execution_stmt_tuple_sig>::call(&conn_type::start_execution),
|
||||
Netmaker::template type<typename table_t::start_execution_stmt_it_sig>::call(&conn_type::start_execution),
|
||||
Netmaker::template type<typename table_t::close_stmt_sig>::call(&conn_type::close_statement),
|
||||
Netmaker::template type<typename table_t::read_resultset_head_sig>::call(&conn_type::read_resultset_head),
|
||||
Netmaker::template type<typename table_t::read_some_rows_sig>::call(&conn_type::read_some_rows),
|
||||
@ -123,12 +145,18 @@ function_table<Stream> create_async_table()
|
||||
return function_table<Stream>{
|
||||
Netmaker::template type<typename table_t::connect_sig>::call(&conn_type::async_connect),
|
||||
Netmaker::template type<typename table_t::handshake_sig>::call(&conn_type::async_handshake),
|
||||
Netmaker::template type<typename table_t::query_sig>::call(&conn_type::async_query),
|
||||
Netmaker::template type<typename table_t::start_query_sig>::call(&conn_type::async_start_query),
|
||||
Netmaker::template type<typename table_t::query_legacy_sig>::call(&conn_type::async_query),
|
||||
Netmaker::template type<typename table_t::start_query_legacy_sig>::call(&conn_type::async_start_query),
|
||||
Netmaker::template type<typename table_t::prepare_statement_sig>::call(&conn_type::async_prepare_statement),
|
||||
Netmaker::template type<typename table_t::execute_stmt_sig>::call(&conn_type::async_execute_statement),
|
||||
Netmaker::template type<typename table_t::start_stmt_execution_tuple_sig>::call(&conn_type::async_start_statement_execution),
|
||||
Netmaker::template type<typename table_t::start_stmt_execution_it_sig>::call(&conn_type::async_start_statement_execution),
|
||||
Netmaker::template type<typename table_t::execute_stmt_legacy_sig>::call(&conn_type::async_execute_statement),
|
||||
Netmaker::template type<typename table_t::start_stmt_execution_legacy_tuple_sig>::call(&conn_type::async_start_statement_execution),
|
||||
Netmaker::template type<typename table_t::start_stmt_execution_legacy_it_sig>::call(&conn_type::async_start_statement_execution),
|
||||
Netmaker::template type<typename table_t::execute_query_sig>::call(&conn_type::async_execute),
|
||||
Netmaker::template type<typename table_t::execute_stmt_tuple_sig>::call(&conn_type::async_execute),
|
||||
Netmaker::template type<typename table_t::execute_stmt_it_sig>::call(&conn_type::async_execute),
|
||||
Netmaker::template type<typename table_t::start_execution_query_sig>::call(&conn_type::async_start_execution),
|
||||
Netmaker::template type<typename table_t::start_execution_stmt_tuple_sig>::call(&conn_type::async_start_execution),
|
||||
Netmaker::template type<typename table_t::start_execution_stmt_it_sig>::call(&conn_type::async_start_execution),
|
||||
Netmaker::template type<typename table_t::close_stmt_sig>::call(&conn_type::async_close_statement),
|
||||
Netmaker::template type<typename table_t::read_resultset_head_sig>::call(&conn_type::async_read_resultset_head),
|
||||
Netmaker::template type<typename table_t::read_some_rows_sig>::call(&conn_type::async_read_some_rows),
|
||||
@ -220,11 +248,11 @@ public:
|
||||
}
|
||||
network_result<void> query(string_view query, results& result) override
|
||||
{
|
||||
return table_.query(conn_, query, result);
|
||||
return table_.query_legacy(conn_, query, result);
|
||||
}
|
||||
network_result<void> start_query(string_view query, execution_state& st) override
|
||||
{
|
||||
return table_.start_query(conn_, query, st);
|
||||
return table_.start_query_legacy(conn_, query, st);
|
||||
}
|
||||
network_result<statement> prepare_statement(string_view stmt_sql) override
|
||||
{
|
||||
@ -237,7 +265,7 @@ public:
|
||||
results& result
|
||||
) override
|
||||
{
|
||||
return table_.execute_stmt(conn_, stmt, std::make_tuple(param1, param2), result);
|
||||
return table_.execute_stmt_legacy(conn_, stmt, std::make_tuple(param1, param2), result);
|
||||
}
|
||||
network_result<void> start_statement_execution(
|
||||
const statement& stmt,
|
||||
@ -246,7 +274,7 @@ public:
|
||||
execution_state& st
|
||||
) override
|
||||
{
|
||||
return table_.start_stmt_execution_tuple(conn_, stmt, std::make_tuple(param1, param2), st);
|
||||
return table_.start_stmt_execution_legacy_tuple(conn_, stmt, std::make_tuple(param1, param2), st);
|
||||
}
|
||||
network_result<void> start_statement_execution(
|
||||
const statement& stmt,
|
||||
@ -255,8 +283,41 @@ public:
|
||||
execution_state& st
|
||||
) override
|
||||
{
|
||||
return table_.start_stmt_execution_it(conn_, stmt, params_first, params_last, st);
|
||||
return table_.start_stmt_execution_legacy_it(conn_, stmt, params_first, params_last, st);
|
||||
}
|
||||
|
||||
network_result<void> execute(string_view query, results& result) override
|
||||
{
|
||||
return table_.execute_query(conn_, query, result);
|
||||
}
|
||||
network_result<void> execute(
|
||||
bound_statement_tuple<std::tuple<field_view, field_view>> req,
|
||||
results& result
|
||||
) override
|
||||
{
|
||||
return table_.execute_stmt_tuple(conn_, req, result);
|
||||
}
|
||||
network_result<void> execute(bound_statement_iterator_range<fv_list_it> req, results& result) override
|
||||
{
|
||||
return table_.execute_stmt_it(conn_, req, result);
|
||||
}
|
||||
network_result<void> start_execution(string_view query, execution_state& st) override
|
||||
{
|
||||
return table_.start_execution_query(conn_, query, st);
|
||||
}
|
||||
network_result<void> start_execution(
|
||||
bound_statement_tuple<std::tuple<field_view, field_view>> req,
|
||||
execution_state& st
|
||||
) override
|
||||
{
|
||||
return table_.start_execution_stmt_tuple(conn_, req, st);
|
||||
}
|
||||
network_result<void> start_execution(bound_statement_iterator_range<fv_list_it> req, execution_state& st)
|
||||
override
|
||||
{
|
||||
return table_.start_execution_stmt_it(conn_, req, st);
|
||||
}
|
||||
|
||||
network_result<void> close_statement(statement& stmt) override { return table_.close_stmt(conn_, stmt); }
|
||||
network_result<void> read_resultset_head(execution_state& st) override
|
||||
{
|
||||
|
@ -16,6 +16,7 @@ add_executable(
|
||||
detail/auxiliar/static_string.cpp
|
||||
detail/auxiliar/rows_iterator.cpp
|
||||
detail/auxiliar/field_type_traits.cpp
|
||||
detail/auxiliar/execution_request.cpp
|
||||
detail/auxiliar/datetime.cpp
|
||||
detail/auxiliar/row_impl.cpp
|
||||
detail/protocol/capabilities.cpp
|
||||
@ -28,10 +29,10 @@ add_executable(
|
||||
detail/protocol/deserialize_execute_response.cpp
|
||||
detail/protocol/process_error_packet.cpp
|
||||
detail/protocol/execution_state_impl.cpp
|
||||
detail/network_algorithms/start_execution_impl.cpp
|
||||
detail/network_algorithms/read_resultset_head.cpp
|
||||
detail/network_algorithms/start_execution.cpp
|
||||
detail/network_algorithms/read_some_rows.cpp
|
||||
detail/network_algorithms/execute.cpp
|
||||
detail/network_algorithms/execute_impl.cpp
|
||||
detail/network_algorithms/high_level_execution.cpp
|
||||
detail/network_algorithms/close_statement.cpp
|
||||
detail/network_algorithms/ping.cpp
|
||||
|
@ -35,6 +35,7 @@ unit-test boost_mysql_unittests
|
||||
detail/auxiliar/static_string.cpp
|
||||
detail/auxiliar/rows_iterator.cpp
|
||||
detail/auxiliar/field_type_traits.cpp
|
||||
detail/auxiliar/execution_request.cpp
|
||||
detail/auxiliar/datetime.cpp
|
||||
detail/auxiliar/row_impl.cpp
|
||||
detail/protocol/capabilities.cpp
|
||||
@ -47,10 +48,10 @@ unit-test boost_mysql_unittests
|
||||
detail/protocol/deserialize_execute_response.cpp
|
||||
detail/protocol/process_error_packet.cpp
|
||||
detail/protocol/execution_state_impl.cpp
|
||||
detail/network_algorithms/start_execution_impl.cpp
|
||||
detail/network_algorithms/read_resultset_head.cpp
|
||||
detail/network_algorithms/start_execution.cpp
|
||||
detail/network_algorithms/read_some_rows.cpp
|
||||
detail/network_algorithms/execute.cpp
|
||||
detail/network_algorithms/execute_impl.cpp
|
||||
detail/network_algorithms/high_level_execution.cpp
|
||||
detail/network_algorithms/close_statement.cpp
|
||||
detail/network_algorithms/ping.cpp
|
||||
|
76
test/unit/detail/auxiliar/execution_request.cpp
Normal file
76
test/unit/detail/auxiliar/execution_request.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
//
|
||||
// Copyright (c) 2019-2023 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)
|
||||
//
|
||||
|
||||
#include <boost/mysql/string_view.hpp>
|
||||
|
||||
#include <boost/mysql/detail/auxiliar/execution_request.hpp>
|
||||
#include <boost/mysql/detail/config.hpp>
|
||||
#include <boost/mysql/impl/statement.hpp>
|
||||
|
||||
#include <string>
|
||||
#ifdef __cpp_lib_string_view
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
using namespace boost::mysql;
|
||||
using detail::is_execution_request;
|
||||
|
||||
// -----
|
||||
// strings
|
||||
// -----
|
||||
static_assert(is_execution_request<std::string>::value, "");
|
||||
static_assert(is_execution_request<const std::string&>::value, "");
|
||||
static_assert(is_execution_request<std::string&&>::value, "");
|
||||
static_assert(is_execution_request<std::string&>::value, "");
|
||||
|
||||
static_assert(is_execution_request<string_view>::value, "");
|
||||
static_assert(is_execution_request<const string_view&>::value, "");
|
||||
static_assert(is_execution_request<string_view&&>::value, "");
|
||||
|
||||
#ifdef __cpp_lib_string_view
|
||||
static_assert(is_execution_request<std::string_view>::value, "");
|
||||
static_assert(is_execution_request<const std::string_view&>::value, "");
|
||||
static_assert(is_execution_request<std::string_view&&>::value, "");
|
||||
#endif
|
||||
|
||||
static_assert(is_execution_request<const char*>::value, "");
|
||||
|
||||
static_assert(is_execution_request<const char[14]>::value, "");
|
||||
static_assert(is_execution_request<const char (&)[14]>::value, "");
|
||||
|
||||
// -----
|
||||
// tuple statements
|
||||
// -----
|
||||
using tup_type = std::tuple<int, const char*, std::nullptr_t>;
|
||||
static_assert(is_execution_request<bound_statement_tuple<tup_type>>::value, "");
|
||||
static_assert(is_execution_request<const bound_statement_tuple<tup_type>&>::value, "");
|
||||
static_assert(is_execution_request<bound_statement_tuple<tup_type>&>::value, "");
|
||||
static_assert(is_execution_request<bound_statement_tuple<tup_type>&&>::value, "");
|
||||
|
||||
static_assert(is_execution_request<bound_statement_tuple<std::tuple<>>>::value, "");
|
||||
|
||||
// tuples not accepted
|
||||
static_assert(!is_execution_request<tup_type>::value, "");
|
||||
static_assert(!is_execution_request<const tup_type&>::value, "");
|
||||
static_assert(!is_execution_request<tup_type&>::value, "");
|
||||
static_assert(!is_execution_request<tup_type&&>::value, "");
|
||||
|
||||
// -----
|
||||
// iterator statements
|
||||
// -----
|
||||
static_assert(is_execution_request<bound_statement_iterator_range<field_view*>>::value, "");
|
||||
static_assert(is_execution_request<const bound_statement_iterator_range<field_view*>&>::value, "");
|
||||
static_assert(is_execution_request<bound_statement_iterator_range<field_view*>&>::value, "");
|
||||
static_assert(is_execution_request<bound_statement_iterator_range<field_view*>&&>::value, "");
|
||||
|
||||
// iterators not accepted
|
||||
static_assert(!is_execution_request<field_view*>::value, "");
|
||||
|
||||
// Other stuff not accepted
|
||||
static_assert(!is_execution_request<field_view>::value, "");
|
||||
static_assert(!is_execution_request<int>::value, "");
|
||||
static_assert(!is_execution_request<std::nullptr_t>::value, "");
|
@ -8,7 +8,7 @@
|
||||
#include <boost/mysql/client_errc.hpp>
|
||||
#include <boost/mysql/execution_state.hpp>
|
||||
|
||||
#include <boost/mysql/detail/network_algorithms/execute.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/execute_impl.hpp>
|
||||
#include <boost/mysql/detail/protocol/constants.hpp>
|
||||
#include <boost/mysql/detail/protocol/resultset_encoding.hpp>
|
||||
|
||||
@ -38,8 +38,8 @@ struct
|
||||
typename netfun_maker::signature execute;
|
||||
const char* name;
|
||||
} all_fns[] = {
|
||||
{netfun_maker::sync_errc(&detail::execute<test_stream>), "sync" },
|
||||
{netfun_maker::async_errinfo(&detail::async_execute<test_stream>), "async"}
|
||||
{netfun_maker::sync_errc(&detail::execute_impl<test_stream>), "sync" },
|
||||
{netfun_maker::async_errinfo(&detail::async_execute_impl<test_stream>), "async"}
|
||||
};
|
||||
|
||||
// Verify that we clear any previous result
|
@ -11,6 +11,7 @@
|
||||
#include <boost/mysql/field_view.hpp>
|
||||
#include <boost/mysql/results.hpp>
|
||||
#include <boost/mysql/statement.hpp>
|
||||
#include <boost/mysql/string_view.hpp>
|
||||
|
||||
#include <boost/mysql/detail/protocol/constants.hpp>
|
||||
#include <boost/mysql/detail/protocol/resultset_encoding.hpp>
|
||||
@ -19,7 +20,9 @@
|
||||
#include <boost/asio/use_awaitable.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "assert_buffer_equals.hpp"
|
||||
#include "creation/create_execution_state.hpp"
|
||||
@ -78,20 +81,27 @@ execution_state create_initial_state()
|
||||
|
||||
//
|
||||
// ------- query ---------
|
||||
// Both legacy query() and execute("SELECT ...") share a compatible signature
|
||||
//
|
||||
BOOST_AUTO_TEST_SUITE(query_)
|
||||
|
||||
using netfun_maker = netfun_maker_mem<void, test_connection, string_view, results&>;
|
||||
using netfun_maker_execute = netfun_maker_mem<void, test_connection, const string_view&, results&>;
|
||||
|
||||
struct
|
||||
{
|
||||
netfun_maker::signature query;
|
||||
const char* name;
|
||||
} all_fns[] = {
|
||||
{netfun_maker::sync_errc(&test_connection::query), "sync_errc" },
|
||||
{netfun_maker::sync_exc(&test_connection::query), "sync_exc" },
|
||||
{netfun_maker::async_errinfo(&test_connection::async_query), "async_errinfo" },
|
||||
{netfun_maker::async_noerrinfo(&test_connection::async_query), "async_noerrinfo"},
|
||||
{netfun_maker::sync_errc(&test_connection::query), "sync_errc" },
|
||||
{netfun_maker::sync_exc(&test_connection::query), "sync_exc" },
|
||||
{netfun_maker::async_errinfo(&test_connection::async_query), "async_errinfo" },
|
||||
{netfun_maker::async_noerrinfo(&test_connection::async_query), "async_noerrinfo"},
|
||||
|
||||
{netfun_maker_execute::sync_errc(&test_connection::execute), "sync_errc" },
|
||||
{netfun_maker_execute::sync_exc(&test_connection::execute), "sync_exc" },
|
||||
{netfun_maker_execute::async_errinfo(&test_connection::async_execute), "async_errinfo" },
|
||||
{netfun_maker_execute::async_noerrinfo(&test_connection::async_execute), "async_noerrinfo"},
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(success)
|
||||
@ -140,20 +150,27 @@ BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
//
|
||||
// ------- start_query ---------
|
||||
// Both legacy start_query() and start_execution("SELECT ...") share a compatible signature
|
||||
//
|
||||
BOOST_AUTO_TEST_SUITE(start_query_)
|
||||
|
||||
using netfun_maker = netfun_maker_mem<void, test_connection, string_view, execution_state&>;
|
||||
using netfun_maker_execute = netfun_maker_mem<void, test_connection, const string_view&, execution_state&>;
|
||||
|
||||
struct
|
||||
{
|
||||
netfun_maker::signature start_query;
|
||||
const char* name;
|
||||
} all_fns[] = {
|
||||
{netfun_maker::sync_errc(&test_connection::start_query), "sync_errc" },
|
||||
{netfun_maker::sync_exc(&test_connection::start_query), "sync_exc" },
|
||||
{netfun_maker::async_errinfo(&test_connection::async_start_query), "async_errinfo" },
|
||||
{netfun_maker::async_noerrinfo(&test_connection::async_start_query), "async_noerrinfo"},
|
||||
{netfun_maker::sync_errc(&test_connection::start_query), "sync_errc" },
|
||||
{netfun_maker::sync_exc(&test_connection::start_query), "sync_exc" },
|
||||
{netfun_maker::async_errinfo(&test_connection::async_start_query), "async_errinfo" },
|
||||
{netfun_maker::async_noerrinfo(&test_connection::async_start_query), "async_noerrinfo"},
|
||||
|
||||
{netfun_maker_execute::sync_errc(&test_connection::start_execution), "sync_errc" },
|
||||
{netfun_maker_execute::sync_exc(&test_connection::start_execution), "sync_exc" },
|
||||
{netfun_maker_execute::async_errinfo(&test_connection::async_start_execution), "async_errinfo" },
|
||||
{netfun_maker_execute::async_noerrinfo(&test_connection::async_start_execution), "async_noerrinfo"},
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(success)
|
||||
@ -200,13 +217,12 @@ BOOST_AUTO_TEST_CASE(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
//
|
||||
// ------- execute_statement ---------
|
||||
// ------- execute_statement (legacy) ---------
|
||||
//
|
||||
BOOST_AUTO_TEST_SUITE(execute_statement_)
|
||||
BOOST_AUTO_TEST_SUITE(execute_statement_legacy)
|
||||
|
||||
using netfun_maker = netfun_maker_mem<
|
||||
void,
|
||||
@ -321,9 +337,219 @@ BOOST_AUTO_TEST_CASE(deferred_lifetimes_lvalues)
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
//
|
||||
// ------- start_statement_execution (tuple) ---------
|
||||
// ------- execute_statement (tuple) ---------
|
||||
//
|
||||
BOOST_AUTO_TEST_SUITE(start_statement_execution_tuple)
|
||||
BOOST_AUTO_TEST_SUITE(execute_statement_tuple)
|
||||
|
||||
using netfun_maker = netfun_maker_mem<
|
||||
void,
|
||||
test_connection,
|
||||
const bound_statement_tuple<std::tuple<const char*, std::nullptr_t>>&,
|
||||
results&>;
|
||||
|
||||
struct
|
||||
{
|
||||
netfun_maker::signature execute;
|
||||
const char* name;
|
||||
} all_fns[] = {
|
||||
{netfun_maker::sync_errc(&test_connection::execute), "sync_errc" },
|
||||
{netfun_maker::sync_exc(&test_connection::execute), "sync_exc" },
|
||||
{netfun_maker::async_errinfo(&test_connection::async_execute), "async_errinfo" },
|
||||
{netfun_maker::async_noerrinfo(&test_connection::async_execute), "async_noerrinfo"},
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(success)
|
||||
{
|
||||
for (auto fns : all_fns)
|
||||
{
|
||||
BOOST_TEST_CONTEXT(fns.name)
|
||||
{
|
||||
auto result = create_initial_results();
|
||||
auto stmt = create_the_statement();
|
||||
test_connection conn;
|
||||
conn.stream().add_message(ok_msg_builder().seqnum(1).affected_rows(50).info("1st").build_ok());
|
||||
|
||||
// Call the function
|
||||
fns.execute(conn, stmt.bind("test", nullptr), result).validate_no_error();
|
||||
|
||||
// Verify the message we sent
|
||||
BOOST_MYSQL_ASSERT_BLOB_EQUALS(conn.stream().bytes_written(), execute_stmt_msg);
|
||||
|
||||
// Verify the results
|
||||
BOOST_TEST_REQUIRE(result.size() == 1u);
|
||||
BOOST_TEST(result.meta().size() == 0u);
|
||||
BOOST_TEST(result.affected_rows() == 50u);
|
||||
BOOST_TEST(result.info() == "1st");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(error_wrong_num_params)
|
||||
{
|
||||
for (auto fns : all_fns)
|
||||
{
|
||||
BOOST_TEST_CONTEXT(fns.name)
|
||||
{
|
||||
auto result = create_initial_results();
|
||||
auto stmt = statement_builder().id(1).num_params(3).build();
|
||||
test_connection conn;
|
||||
|
||||
// Call the function
|
||||
fns.execute(conn, stmt.bind("test", nullptr), result)
|
||||
.validate_error_exact(client_errc::wrong_num_params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that we correctly perform a decay-copy of the execution request,
|
||||
// relevant for deferred tokens
|
||||
#ifdef BOOST_ASIO_HAS_CO_AWAIT
|
||||
BOOST_AUTO_TEST_CASE(deferred_lifetimes_rvalues)
|
||||
{
|
||||
run_coroutine([]() -> boost::asio::awaitable<void> {
|
||||
results result;
|
||||
test_connection conn;
|
||||
conn.stream().add_message(ok_msg_builder().seqnum(1).info("1st").build_ok());
|
||||
|
||||
// Deferred op. Execution request is a temporary
|
||||
auto aw = conn.async_execute(
|
||||
create_the_statement().bind(std::string("test"), nullptr),
|
||||
result,
|
||||
boost::asio::use_awaitable
|
||||
);
|
||||
co_await std::move(aw);
|
||||
|
||||
// verify that the op had the intended effects
|
||||
BOOST_MYSQL_ASSERT_BLOB_EQUALS(conn.stream().bytes_written(), execute_stmt_msg);
|
||||
BOOST_TEST(result.info() == "1st");
|
||||
});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(deferred_lifetimes_lvalues)
|
||||
{
|
||||
run_coroutine([]() -> boost::asio::awaitable<void> {
|
||||
results result;
|
||||
test_connection conn;
|
||||
conn.stream().add_message(ok_msg_builder().seqnum(1).info("1st").build_ok());
|
||||
boost::asio::awaitable<void> aw;
|
||||
|
||||
// Deferred op
|
||||
{
|
||||
auto stmt = create_the_statement();
|
||||
auto req = stmt.bind(std::string("test"), nullptr);
|
||||
aw = conn.async_execute(req, result, boost::asio::use_awaitable);
|
||||
}
|
||||
|
||||
co_await std::move(aw);
|
||||
|
||||
// verify that the op had the intended effects
|
||||
BOOST_MYSQL_ASSERT_BLOB_EQUALS(conn.stream().bytes_written(), execute_stmt_msg);
|
||||
BOOST_TEST(result.info() == "1st");
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
//
|
||||
// ------- execute_statement (iterator) ---------
|
||||
//
|
||||
BOOST_AUTO_TEST_SUITE(execute_statement_iterator_range)
|
||||
|
||||
using netfun_maker = netfun_maker_mem<
|
||||
void,
|
||||
test_connection,
|
||||
const bound_statement_iterator_range<const field_view*>&,
|
||||
results&>;
|
||||
|
||||
struct
|
||||
{
|
||||
netfun_maker::signature execute;
|
||||
const char* name;
|
||||
} all_fns[] = {
|
||||
{netfun_maker::sync_errc(&test_connection::execute), "sync_errc" },
|
||||
{netfun_maker::sync_exc(&test_connection::execute), "sync_exc" },
|
||||
{netfun_maker::async_errinfo(&test_connection::async_execute), "async_errinfo" },
|
||||
{netfun_maker::async_noerrinfo(&test_connection::async_execute), "async_noerrinfo"},
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(success)
|
||||
{
|
||||
for (auto fns : all_fns)
|
||||
{
|
||||
BOOST_TEST_CONTEXT(fns.name)
|
||||
{
|
||||
auto result = create_initial_results();
|
||||
auto stmt = create_the_statement();
|
||||
test_connection conn;
|
||||
conn.stream().add_message(ok_msg_builder().seqnum(1).affected_rows(50).info("1st").build_ok());
|
||||
|
||||
// Call the function
|
||||
const auto params = make_fv_arr("test", nullptr);
|
||||
fns.execute(conn, stmt.bind(params.data(), params.data() + params.size()), result)
|
||||
.validate_no_error();
|
||||
|
||||
// Verify the message we sent
|
||||
BOOST_MYSQL_ASSERT_BLOB_EQUALS(conn.stream().bytes_written(), execute_stmt_msg);
|
||||
|
||||
// Verify the results
|
||||
BOOST_TEST_REQUIRE(result.size() == 1u);
|
||||
BOOST_TEST(result.meta().size() == 0u);
|
||||
BOOST_TEST(result.affected_rows() == 50u);
|
||||
BOOST_TEST(result.info() == "1st");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Regression check: iterator reference type is convertible to field_view,
|
||||
// but not equal to field_view
|
||||
BOOST_AUTO_TEST_CASE(iterator_reference_not_field_view)
|
||||
{
|
||||
auto result = create_initial_results();
|
||||
auto stmt = create_the_statement();
|
||||
test_connection conn;
|
||||
conn.stream().add_message(ok_msg_builder().seqnum(1).affected_rows(50).info("1st").build_ok());
|
||||
|
||||
// Call the function
|
||||
std::vector<field> fields{field_view("test"), field_view()};
|
||||
conn.execute(stmt.bind(fields.begin(), fields.end()), result);
|
||||
|
||||
// Verify the message we sent
|
||||
BOOST_MYSQL_ASSERT_BLOB_EQUALS(conn.stream().bytes_written(), execute_stmt_msg);
|
||||
|
||||
// Verify the results
|
||||
BOOST_TEST_REQUIRE(result.size() == 1u);
|
||||
BOOST_TEST(result.meta().size() == 0u);
|
||||
BOOST_TEST(result.affected_rows() == 50u);
|
||||
BOOST_TEST(result.info() == "1st");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(error_wrong_num_params)
|
||||
{
|
||||
for (auto fns : all_fns)
|
||||
{
|
||||
BOOST_TEST_CONTEXT(fns.name)
|
||||
{
|
||||
auto result = create_initial_results();
|
||||
auto stmt = statement_builder().id(1).num_params(3).build();
|
||||
test_connection conn;
|
||||
|
||||
// Call the function
|
||||
const auto params = make_fv_arr("test", nullptr);
|
||||
fns.execute(conn, stmt.bind(params.data(), params.data() + params.size()), result)
|
||||
.validate_error_exact(client_errc::wrong_num_params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No need to test for decay copies again here, already tested
|
||||
// in the tuple version.
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
//
|
||||
// ------- start_statement_execution (tuple, legacy) ---------
|
||||
//
|
||||
BOOST_AUTO_TEST_SUITE(start_statement_execution_tuple_legacy)
|
||||
|
||||
using netfun_maker = netfun_maker_mem<
|
||||
void,
|
||||
@ -441,9 +667,126 @@ BOOST_AUTO_TEST_CASE(deferred_lifetimes_lvalues)
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
//
|
||||
// ------- start_statement_execution (iterator) ---------
|
||||
// ------- start_statement_execution (tuple) ---------
|
||||
//
|
||||
BOOST_AUTO_TEST_SUITE(start_statement_execution_it)
|
||||
BOOST_AUTO_TEST_SUITE(start_statement_execution_tuple)
|
||||
|
||||
using netfun_maker = netfun_maker_mem<
|
||||
void,
|
||||
test_connection,
|
||||
const bound_statement_tuple<std::tuple<const char*, std::nullptr_t>>&,
|
||||
execution_state&>;
|
||||
|
||||
struct
|
||||
{
|
||||
netfun_maker::signature start_execution;
|
||||
const char* name;
|
||||
} all_fns[] = {
|
||||
{netfun_maker::sync_errc(&test_connection::start_execution), "sync_errc" },
|
||||
{netfun_maker::sync_exc(&test_connection::start_execution), "sync_exc" },
|
||||
{netfun_maker::async_errinfo(&test_connection::async_start_execution), "async_errinfo" },
|
||||
{netfun_maker::async_noerrinfo(&test_connection::async_start_execution), "async_noerrinfo"},
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(success)
|
||||
{
|
||||
for (auto fns : all_fns)
|
||||
{
|
||||
BOOST_TEST_CONTEXT(fns.name)
|
||||
{
|
||||
auto st = create_initial_state();
|
||||
auto stmt = create_the_statement();
|
||||
test_connection conn;
|
||||
conn.stream().add_message(ok_msg_builder().seqnum(1).affected_rows(50).info("1st").build_ok());
|
||||
|
||||
// Call the function
|
||||
fns.start_execution(conn, stmt.bind("test", nullptr), st).validate_no_error();
|
||||
|
||||
// Verify the message we sent
|
||||
BOOST_MYSQL_ASSERT_BLOB_EQUALS(conn.stream().bytes_written(), execute_stmt_msg);
|
||||
|
||||
// Verify the results
|
||||
BOOST_TEST(get_impl(st).encoding() == resultset_encoding::binary);
|
||||
BOOST_TEST_REQUIRE(st.complete());
|
||||
BOOST_TEST(get_impl(st).sequence_number() == 2u);
|
||||
BOOST_TEST(st.meta().size() == 0u);
|
||||
BOOST_TEST(st.affected_rows() == 50u);
|
||||
BOOST_TEST(st.info() == "1st");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(error_wrong_num_params)
|
||||
{
|
||||
for (auto fns : all_fns)
|
||||
{
|
||||
BOOST_TEST_CONTEXT(fns.name)
|
||||
{
|
||||
execution_state st;
|
||||
auto stmt = statement_builder().id(1).num_params(3).build();
|
||||
test_connection conn;
|
||||
|
||||
// Call the function
|
||||
fns.start_execution(conn, stmt.bind("test", nullptr), st)
|
||||
.validate_error_exact(client_errc::wrong_num_params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that we correctly perform a decay-copy of the parameters and the
|
||||
// statement handle, relevant for deferred tokens
|
||||
#ifdef BOOST_ASIO_HAS_CO_AWAIT
|
||||
BOOST_AUTO_TEST_CASE(deferred_lifetimes_rvalues)
|
||||
{
|
||||
run_coroutine([]() -> boost::asio::awaitable<void> {
|
||||
execution_state st;
|
||||
test_connection conn;
|
||||
conn.stream().add_message(ok_msg_builder().seqnum(1).info("1st").build_ok());
|
||||
|
||||
// Deferred op. Execution request is a temporary
|
||||
auto aw = conn.async_start_execution(
|
||||
create_the_statement().bind(std::string("test"), nullptr),
|
||||
st,
|
||||
boost::asio::use_awaitable
|
||||
);
|
||||
co_await std::move(aw);
|
||||
|
||||
// verify that the op had the intended effects
|
||||
BOOST_MYSQL_ASSERT_BLOB_EQUALS(conn.stream().bytes_written(), execute_stmt_msg);
|
||||
BOOST_TEST(st.info() == "1st");
|
||||
});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(deferred_lifetimes_lvalues)
|
||||
{
|
||||
run_coroutine([]() -> boost::asio::awaitable<void> {
|
||||
execution_state st;
|
||||
test_connection conn;
|
||||
conn.stream().add_message(ok_msg_builder().seqnum(1).info("1st").build_ok());
|
||||
boost::asio::awaitable<void> aw;
|
||||
|
||||
// Deferred op
|
||||
{
|
||||
const auto stmt = create_the_statement();
|
||||
const auto req = stmt.bind(std::string("test"), nullptr);
|
||||
aw = conn.async_start_execution(req, st, boost::asio::use_awaitable);
|
||||
}
|
||||
|
||||
co_await std::move(aw);
|
||||
|
||||
// verify that the op had the intended effects
|
||||
BOOST_MYSQL_ASSERT_BLOB_EQUALS(conn.stream().bytes_written(), execute_stmt_msg);
|
||||
BOOST_TEST(st.info() == "1st");
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
//
|
||||
// ------- start_statement_execution (iterator, legacy) ---------
|
||||
//
|
||||
BOOST_AUTO_TEST_SUITE(start_statement_execution_it_legacy)
|
||||
|
||||
using netfun_maker = netfun_maker_mem<
|
||||
void,
|
||||
@ -541,6 +884,80 @@ BOOST_AUTO_TEST_CASE(deferred_lifetimes)
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
//
|
||||
// ------- start_statement_execution (iterator) ---------
|
||||
//
|
||||
BOOST_AUTO_TEST_SUITE(start_statement_execution_it)
|
||||
|
||||
using netfun_maker = netfun_maker_mem<
|
||||
void,
|
||||
test_connection,
|
||||
const bound_statement_iterator_range<field_view*>&,
|
||||
execution_state&>;
|
||||
|
||||
struct
|
||||
{
|
||||
netfun_maker::signature start_execution;
|
||||
const char* name;
|
||||
} all_fns[] = {
|
||||
{netfun_maker::sync_errc(&test_connection::start_execution), "sync_errc" },
|
||||
{netfun_maker::sync_exc(&test_connection::start_execution), "sync_exc" },
|
||||
{netfun_maker::async_errinfo(&test_connection::async_start_execution), "async_errinfo" },
|
||||
{netfun_maker::async_noerrinfo(&test_connection::async_start_execution), "async_noerrinfo"},
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(success)
|
||||
{
|
||||
for (auto fns : all_fns)
|
||||
{
|
||||
BOOST_TEST_CONTEXT(fns.name)
|
||||
{
|
||||
auto st = create_initial_state();
|
||||
auto stmt = create_the_statement();
|
||||
test_connection conn;
|
||||
conn.stream().add_message(ok_msg_builder().seqnum(1).affected_rows(50).info("1st").build_ok());
|
||||
|
||||
// Call the function
|
||||
auto fields = make_fv_arr("test", nullptr);
|
||||
fns.start_execution(conn, stmt.bind(fields.data(), fields.data() + fields.size()), st)
|
||||
.validate_no_error();
|
||||
|
||||
// Verify the message we sent
|
||||
BOOST_MYSQL_ASSERT_BLOB_EQUALS(conn.stream().bytes_written(), execute_stmt_msg);
|
||||
|
||||
// Verify the results
|
||||
BOOST_TEST(get_impl(st).encoding() == resultset_encoding::binary);
|
||||
BOOST_TEST(st.complete());
|
||||
BOOST_TEST(get_impl(st).sequence_number() == 2u);
|
||||
BOOST_TEST(st.meta().size() == 0u);
|
||||
BOOST_TEST(st.affected_rows() == 50u);
|
||||
BOOST_TEST(st.info() == "1st");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(error_wrong_num_params)
|
||||
{
|
||||
for (auto fns : all_fns)
|
||||
{
|
||||
BOOST_TEST_CONTEXT(fns.name)
|
||||
{
|
||||
execution_state st;
|
||||
auto stmt = statement_builder().id(1).num_params(3).build();
|
||||
test_connection conn;
|
||||
|
||||
// Call the function
|
||||
auto fields = make_fv_arr("test", nullptr);
|
||||
fns.start_execution(conn, stmt.bind(fields.data(), fields.data() + fields.size()), st)
|
||||
.validate_error_exact(client_errc::wrong_num_params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No need to test for decay copies again here, already tested
|
||||
// in the tuple version.
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
} // namespace
|
@ -12,7 +12,7 @@
|
||||
#include <boost/mysql/error_code.hpp>
|
||||
#include <boost/mysql/field_view.hpp>
|
||||
|
||||
#include <boost/mysql/detail/network_algorithms/start_execution.hpp>
|
||||
#include <boost/mysql/detail/network_algorithms/start_execution_impl.hpp>
|
||||
#include <boost/mysql/detail/protocol/constants.hpp>
|
||||
#include <boost/mysql/detail/protocol/execution_state_impl.hpp>
|
||||
#include <boost/mysql/detail/protocol/resultset_encoding.hpp>
|
||||
@ -47,8 +47,8 @@ struct
|
||||
typename netfun_maker::signature start_execution;
|
||||
const char* name;
|
||||
} all_fns[] = {
|
||||
{netfun_maker::sync_errc(&boost::mysql::detail::start_execution), "sync" },
|
||||
{netfun_maker::async_errinfo(&boost::mysql::detail::async_start_execution), "async"}
|
||||
{netfun_maker::sync_errc(&boost::mysql::detail::start_execution_impl), "sync" },
|
||||
{netfun_maker::async_errinfo(&boost::mysql::detail::async_start_execution_impl), "async"}
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(test_start_execution)
|
@ -32,22 +32,22 @@ using detail::protocol_field_type;
|
||||
|
||||
namespace {
|
||||
|
||||
using start_query_netm = netfun_maker_mem<void, test_connection, string_view, execution_state&>;
|
||||
using start_query_netm = netfun_maker_mem<void, test_connection, const string_view&, execution_state&>;
|
||||
using read_resultset_head_netm = netfun_maker_mem<void, test_connection, execution_state&>;
|
||||
using read_some_rows_netm = netfun_maker_mem<rows_view, test_connection, execution_state&>;
|
||||
|
||||
struct
|
||||
{
|
||||
start_query_netm::signature start_query;
|
||||
start_query_netm::signature start_execution;
|
||||
read_resultset_head_netm::signature read_resultset_head;
|
||||
read_some_rows_netm::signature read_some_rows;
|
||||
const char* name;
|
||||
} all_fns[] = {
|
||||
{start_query_netm::sync_errc(&test_connection::start_query),
|
||||
{start_query_netm::sync_errc(&test_connection::start_execution),
|
||||
read_resultset_head_netm::sync_errc(&test_connection::read_resultset_head),
|
||||
read_some_rows_netm::sync_errc(&test_connection::read_some_rows),
|
||||
"sync" },
|
||||
{start_query_netm::async_errinfo(&test_connection::async_start_query),
|
||||
{start_query_netm::async_errinfo(&test_connection::async_start_execution),
|
||||
read_resultset_head_netm::async_errinfo(&test_connection::async_read_resultset_head),
|
||||
read_some_rows_netm::async_errinfo(&test_connection::async_read_some_rows),
|
||||
"async"},
|
||||
@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE(separate_batches)
|
||||
));
|
||||
|
||||
// Start
|
||||
fns.start_query(conn, "SELECT 1", st).validate_no_error();
|
||||
fns.start_execution(conn, "SELECT 1", st).validate_no_error();
|
||||
BOOST_TEST_REQUIRE(st.should_read_rows());
|
||||
check_meta(st.meta(), {column_type::varchar});
|
||||
|
||||
@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(single_read)
|
||||
conn.stream().add_message(std::move(msgs));
|
||||
|
||||
// Start
|
||||
fns.start_query(conn, "SELECT 1", st).validate_no_error();
|
||||
fns.start_execution(conn, "SELECT 1", st).validate_no_error();
|
||||
BOOST_TEST_REQUIRE(st.should_read_rows());
|
||||
check_meta(st.meta(), {column_type::varchar});
|
||||
|
||||
@ -188,7 +188,7 @@ BOOST_AUTO_TEST_CASE(empty_resultsets)
|
||||
conn.stream().add_message(std::move(msgs));
|
||||
|
||||
// Start
|
||||
fns.start_query(conn, "SELECT 1", st).validate_no_error();
|
||||
fns.start_execution(conn, "SELECT 1", st).validate_no_error();
|
||||
BOOST_TEST_REQUIRE(st.should_read_head());
|
||||
BOOST_TEST(st.meta().size() == 0u);
|
||||
BOOST_TEST(st.affected_rows() == 10u);
|
||||
|
@ -5,15 +5,18 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <boost/mysql/field_view.hpp>
|
||||
#include <boost/mysql/statement.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include "creation/create_statement.hpp"
|
||||
#include "test_common.hpp"
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
using boost::mysql::statement;
|
||||
using namespace boost::mysql;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -34,6 +37,84 @@ BOOST_AUTO_TEST_CASE(member_fns)
|
||||
BOOST_TEST(stmt.id() == 1u);
|
||||
}
|
||||
|
||||
statement create_valid_stmt() { return statement_builder().id(1).build(); }
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(bind_field_like)
|
||||
BOOST_AUTO_TEST_CASE(regular)
|
||||
{
|
||||
std::string s("def");
|
||||
blob blb;
|
||||
auto b = create_valid_stmt().bind(42, std::string("abc"), std::ref(s), s, blb);
|
||||
using tup_type = std::tuple<int, std::string, std::string&, std::string, blob>;
|
||||
static_assert(std::is_same<decltype(b), bound_statement_tuple<tup_type>>::value, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(empty)
|
||||
{
|
||||
auto b = create_valid_stmt().bind();
|
||||
static_assert(std::is_same<decltype(b), bound_statement_tuple<std::tuple<>>>::value, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stmt_const)
|
||||
{
|
||||
const statement stmt = create_valid_stmt();
|
||||
auto b = stmt.bind(); // compiles
|
||||
static_assert(std::is_same<decltype(b), bound_statement_tuple<std::tuple<>>>::value, "");
|
||||
}
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(bind_field_like_tuple)
|
||||
BOOST_AUTO_TEST_CASE(regular)
|
||||
{
|
||||
auto b = create_valid_stmt().bind(std::make_tuple(42, 4.2f));
|
||||
using expected_type = bound_statement_tuple<std::tuple<int, float>>;
|
||||
static_assert(std::is_same<decltype(b), expected_type>::value, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(tuple_const_reference)
|
||||
{
|
||||
const auto params = std::make_tuple(42, 4.2f);
|
||||
auto b = create_valid_stmt().bind(params);
|
||||
using expected_type = bound_statement_tuple<std::tuple<int, float>>;
|
||||
static_assert(std::is_same<decltype(b), expected_type>::value, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(tuple_reference)
|
||||
{
|
||||
auto params = std::make_tuple(42, 4.2f);
|
||||
auto b = create_valid_stmt().bind(params);
|
||||
using expected_type = bound_statement_tuple<std::tuple<int, float>>;
|
||||
static_assert(std::is_same<decltype(b), expected_type>::value, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stmt_const)
|
||||
{
|
||||
const statement stmt = create_valid_stmt();
|
||||
auto b = stmt.bind(std::make_tuple(42)); // compiles
|
||||
using expected_type = bound_statement_tuple<std::tuple<int>>;
|
||||
static_assert(std::is_same<decltype(b), expected_type>::value, "");
|
||||
}
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(bind_iterator_range)
|
||||
BOOST_AUTO_TEST_CASE(regular)
|
||||
{
|
||||
auto fvs = make_fv_arr(42, "abc");
|
||||
auto b = create_valid_stmt().bind(fvs.begin(), fvs.end());
|
||||
using expected_type = bound_statement_iterator_range<std::array<field_view, 2>::iterator>;
|
||||
static_assert(std::is_same<decltype(b), expected_type>::value, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stmt_const)
|
||||
{
|
||||
const statement stmt = create_valid_stmt();
|
||||
auto fvs = make_fv_arr(42, "abc");
|
||||
auto b = stmt.bind(fvs.begin(), fvs.end()); // compiles
|
||||
using expected_type = bound_statement_iterator_range<std::array<field_view, 2>::iterator>;
|
||||
static_assert(std::is_same<decltype(b), expected_type>::value, "");
|
||||
}
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
} // namespace
|
||||
|
Loading…
x
Reference in New Issue
Block a user