<Proposed for> Boost.MySQL (not yet in Boost)
| Linux/OSX | Windows | Coverage | Documentation |
|---|---|---|---|
Boost.Mysql is a C++11 client for the MySQL database server, based on Boost.Asio. This library is in the process of being proposed for Boost.
Documentation and examples are here.
Why another MySQL C++ client?
- It is fully compatible with Boost.Asio and integrates well with any other library in the Boost.Asio ecosystem (like Boost.Beast).
- It supports Boost.Asio's universal asynchronous model, which means you can go asyncrhonous using callbacks, futures or coroutines (including C++20 coroutines).
- It is written in modern C++ (C++11) and takes advantage of the latest language features and standard library additions.
- It is header only.
Building
As this is a header-only library, you do not need to build it. However, as it has a bunch of dependencies, we suggest you use CMake to pull them in as you build your application.
Download Boost.MySQL and make it available to your CMake script (we suggest you use CMake's FetchContent module to do this), and then call add_subdirectory() on the Boost.MySQL root directory. This will look for all the required dependencies.
Finally, link your target against the Boost::mysql interface library, and you will be done!
Requirements
- C++11 capable compiler (tested with gcc 5 to 11, clang 3.6 to 13 and MSVC 19.25).
- Boost.
- OpenSSL.
- CMake 3.13.0 or higher, if using CMake to build against the library (this is the preferred way).
- Tested with MySQL v5.7.29, MySQL v8.0.19, MariaDB v10.3 and MariaDB v10.5.
Versioning and upgrading
The current latest version is 0.1.0. Until Boost.Mysql passes its Boost formal review, the library might get non-backwards-compatible changes between minor versions. Sorry for that! Any breaking change will be listed here, together with a rationale and an upgrade guide. If you encounter any trouble, please open an issue in the repository.
Breaking changes from 0.0.x to 0.1.x
This version has changed the way SSL is handled by the library to a more standard approach, similar to what Boost.Beast and Boost.Asio use. It has also introduced some naming changes. The full list of breaking changes follows:
- The
connectionobject no longer uses SSL/TLS implicitly. To enable SSL/TLS, you must explicitly use aStreamtype supporting SSL/TLS.- Rationale: in 0.0.x,
connectionobjects created a hidden SSL stream on top of the provided stream. This approach is confusing and non-standard, and allowed little control over SSL options to the user. You were probably using SSL without knowing you were. - How to upgrade:
- If you were using
tcp_connectionorunix_connectionand you want to keep using SSL, use the newtcp_ssl_connectionorunix_ssl_connection, instead. You will need to create aboost::asio::ssl::contextand pass it to the connection constructor. All of the examples use SSL, so you can review those. - If you were using
tcp_connectionorunix_connectionand you don't want to use SSL, you don't need to change anything. - If you were directly using the template classes
connection<Stream>orsocket_connection<Stream>, and you want to keep using SSL, you will need to useconnection<boost::asio::ssl::stream<Stream>>, instead. You will need to create aboost::asio::ssl::contextand pass it to the connection constructor. - If you were directly using the template classes
connection<Stream>orsocket_connection<Stream>, and you don't want to use SSL, you don't need to change anything.
- If you were using
- Rationale: in 0.0.x,
- The
ssl_optionsstruct has been removed, in favor of its only member,ssl_mode.- Rationale:
ssl_optionswould eventually include options to be set on thessl::contextthat was implicitly created byconnection. You can now provide assl::contextwith all the options, so this is no longer required. - How to upgrade:
- If you were using the struct
ssl_options(ssl_mode::xxxx)anywhere, replace it byssl_mode::xxxx. - If you were using
connection_params::ssl(), this function now returns an instance ofssl_mode, instead ofssl_options. - Otherwise, you don't need to do anything.
- If you were using the struct
- Rationale:
- The
socket_connectionclass has been removed, and its functionality has been merged intoconnection.- Rationale:
socket_connectionadded complexity with no added value. - How to upgrade: if you were explicitly using
socket_connection<MyStreamType>, replace it byconnection<MyStreamType>. If you were using thetcp_connectionandunix_connectiontype aliases, you don't need to do anything.
- Rationale:
- Type aliases for
connection,prepared_statementandresultsethave moved to separate files.- Rationale: as more type aliases become available, the
connection.hppheader would include more and more unwanted dependencies. - How to upgrade: use the new header files
tcp.hpp,tcp_ssl.hpp,unix.hppandunix_ssl.hpp.
- Rationale: as more type aliases become available, the
- The convenience header
boost/mysql/mysql.hpphas been moved toboost/mysql.hpp.- Rationale: the first path was a mistake, in the first place. All other Boost libs follow the other convention.
- How to upgrade: if you were using the
boost/mysql/mysql.hppheader, replace it byboost/mysql.hpp. Otherwise, you don't need to do anything.
- The
prepared_statement::executeiterator overload has been replaced by an overload taking anexecute_paramsstruct, encapsulating those iterators.- Rationale: this approach is more extensible. When adding further optional parameters to
execute, we don't need to create extra overloads. - How to upgrade: replace
prepared_statement::execute(it1, it2)calls byprepared_statement::execute(make_execute_params(it1, it2)).
- Rationale: this approach is more extensible. When adding further optional parameters to
- The
resultset::fetch_one,resultset::fetch_many,resultset::fetch_allmethods have been renamed toread_one,read_manyandread_all.- Rationale: these functions read rows that the MySQL server has already sent. The term fetch is used in the MySQL protocol to ask the server for extra rows under certain circumstances. We would like to be able to implement this protocol feature in the future without causing massive confusion.
- How to upgrade: apply the renaming.
- There are no longer
rows andowning_rows. Instead, all rows now own the memory for their values and are simply calledrows. Theresultset::read_one(oldresultset::fetch_one) function now takes arowlvalue reference and returns a boolean indicating whether a row was read or not.- Rationale: the old mechanics for
resultset::fetch_onedidn't allow for efficient composition, as the returned row was owned by theresultsetand had to be copied before further reading. With the new approach,read_manyandread_allcan be implemented in terms offetch_one. - How to upgrade: replace loops like
while (const row* r = resultset.fetch_one()) {}byrow r; while (resultset.fetch_one(r))(and their async equivalents).
- Rationale: the old mechanics for
NULLvalues are now represented as a custom typeboost::mysql::null_t(which is an alias forboost::variant2::monostate), instead ofstd::nullptr_t.- Rationale: relational operators like
<don't work forstd::nullptr_tvalues, which means you can't have astd::set<value>.boost::variant2::monostateis the right tool to represent values likeNULL. - How to upgrade:
- If you were using
boost::variant2::visiton the underlying variant returned byvalue::to_variant, you need to add an overload taking anull_tto the visitor function. - If you were using
value::is<std::nullptr_t>, replace it byvalue::is_nullorvalue::is<null_t>.
- If you were using
- Rationale: relational operators like
value::getno longer throwsboost::variant2::bad_variant_access, but a custom exception typeboost::mysql::bad_value_access.- Rationale: it provides finer control over exception handling.
- How to upgrade: if you were catching
boost::variant2::bad_variant_accessas a result of avalue::getcall, replace the exception type in thecatchclause byboost::mysql::bad_value_access.
Features
Currently implemented:
- Text queries (execution of text SQL queries and data retrieval). MySQL refers to this as the "text protocol", as all information is passed using text (as opposed to prepared statements, see below).
- Prepared statements. MySQL refers to this as the "binary protocol", as the result of executing a prepared statement is sent in binary format rather than in text.
- Authentication methods (authentication plugins): mysql_native_password and caching_sha2_password. These are the default methods in MySQL 5 and MySQL 8, respectively.
- Encrypted connections (TLS).
- TCP and UNIX socket connections. The implementation is based on Boost.Asio SyncStream and AsyncStream concepts, so it is generic and can be used with any stream that fulfills these concept's requirements. There are user-friendly typedefs and regression tests for TCP and UNIX socket streams.
Yet to be done (but it is on our list - PRs welcome):
- Further authentication methods: sha256_password
- Multi-resultset: being able to specify several semicolon-separated queries.