Skip to content

Commit f6c1192

Browse files
authored
Boost 1.87: new discussion and examples (part 1)
Added tutorials 2, 3 and 4 Changed most of the discussion to use any_connection Added examples on disabling TLS, multi-function operations, multi-queries and transactions All examples now use any_connection Automate parts of example qbk generation Partially addresses #365 and #366
1 parent c57103b commit f6c1192

File tree

101 files changed

+6058
-6738
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+6058
-6738
lines changed

doc/qbk/00_main.qbk

Lines changed: 69 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
[library Boost.MySQL
99
[quickbook 1.7]
10-
[copyright 2019 - 2023 Ruben Perez]
10+
[copyright 2019 - 2024 Ruben Perez]
1111
[id mysql]
1212
[purpose MySQL client library]
1313
[license
@@ -56,16 +56,16 @@
5656
[def __Context__ [@boost:/libs/context/index.html Boost.Context]]
5757
[def __Self__ [@boost:/libs/mysql/index.html Boost.MySQL]]
5858
[def __boost_optional__ [@boost:/libs/optional/index.html `boost::optional`]]
59-
[def __see_error_handling__ See [link mysql.error_handling this section] for more info on error handling.]
60-
[def __assume_setup__ This example assumes you have gone through the [link mysql.examples.setup setup].]
59+
[def __Describe__ [@boost:/libs/describe/index.html Boost.Describe]]
60+
[def __Pfr__ [@boost:/libs/pfr/index.html Boost.Pfr]]
61+
[def __ssl_context__ [asioreflink ssl__context ssl::context]]
6162

6263
[/ MySQL stuff]
6364
[def __Mysql__ [@https://www.mysql.com/ MySQL]]
6465
[def __sql_mode__ [mysqllink sql-mode.html `sql_mode`]]
6566
[def __allow_invalid_dates__ [mysqllink sql-mode.html#sqlmode_allow_invalid_dates `ALLOW_INVALID_DATES`]]
6667
[def __strict_sql__ [mysqllink sql-mode.html#sql-mode-strict strict SQL mode]]
6768
[def __time_zone__ [mysqllink server-system-variables.html#sysvar_time_zone `time_zone`]]
68-
[def __SET_NAMES__ [mysqllink set-names.html `SET NAMES`]]
6969
[def __TINYINT__ [mysqllink integer-types.html `TINYINT`]]
7070
[def __SMALLINT__ [mysqllink integer-types.html `SMALLINT`]]
7171
[def __MEDIUMINT__ [mysqllink integer-types.html `MEDIUMINT`]]
@@ -124,47 +124,80 @@ BEGIN
124124
END
125125
```]
126126

127-
[import ../../test/integration/include/test_integration/snippets/describe.hpp]
128-
[import ../../test/integration/test/snippets/overview.cpp]
129-
[import ../../test/integration/test/snippets/dynamic.cpp]
130-
[import ../../test/integration/test/snippets/static.cpp]
127+
[/ AUTOGENERATED IMPORTS BEGIN ]
128+
[import ../../example/1_tutorial/1_sync.cpp]
129+
[import ../../example/1_tutorial/2_async.cpp]
130+
[import ../../example/1_tutorial/3_with_params.cpp]
131+
[import ../../example/1_tutorial/4_static_interface.cpp]
132+
[import ../../example/2_simple/prepared_statements.cpp]
133+
[import ../../example/2_simple/timeouts.cpp]
134+
[import ../../example/2_simple/multi_queries_transactions.cpp]
135+
[import ../../example/2_simple/disable_tls.cpp]
136+
[import ../../example/2_simple/tls_certificate_verification.cpp]
137+
[import ../../example/2_simple/metadata.cpp]
138+
[import ../../example/2_simple/multi_function.cpp]
139+
[import ../../example/2_simple/callbacks.cpp]
140+
[import ../../example/2_simple/coroutines_cpp11.cpp]
141+
[import ../../example/2_simple/unix_socket.cpp]
142+
[import ../../example/2_simple/batch_inserts.cpp]
143+
[import ../../example/2_simple/batch_inserts_generic.cpp]
144+
[import ../../example/2_simple/dynamic_filters.cpp]
145+
[import ../../example/2_simple/patch_updates.cpp]
146+
[import ../../example/2_simple/source_script.cpp]
147+
[import ../../example/2_simple/pipeline.cpp]
148+
[import ../../example/3_advanced/connection_pool/main.cpp]
149+
[import ../../example/3_advanced/connection_pool/types.hpp]
150+
[import ../../example/3_advanced/connection_pool/repository.hpp]
151+
[import ../../example/3_advanced/connection_pool/repository.cpp]
152+
[import ../../example/3_advanced/connection_pool/handle_request.hpp]
153+
[import ../../example/3_advanced/connection_pool/handle_request.cpp]
154+
[import ../../example/3_advanced/connection_pool/server.hpp]
155+
[import ../../example/3_advanced/connection_pool/server.cpp]
156+
[import ../../example/3_advanced/connection_pool/log_error.hpp]
131157
[import ../../test/integration/test/snippets/prepared_statements.cpp]
132-
[import ../../test/integration/test/snippets/multi_resultset.cpp]
158+
[import ../../test/integration/test/snippets/connection_establishment.cpp]
159+
[import ../../test/integration/test/snippets/charsets.cpp]
160+
[import ../../test/integration/test/snippets/sql_formatting_custom.cpp]
133161
[import ../../test/integration/test/snippets/multi_function.cpp]
162+
[import ../../test/integration/test/snippets/tutorials.cpp]
134163
[import ../../test/integration/test/snippets/metadata.cpp]
135-
[import ../../test/integration/test/snippets/charsets.cpp]
136-
[import ../../test/integration/test/snippets/time_types.cpp]
137-
[import ../../test/integration/test/snippets/any_connection.cpp]
138164
[import ../../test/integration/test/snippets/connection_pool.cpp]
139-
[import ../../test/integration/test/snippets/sql_formatting.cpp]
140-
[import ../../test/integration/test/snippets/sql_formatting_custom.cpp]
165+
[import ../../test/integration/test/snippets/time_types.cpp]
141166
[import ../../test/integration/test/snippets/pipeline.cpp]
167+
[import ../../test/integration/test/snippets/sql_formatting.cpp]
168+
[import ../../test/integration/test/snippets/overview.cpp]
169+
[import ../../test/integration/test/snippets/dynamic.cpp]
170+
[import ../../test/integration/test/snippets/multi_resultset.cpp]
171+
[import ../../test/integration/test/snippets/static.cpp]
172+
[/ AUTOGENERATED IMPORTS END ]
173+
[import ../../test/integration/include/test_integration/snippets/describe.hpp]
142174

143175
[include 01_intro.qbk]
144176
[include 02_integrating.qbk]
145-
[include 03_tutorial.qbk]
177+
[include 03_1_tutorial_sync.qbk]
178+
[include 03_2_tutorial_async.qbk]
179+
[include 03_3_tutorial_with_params.qbk]
180+
[include 03_4_tutorial_static_interface.qbk]
146181
[include 04_overview.qbk]
147-
[include 05_dynamic_interface.qbk]
148-
[include 06_static_interface.qbk]
149-
[include 07_queries.qbk]
150-
[include 08_prepared_statements.qbk]
151-
[include 09_multi_resultset.qbk]
152-
[include 10_multi_function.qbk]
153-
[include 11_metadata.qbk]
154-
[include 12_async.qbk]
155-
[include 13_ssl.qbk]
156-
[include 14_other_streams.qbk]
157-
[include 15_error_handling.qbk]
158-
[include 16_connparams.qbk]
159-
[include 17_reconnecting.qbk]
160-
[include 18_charsets.qbk]
161-
[include 19_time_types.qbk]
162-
[include 20_any_connection.qbk]
163-
[include 21_connection_pool.qbk]
164-
[include 22_sql_formatting.qbk]
165-
[include 23_sql_formatting_advanced.qbk]
166-
[include 24_pipeline.qbk]
167-
[include 24_examples.qbk]
182+
[include 05_connection_establishment.qbk]
183+
[include 06_sql_formatting.qbk]
184+
[include 07_prepared_statements.qbk]
185+
[include 08_dynamic_interface.qbk]
186+
[include 09_static_interface.qbk]
187+
[include 10_multi_resultset.qbk]
188+
[include 11_multi_function.qbk]
189+
[include 12_connection_pool.qbk]
190+
[include 13_async.qbk]
191+
[include 14_error_handling.qbk]
192+
[include 15_sql_formatting_advanced.qbk]
193+
[include 16_metadata.qbk]
194+
[include 17_charsets.qbk]
195+
[include 18_time_types.qbk]
196+
[/ TODO: re-enable this
197+
[include 19_templated_connection.qbk] ]
198+
[include 20_pipeline.qbk]
199+
[include 21_examples.qbk]
200+
168201

169202

170203
[section:ref Reference]

doc/qbk/02_integrating.qbk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ target_link_libraries(main PRIVATE Boost::charconv Threads::Threads OpenSSL::Cry
4646
an older version, use the `Boost::headers` target, instead.
4747
]
4848

49-
If you're happy with header-only mode, have a look at [link mysql.tutorial the tutorial]
49+
If you're happy with header-only mode, have a look at [link mysql.tutorial_sync the first tutorial]
5050
or [link mysql.examples any of the examples] to learn how to use the library.
5151

5252
[endsect]

doc/qbk/03_1_tutorial_sync.qbk

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
[/
2+
Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
3+
4+
Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
]
7+
8+
[section:tutorial_sync Tutorial 1: hello world!]
9+
10+
In this first tutorial, we will write a simple program
11+
to demonstrate the basic concepts. We will connect to the server
12+
and issue the query `SELECT "Hello World!"`.
13+
14+
To run this tutorial, you need a running MySQL server listening
15+
in localhost on port 3306 (the default one). You should have
16+
the credentials of a valid MySQL user (username and password).
17+
No further setup is needed.
18+
19+
The full program listing for this tutorial can be found [link mysql.examples.tutorial_sync here].
20+
21+
We will follow these steps:
22+
23+
# Create a connection object.
24+
# Establish a session with the server.
25+
# Issue the query.
26+
# Use the rows generated by the query.
27+
# Close the connection.
28+
29+
This tutorial uses synchronous functions with exceptions,
30+
as they're easy to use. In subsequent tutorials, we will
31+
learn how to use asynchronous functions, which are more versatile.
32+
33+
[heading Namespace conventions]
34+
35+
All functions and classes reside within the `boost::mysql` namespace.
36+
To reduce verbosity, all examples and code samples use the following namespace aliases:
37+
38+
[tutorial_sync_namespaces]
39+
40+
41+
42+
43+
[heading Connection object]
44+
45+
Like most Asio-based applications, we need to create a
46+
[asioreflink io_context io_context] object before anything else.
47+
An `io_context` is an execution context: it contains an event loop,
48+
file descriptor states, timers and other items required to perform I/O.
49+
Most applications should only create a single `io_context`, even when
50+
multiple MySQL connections are needed.
51+
52+
We then create an [reflink any_connection], which represents a single connection
53+
to a MySQL server:
54+
55+
[tutorial_sync_connection]
56+
57+
58+
59+
60+
[heading Connecting to the server]
61+
62+
[refmem any_connection connect] establishes a client session with the server.
63+
It takes a [reflink connect_params] object with the required
64+
information to establish a session:
65+
66+
[tutorial_sync_connect]
67+
68+
69+
70+
71+
[heading Issuing the SQL query]
72+
73+
[refmem any_connection execute] accepts a string containing
74+
the SQL query to run and sends it to the server for execution.
75+
It returns a [reflink results] object, containing the rows returned by the query:
76+
77+
[tutorial_sync_query]
78+
79+
80+
81+
82+
[heading Obtaining the results]
83+
84+
[reflink results] is a class that holds the result of a query in memory.
85+
To obtain the value we selected, we can write:
86+
87+
[tutorial_sync_results]
88+
89+
Let's break this into steps:
90+
91+
* [refmem results rows] returns all the rows that this object contains.
92+
It returns a [reflink rows_view], which is a 2D matrix-like structure.
93+
* `result.rows().at(0)` returns the first row, represented as a [reflink row_view].
94+
* `result.rows().at(0).at(0)` returns the first field in the first row. This is a
95+
[reflink field_view], a variant-like class that can hold any type allowed in MySQL.
96+
* The obtained `field_view` is streamed to `std::cout`.
97+
98+
99+
100+
101+
[heading Closing the connection]
102+
103+
Once we are done with the connection, we can close it by calling
104+
[refmem any_connection close]. Note that
105+
this will send a final quit packet to the MySQL server to notify
106+
we are closing the connection, and thus may fail.
107+
108+
[tutorial_sync_close]
109+
110+
111+
112+
113+
[heading Next steps]
114+
115+
Full program listing for this tutorial is [link mysql.examples.tutorial_sync here].
116+
117+
You can now proceed to [link mysql.tutorial_async the next tutorial].
118+
119+
[endsect]

doc/qbk/03_2_tutorial_async.qbk

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
[/
2+
Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
3+
4+
Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
]
7+
8+
[section:tutorial_async Tutorial 2: going async with C++20 coroutines]
9+
10+
In the [link mysql.tutorial_sync previous tutorial] we used
11+
synchronous functions. They are simple, but have a number of limitations:
12+
13+
* They aren't as versatile as async functions. For example, there is no way
14+
to set a timeout to a sync operation.
15+
* They don't scale well. Since sync functions block the calling thread until they complete,
16+
you need to create OS threads to achieve parallelism. This doesn't scale well
17+
and leads to the inherent complexities of multi-threaded programs.
18+
* Some classes (like [reflink connection_pool]) only offer an async interface.
19+
20+
For this reason, we recommend to always use async functions.
21+
All Asio-compatible libraries (including this one) allow async
22+
programming using a variety of styles. In this chapter, we will
23+
explain how to use C++20 coroutines because they are the simplest to use.
24+
25+
[note
26+
Still not using C++20? Don't worry, you can use
27+
[link mysql.examples.coroutines_cpp11 stackful coroutines] and
28+
[link mysql.examples.callbacks callbacks] even in C++11.
29+
]
30+
31+
32+
33+
[heading What is a coroutine?]
34+
35+
Roughly speaking, it's a function that can suspend and resume, keeping local variables
36+
alive in the process. Suspension happens when reaching a `co_await` expression.
37+
These usually appear when the program performs an I/O operation.
38+
When an expression like this is encountered, the following happens:
39+
40+
# The coroutine initiates the I/O operation.
41+
# The coroutine suspends, passing control back to the `io_context` (that is, the event loop).
42+
# While the I/O operation is in progress, the `io_context` may run other operations,
43+
like other coroutines.
44+
# When the I/O operation completes, the `io_context` resumes the coroutine
45+
immediately after the `co_await` expression.
46+
47+
48+
49+
50+
51+
[heading Transforming sync code into coroutines]
52+
53+
Recall the following code from our previous tutorial:
54+
55+
[tutorial_sync_main]
56+
57+
To transform this code into a coroutine, we need to:
58+
59+
* Extract it to a separate function returning `boost::asio::awaitable<void>`.
60+
* Replace sync functions (like [refmem any_connection connect]) by async ones
61+
(like [refmem any_connection async_connect]).
62+
* Place a `co_await` operator in front of each I/O operation.
63+
64+
Doing this, we have:
65+
66+
[tutorial_async_coro]
67+
68+
Note that the coroutine doesn't create or return explicitly any
69+
`boost::asio::awaitable<void>` object - this is handled by the compiler.
70+
The return type actually marks the function as being a coroutine.
71+
`void` here means that the coroutine doesn't return anything.
72+
73+
If any of the above I/O operations fail, an exception is thrown.
74+
You can prevent this by [link mysql.overview.errors using `asio::redirect_error`].
75+
76+
77+
78+
79+
[heading Running our coroutine]
80+
81+
As in the previous tutorial, we first need to create an `io_context` and a connection:
82+
83+
[tutorial_async_connection]
84+
85+
To run a coroutine, use [asioreflink co_spawn co_spawn]:
86+
87+
[tutorial_async_co_spawn]
88+
89+
Note that this will only schedule the coroutine. To actually run
90+
it, we need to call `io_context::run`. This will block the calling
91+
thread until all the scheduled coroutines and I/O operations complete:
92+
93+
[tutorial_async_run]
94+
95+
96+
97+
98+
99+
[heading Next steps]
100+
101+
Full program listing for this tutorial is [link mysql.examples.tutorial_async here].
102+
103+
You can now proceed to [link mysql.tutorial_with_params the next tutorial].
104+
105+
[endsect]

0 commit comments

Comments
 (0)