### Main Implementation: Server Setup and Argument Parsing Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/examples/tutorial_error_handling Parses command-line arguments for database credentials and listener port, initializes an Asio `io_context`, and configures `mysql::pool_params` for establishing database connections. This function serves as the entry point for the server application, setting up the necessary components before starting the listener. ```c++ void main_impl(int argc, char** argv) { if (argc != 5) { std::cerr << "Usage: " << argv[0] << " \n"; exit(1); } const char* username = argv[1]; const char* password = argv[2]; const char* server_hostname = argv[3]; auto listener_port = static_cast(std::stoi(argv[4])); // Create an I/O context, required by all I/O objects asio::io_context ctx; // pool_params contains configuration for the pool. // You must specify enough information to establish a connection, // including the server address and credentials. // You can configure a lot of other things, like pool limits mysql::pool_params params; params.server_address.emplace_host_and_port(server_hostname); params.username = username; params.password = password; } ``` -------------------------------- ### Main Server Setup with Boost.MySQL and Asio Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/tutorial_connection_pool This C++ code outlines the main entry point for a Boost.MySQL server application. It initializes an `asio::io_context`, configures a `mysql::connection_pool` with connection details, and starts the pool's asynchronous run. It also sets up signal handling for graceful shutdown and launches the connection listener coroutine before entering the `io_context::run` loop to start processing events. ```cpp // Create an I/O context, required by all I/O objects asio::io_context ctx; // pool_params contains configuration for the pool. // You must specify enough information to establish a connection, // including the server address and credentials. // You can configure a lot of other things, like pool limits mysql::pool_params params; params.server_address.emplace_host_and_port(server_hostname); params.username = username; params.password = password; params.database = "boost_mysql_examples"; // Construct the pool. // ctx will be used to create the connections and other I/O objects mysql::connection_pool pool(ctx, std::move(params)); // You need to call async_run on the pool before doing anything useful with it. // async_run creates connections and keeps them healthy. It must be called // only once per pool. // The detached completion token means that we don't want to be notified when // the operation ends. It's similar to a no-op callback. pool.async_run(asio::detached); // signal_set is an I/O object that allows waiting for signals asio::signal_set signals(ctx, SIGINT, SIGTERM); // Wait for signals signals.async_wait([&](boost::system::error_code, int) { // Stop the execution context. This will cause io_context::run to return ctx.stop(); }); // Launch our listener asio::co_spawn( ctx, [&pool, listener_port] { return listener(pool, listener_port); }, // If any exception is thrown in the coroutine body, rethrow it. [](std::exception_ptr ptr) { if (ptr) { std::rethrow_exception(ptr); } } ); // Calling run will actually execute the coroutine until completion ctx.run(); ``` -------------------------------- ### Boost.MySql Connection Pool Server Example Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/examples/tutorial_connection_pool This C++ example demonstrates a server using boost::mysql::connection_pool to manage database connections for a custom TCP protocol. It retrieves employee details based on an ID and handles client sessions. Dependencies include Boost.MySql, Boost.Asio, Boost.Endian, and C++20 features. It expects a 'boost_mysql_examples' database and handles requests for employee names. ```cpp /** * This example demonstrates how to use connection_pool * to implement a server for a simple custom TCP-based protocol. * It also demonstrates how to set timeouts with asio::cancel_after. * * The protocol can be used to retrieve the full name of an * employee, given their ID. It works as follows: * - The client connects. * - The client sends the employee ID, as a big-endian 64-bit signed int. * - The server responds with a string containing the employee full name. * - The connection is closed. * * This tutorial doesn't include proper error handling. * We will build it in the next one. * * It uses Boost.Pfr for reflection, which requires C++20. * You can backport it to C++14 if you need by using Boost.Describe. * It uses C++20 coroutines. If you need, you can backport * it to C++11 by using callbacks, asio::yield_context * or sync functions instead of coroutines. * * This example uses the 'boost_mysql_examples' database, which you * can get by running db_setup.sql. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mysql = boost::mysql; namespace asio = boost::asio; // Should contain a member for each field of interest present in our query struct employee { std::string first_name; std::string last_name; }; // Encapsulates the database access logic. // Given an employee_id, retrieves the employee details to be sent to the client. asio::awaitable get_employee_details(mysql::connection_pool& pool, std::int64_t employee_id) { // Get a connection from the pool. // This will wait until a healthy connection is ready to be used. // pooled_connection grants us exclusive access to the connection until // the object is destroyed. // Fail the operation if no connection becomes available in the next 20 seconds. mysql::pooled_connection conn = co_await pool.async_get_connection( asio::cancel_after(std::chrono::seconds(1)) ); // Use the connection normally to query the database. // operator-> returns a reference to an any_connection, // so we can apply all what we learnt in previous tutorials mysql::static_results> result; co_await conn->async_execute( mysql::with_params("SELECT first_name, last_name FROM employee WHERE id = ?", employee_id), result ); // Compose the message to be sent back to the client if (result.rows().empty()) { co_return "NOT_FOUND"; } else { const auto& emp = result.rows()[0]; co_return emp.first_name + ' ' + emp.last_name; } // When the pooled_connection is destroyed, the connection is returned // to the pool, so it can be re-used. } asio::awaitable handle_session(mysql::connection_pool& pool, asio::ip::tcp::socket client_socket) { // Read the request from the client. // async_read ensures that the 8-byte buffer is filled, handling partial reads. unsigned char message[8]{}; co_await asio::async_read(client_socket, asio::buffer(message)); // Parse the 64-bit big-endian int into a native int64_t std::int64_t employee_id = boost::endian::load_big_s64(message); // Invoke the database handling logic std::string response = co_await get_employee_details(pool, employee_id); // Write the response back to the client. // async_write ensures that the entire message is written, handling partial writes co_await asio::async_write(client_socket, asio::buffer(response)); // The socket's destructor will close the client connection } asio::awaitable listener(mysql::connection_pool& pool, unsigned short port) { // An object that accepts incoming TCP connections. asio::ip::tcp::acceptor acc(co_await asio::this_coro::executor); // The endpoint where the server will listen. asio::ip::tcp::endpoint listening_endpoint(asio::ip::make_address("0.0.0.0"), port); // Open the acceptor acc.open(listening_endpoint.protocol()); // Allow reusing the local address, so we can restart our server // without encountering errors in bind acc.set_option(asio::ip::tcp::acceptor::reuse_address(true)); acc.bind(listening_endpoint); acc.listen(); while (true) { // Wait for a client to connect. asio::ip::tcp::socket client_socket = co_await acc.async_accept(); // Spawn a new coroutine to handle the client session. // detached ensures that the coroutine runs independently, and we don't // need to wait for it to complete before accepting the next connection. asio::co_spawn(acc.get_executor(), handle_session(pool, std::move(client_socket)), asio::detached); } } ``` -------------------------------- ### Boost.MySQL Pipeline: Execute Stage Examples Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/pipeline Provides examples of using `pipeline_request::add_execute` and `pipeline_request::add_execute_range` in Boost.MySQL. It shows how to execute text queries, prepared statements with known parameter counts, and prepared statements with an unknown number of parameters, mirroring `any_connection::execute` behavior. ```cpp // Text query req.add_execute("SELECT 1"); // Prepared statement, with number of parameters known at compile time req.add_execute(stmt, "John", "Doe", 42); // Prepared statement, with number of parameters unknown at compile time std::vector params{ /* ... */ }; req.add_execute_range(stmt, params); ``` -------------------------------- ### TCP Server Listener Setup Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/examples/tutorial_error_handling Sets up a TCP acceptor to listen for incoming connections on a specified port. It configures the acceptor to allow address reuse, binds it to the local endpoint, and starts listening. The function then enters an infinite loop to continuously accept new connections. ```c++ asio::awaitable listener(mysql::connection_pool& pool, unsigned short port) { // An object that accepts incoming TCP connections. asio::ip::tcp::acceptor acc(co_await asio::this_coro::executor); // The endpoint where the server will listen. asio::ip::tcp::endpoint listening_endpoint(asio::ip::make_address("0.0.0.0"), port); // Open the acceptor acc.open(listening_endpoint.protocol()); // Allow reusing the local address, so we can restart our server // without encountering errors in bind acc.set_option(asio::socket_base::reuse_address(true)); // Bind to the local address acc.bind(listening_endpoint); // Start listening for connections acc.listen(); std::cout << "Server listening at " << acc.local_endpoint() << std::endl; // Start the accept loop while (true) { // Accept a new connection auto [ec, sock] = co_await acc.async_accept(asio::as_tuple); if (ec) { log_error("Error accepting connection", ec); co_return; } // Function implementing our session logic. // Take ownership of the socket. // Having this as a named variable workarounds a gcc bug // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107288) auto session_logic = [&pool, s = std::move(sock)]() mutable { return handle_session(pool, std::move(s)); }; // Launch a coroutine that runs our session logic. // We don't co_await this coroutine so we can listen // to new connections while the session is running asio::co_spawn( // Use the same executor as the current coroutine co_await asio::this_coro::executor, // Session logic std::move(session_logic), // Will be called when the coroutine finishes [](std::exception_ptr ptr) { if (ptr) { // For extra safety, log the exception but don't propagate it. // If we failed to anticipate an error condition that ends up raising an exception, // terminate only the affected session, instead of crashing the server. try { std::rethrow_exception(ptr); } catch (const std::exception& exc) { std::cerr << "Uncaught error in a session: " << exc.what() << std::endl; } } } ); } } ``` -------------------------------- ### C++ Boost.MySQL Dynamic UPDATE Query Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/examples/patch_updates This C++ example demonstrates dynamic UPDATE queries with PATCH-like semantics using client-side SQL formatting with Boost.MySQL. It parses command-line arguments to specify which fields of an employee record to update, constructs the SQL query dynamically, and executes it. The example utilizes C++20 coroutines and requires the 'boost_mysql_examples' database setup. ```cpp /** * This example demonstrates how to implement dynamic updates * with PATCH-like semantics using client-side SQL formatting. * * The program updates an employee by ID, modifying fields * as provided by command-line arguments, and leaving all other * fields unmodified. * * This example uses C++20 coroutines. If you need, you can backport * it to C++14 (required by Boost.Describe) by using callbacks, asio::yield_context * or sync functions instead of coroutines. * * This example uses the 'boost_mysql_examples' database, which you * can get by running db_setup.sql. */ #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mysql = boost::mysql; namespace asio = boost::asio; /** * Represents a single update as a name, value pair. * The idea is to use command-line arguments to compose * a std::vector with the fields to be updated, * and use mysql::sequence() to join these with commas */ struct update_field { // The field name to set (i.e. the column name) std::string_view field_name; // The value to set the field to. Recall that field_view is // a variant-like type that can hold all types that MySQL supports. mysql::field_view field_value; }; // Contains the parsed command-line arguments struct cmdline_args { // MySQL username to use during authentication. std::string_view username; // MySQL password to use during authentication. std::string_view password; // Hostname where the MySQL server is listening. std::string_view server_hostname; // The ID of the employee we want to update. std::int64_t employee_id{}; // A list of name, value pairs containing the employee fields to update. std::vector updates; }; // Parses the command line arguments, calling exit on failure. static cmdline_args parse_cmdline_args(int argc, char** argv) { // Available options constexpr std::string_view company_id_prefix = "--company-id="; constexpr std::string_view first_name_prefix = "--first-name="; constexpr std::string_view last_name_prefix = "--last-name="; constexpr std::string_view salary_prefix = "--salary="; // Helper function to print the usage message and exit auto print_usage_and_exit = [argv]() { std::cerr << "Usage: " << argv[0] << " employee_id [updates]\n"; exit(1); }; // Check number of arguments if (argc <= 5) print_usage_and_exit(); // Parse the required arguments cmdline_args res; res.username = argv[1]; res.password = argv[2]; res.server_hostname = argv[3]; res.employee_id = std::stoll(argv[4]); // Parse the requested updates for (int i = 5; i < argc; ++i) { // Get the argument std::string_view arg = argv[i]; // Attempt to match it with the options we have if (arg.starts_with(company_id_prefix)) { std::string_view new_value = arg.substr(company_id_prefix.size()); res.updates.push_back(update_field{"company_id", mysql::field_view(new_value)}); } else if (arg.starts_with(first_name_prefix)) { std::string_view new_value = arg.substr(first_name_prefix.size()); res.updates.push_back(update_field{"first_name", mysql::field_view(new_value)}); } else if (arg.starts_with(last_name_prefix)) { std::string_view new_value = arg.substr(last_name_prefix.size()); res.updates.push_back(update_field{"last_name", mysql::field_view(new_value)}); } else if (arg.starts_with(salary_prefix)) { double new_value = std::stod(std::string(arg.substr(salary_prefix.size()))); res.updates.push_back(update_field{"salary", mysql::field_view(new_value)}); } else { std::cerr << "Unrecognized option: " << arg << std::endl; print_usage_and_exit(); } } // There should be one update, at least if (res.updates.empty()) { std::cerr << "There should be one update, at least\n"; print_usage_and_exit(); } return res; } // The main coroutine asio::awaitable coro_main(const cmdline_args& args) { // Create a connection. // Will use the same executor as the coroutine. mysql::any_connection conn(co_await asio::this_coro::executor); ``` -------------------------------- ### Start SQL Execution Basic - Boost C++ Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/ref/boost__mysql__connection/start_execution Simplified template function overload that starts a SQL execution as a multi-function operation with minimal parameters. Accepts only an ExecutionRequest and ExecutionStateType, suitable for scenarios where error details are not needed or handled through other means. ```cpp template< class _ExecutionRequest_, class _ExecutionStateType_> void start_execution( ExecutionRequest&& req, ExecutionStateType& st); ``` -------------------------------- ### Namespace Aliases for Boost.MySQL and Asio Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/tutorial_sync Defines common namespace aliases for Boost.MySQL and Asio to simplify code readability and reduce verbosity in examples. This is a standard practice when working with these libraries. ```cpp namespace mysql = boost::mysql; namespace asio = boost::asio; ``` -------------------------------- ### Construct `any_connection` with Execution Context and Parameters (C++) Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/ref/boost__mysql__any_connection/any_connection Constructs an `any_connection` object from an execution context and optional parameters. This templated constructor allows for flexible connection setup based on the provided execution context. ```cpp template< class _ExecutionContext_> any_connection( ExecutionContext& ctx, any_connection_params params = {}); ``` -------------------------------- ### Boost.MySQL Connection Pool Setup and Async Run Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/examples/tutorial_error_handling Initializes a Boost.MySQL connection pool with provided context and parameters. It then calls async_run to establish and maintain connections, using asio::detached to ignore completion notifications. ```cpp params.database = "boost_mysql_examples"; // Construct the pool. // ctx will be used to create the connections and other I/O objects mysql::connection_pool pool(ctx, std::move(params)); // You need to call async_run on the pool before doing anything useful with it. // async_run creates connections and keeps them healthy. It must be called // only once per pool. // The detached completion token means that we don't want to be notified when // the operation ends. It's similar to a no-op callback. pool.async_run(asio::detached); ``` -------------------------------- ### Launch Coroutine with ASIO I/O Context Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/examples/metadata Demonstrates the entry point for launching the coroutine-based MySQL example. Creates an ASIO I/O context and spawns the main coroutine using asio::co_spawn for asynchronous execution. ```C++ void main_impl(int argc, char** argv) { if (argc != 4) { std::cerr << "Usage: " << argv[0] << " \n"; exit(1); } asio::io_context ctx; asio::co_spawn( ctx ); } ``` -------------------------------- ### Prepare, Execute, and Deallocate Prepared Statements in C++ Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/examples/prepared_statements This C++20 coroutine example demonstrates the complete lifecycle of a prepared statement with Boost.MySQL. It connects to a database, prepares a statement to retrieve employee information based on a company ID, executes the statement securely with parameters, and then deallocates the statement from the server. This approach is beneficial for executing queries multiple times or when dealing with untrusted input. ```cpp /** * This example demonstrates how to prepare, execute * and deallocate prepared statements. This program retrieves * all employees in a company, given its ID. * * It uses C++20 coroutines. If you need, you can backport * it to C++11 by using callbacks, asio::yield_context * or sync functions instead of coroutines. */ #include #include #include #include #include #include #include #include #include #include #include namespace mysql = boost::mysql; namespace asio = boost::asio; void print_employee(mysql::row_view employee) { std::cout << "Employee '" << employee.at(0) << " " // first_name (string) << employee.at(1) << "' earns " // last_name (string) << employee.at(2) << " dollars yearly\n"; // salary (double) } // The main coroutine asio::awaitable coro_main( std::string_view server_hostname, std::string_view username, std::string_view password, std::string_view company_id ) { // Create a connection. It will use the same executor as our coroutine mysql::any_connection conn(co_await asio::this_coro::executor); // The hostname, username, password and database to use mysql::connect_params params; params.server_address.emplace_host_and_port(std::string(server_hostname)); params.username = username; params.password = password; params.database = "boost_mysql_examples"; // Connect to the server co_await conn.async_connect(params); // Prepared statements can be used to execute queries with untrusted // parameters securely. They are an option to mysql::with_params, // but work server-side. // They are more complex but can yield more efficiency when retrieving // lots of numeric data, or when executing the same query several times with the same parameters. // Ask the server to prepare a statement and retrieve its handle mysql::statement stmt = co_await conn.async_prepare_statement( "SELECT first_name, last_name, salary FROM employee WHERE company_id = ?" ); // Execute the statement. bind() must be passed as many parameters (number of ?) // as the statement has. bind() packages the statement handle with the parameters, // and async_execute sends them to the server mysql::results result; co_await conn.async_execute(stmt.bind(company_id), result); for (mysql::row_view employee : result.rows()) print_employee(employee); // We can execute stmt as many times as we want, potentially with different // parameters, without the need to re-prepare it. // Once we're done with a statement, we can close it, to deallocate it from the server. // Closing the connection will also deallocate active statements, so this is not // strictly required here, but it's shown for completeness. // This can be relevant if you're using long-lived sessions. // Note that statement's destructor does NOT close the statement. co_await conn.async_close_statement(stmt); // Notify the MySQL server we want to quit, then close the underlying connection. co_await conn.async_close(); } void main_impl(int argc, char** argv) { if (argc != 5) { std::cerr << "Usage: " << argv[0] << " \n"; exit(1); } // Create an I/O context, required by all I/O objects asio::io_context ctx; // Launch our coroutine asio::co_spawn( ctx, [=] { return coro_main(argv[3], argv[1], argv[2], argv[4]); }, // If any exception is thrown in the coroutine body, rethrow it. [](std::exception_ptr ptr) { if (ptr) { std::rethrow_exception(ptr); } } ); // Calling run will actually execute the coroutine until completion ctx.run(); std::cout << "Done\n"; } int main(int argc, char** argv) { try { main_impl(argc, argv); } catch (const boost::mysql::error_with_diagnostics& err) { // Some errors include additional diagnostics, like server-provided error messages. // Security note: diagnostics::server_message may contain user-supplied values (e.g. the // field value that caused the error) and is encoded using to the connection's character set // (UTF-8 by default). Treat is as untrusted input. std::cerr << "Error: " << err.what() << ", error code: " << err.code() << '\n' << "Server diagnostics: " << err.get_diagnostics().server_message() << std::endl; return 1; } } ``` -------------------------------- ### connection::start_execution Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/ref/boost__mysql__connection/start_execution Starts a SQL execution as a multi-function operation. This function is overloaded to handle different configurations including error codes and diagnostics. ```APIDOC ## connection::start_execution ### Description Starts a SQL execution as a multi-function operation. This overload includes parameters for error codes and diagnostics. ### Method `void` (Conceptual - this is a C++ function, not an HTTP endpoint) ### Endpoint N/A (C++ function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```cpp template void start_execution( ExecutionRequest&& req, ExecutionStateType& st, error_code& err, diagnostics& diag); ``` ### Response #### Success Response N/A (void function) #### Response Example N/A ``` ```APIDOC ## connection::start_execution (Simplified) ### Description Starts a SQL execution as a multi-function operation. This overload provides a simplified interface without explicit error code and diagnostics parameters. ### Method `void` (Conceptual - this is a C++ function, not an HTTP endpoint) ### Endpoint N/A (C++ function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```cpp template void start_execution( ExecutionRequest&& req, ExecutionStateType& st); ``` ### Response #### Success Response N/A (void function) #### Response Example N/A ``` -------------------------------- ### any_connection::connect Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/ref/boost__mysql__any_connection/connect/overload1 Establishes a connection to a MySQL server. This function handles connection setup, including TCP/UNIX socket connection, MySQL handshake, and optional TLS handshake. It also allows configuration through `connect_params`. ```APIDOC ## POST /connect ### Description Establishes a connection to a MySQL server. This function handles connection setup, including TCP/UNIX socket connection, MySQL handshake, and optional TLS handshake. It also allows configuration through `connect_params`. ### Method POST ### Endpoint /connect ### Parameters #### Request Body - **params** (connect_params) - Required - Connection parameters including server address, SSL mode, and collation. - **ec** (error_code&) - Required - An error code object to store any errors encountered during the connection process. - **diag** (diagnostics&) - Required - A diagnostics object to store detailed information about the connection attempt. ### Request Example ```json { "params": { "server_address": { "type": "host_and_port", "host": "localhost", "port": 3306 }, "ssl": "require", "connection_collation": "utf8mb4_general_ci" }, "ec": {}, "diag": {} } ``` ### Response #### Success Response (200) - **void** - Indicates a successful connection. #### Response Example (No response body for a void return type, success is indicated by the absence of an error code.) #### Error Handling - If the connection fails at any step (hostname resolution, socket connection, MySQL handshake, TLS handshake), the TCP or UNIX socket connection is closed and an appropriate error code is set in `ec`. ``` -------------------------------- ### Boost C++ Libraries: connection::async_start_execution Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/ref/boost__mysql__connection/async_start_execution Starts a SQL execution as a multi-function operation. This function can be called with or without a diagnostics object. It utilizes template programming for flexibility with execution requests, states, and completion tokens. ```cpp template< class _ExecutionRequest_, class _ExecutionStateType_, class _CompletionToken_> auto async_start_execution( ExecutionRequest&& req, ExecutionStateType& st, CompletionToken&& token); _» more..._ template< class _ExecutionRequest_, class _ExecutionStateType_, class _CompletionToken_> auto async_start_execution( ExecutionRequest&& req, ExecutionStateType& st, diagnostics& diag, CompletionToken&& token); _» more..._ ``` -------------------------------- ### Configure TLS Certificate Verification with Boost MySQL and ASIO Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/examples/tls_certificate_verification This example sets up TLS certificate verification for MySQL connections using Boost ASIO SSL context. It demonstrates loading a certificate authority, enabling peer verification, and configuring hostname verification before establishing a secure connection. The example uses C++20 coroutines for async operations. ```cpp #include #include #include #include #include #include #include #include #include #include #include #include namespace mysql = boost::mysql; namespace asio = boost::asio; const char CA_PEM[] = R"%(-----BEGIN CERTIFICATE----- MIIDZzCCAk+gAwIBAgIUWznm2UoxXw3j7HCcp9PpiayTvFQwDQYJKoZIhvcNAQEL BQAwQjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDjAMBgNVBAoM BW15c3FsMQ4wDAYDVQQDDAVteXNxbDAgFw0yMDA0MDQxNDMwMjNaGA8zMDE5MDgw NjE0MzAyM1owQjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDjAM BgNVBAoMBW15c3FsMQ4wDAYDVQQDDAVteXNxbDCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAN0WYdvsDb+a0TxOGPejcwZT0zvTrf921mmDUlrLN1Z0hJ/S ydgQCSD7Q+6za4lTFZCXcvs52xvvS2gfC0yXyYLCT/jA4RQRxuF+/+w1gDWEbGk0 KzEpsBuKrEIvEaVdoS78SxInnW/aegshdrRRocp4JQ6KHsZgkLTxSwPfYSUmMUo0 cRO0Q/ak3VK8NP13A6ZFvZjrBxjS3cSw9HqilgADcyj1D4EokvfI1C9LrgwgLlZC XVkjjBqqoMXGGlnXOEK+pm8bU68HM/QvMBkb1Amo8pioNaaYgqJUCP0Ch0iu1nUU HtsWt6emXv0jANgIW0oga7xcT4MDGN/M+IRWLTECAwEAAaNTMFEwHQYDVR0OBBYE FNxhaGwf5ePPhzK7yOAKD3VF6wm2MB8GA1UdIwQYMBaAFNxhaGwf5ePPhzK7yOAK D3VF6wm2MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAoeJCAX IDCFoAaZoQ1niI6Ac/cds8G8It0UCcFGSg+HrZ0YujJxWIruRCUG60Q2OAbEvn0+ uRpTm+4tV1Wt92WFeuRyqkomozx0g4CyfsxGX/x8mLhKPFK/7K9iTXM4/t+xQC4f J+iRmPVsMKQ8YsHYiWVhlOMH9XJQiqERCB2kOKJCH6xkaF2k0GbM2sGgbS7Z6lrd fsFTOIVx0VxLVsZnWX3byE9ghnDR5jn18u30Cpb/R/ShxNUGIHqRa4DkM5la6uZX W1fpSW11JBSUv4WnOO0C2rlIu7UJWOROqZZ0OsybPRGGwagcyff2qVRuI2XFvAMk OzBrmpfHEhF6NDU= -----END CERTIFICATE----- )%"; asio::awaitable coro_main( std::string_view server_hostname, std::string_view username, std::string_view password ) { // Create a SSL context, which contains TLS configuration options asio::ssl::context ssl_ctx(asio::ssl::context::tls_client); // Enable certificate verification ssl_ctx.set_verify_mode(asio::ssl::verify_peer); // Load a trusted CA ssl_ctx.add_certificate_authority(asio::buffer(CA_PEM)); // Set hostname verification ssl_ctx.set_verify_callback(asio::ssl::host_name_verification("mysql")); // Create a connection with SSL context mysql::any_connection conn(co_await asio::this_coro::executor, mysql::any_connection_params{&ssl_ctx}); // Configure connection parameters mysql::connect_params params; params.server_address.emplace_host_and_port(std::string(server_hostname)); params.username = username; params.password = password; params.database = "boost_mysql_examples"; // Connect to the server with certificate verification co_await conn.async_connect(params); // Execute query mysql::results result; co_await conn.async_execute("SELECT 'Hello world!'", result); std::cout << result.rows().at(0).at(0) << std::endl; // Close connection co_await conn.async_close(); } ``` -------------------------------- ### Connect to MySQL Server with Boost.MySQL Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/tutorial_sync Demonstrates how to establish a client session with a MySQL server using `any_connection::connect`. It requires a `connect_params` object to specify server details like hostname, username, and password. ```cpp // The hostname, username and password to use mysql::connect_params params; params.server_address.emplace_host_and_port(hostname); params.username = username; params.password = password; // Connect to the server conn.connect(params); ``` -------------------------------- ### Read MySQL Rows in Batches with C++ Coroutines (Boost.MySQL) Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/examples/multi_function This C++ example shows how to read rows from a MySQL table in batches using Boost.MySQL and C++20 coroutines. It connects to the database, starts a query as a multi-function operation, and then iteratively reads batches of rows until all rows are fetched. The example requires C++20 support and the Boost.MySQL library. It takes server hostname, username, and password as command-line arguments. ```cpp /** * This example demonstrates how to run multi-function operations * to dump an entire table to stdout, reading rows in batches. * * It uses C++20 coroutines. If you need, you can backport * it to C++11 by using callbacks, asio::yield_context * or sync functions instead of coroutines. */ #include #include #include #include #include #include #include #include #include #include namespace mysql = boost::mysql; namespace asio = boost::asio; void print_employee(mysql::row_view employee) { std::cout << "Employee '" << employee.at(0) << " " // first_name (string) << employee.at(1) << "' earns " // last_name (string) << employee.at(2) << " dollars yearly\n"; // salary (double) } // The main coroutine asio::awaitable coro_main( std::string_view server_hostname, std::string_view username, std::string_view password ) { // Create a connection. It will use the same executor as our coroutine mysql::any_connection conn(co_await asio::this_coro::executor); // The hostname, username, password and database to use mysql::connect_params params; params.server_address.emplace_host_and_port(std::string(server_hostname)); params.username = username; params.password = password; params.database = "boost_mysql_examples"; // Connect to the server co_await conn.async_connect(params); // Start our query as a multi-function operation. // This will send the query for execution but won't read the rows. // An execution_state keep tracks of the operation. mysql::execution_state st; co_await conn.async_start_execution("SELECT first_name, last_name, salary FROM employee", st); // st.should_read_rows() returns true while there are more rows to read. // Use async_read_some_rows to read a batch of rows. // This function tries to minimize copies. employees is a view // object pointing into the connection's internal buffers, // and is valid until you start the next async operation. while (st.should_read_rows()) { mysql::rows_view employees = co_await conn.async_read_some_rows(st); for (auto employee : employees) print_employee(employee); } // Notify the MySQL server we want to quit, then close the underlying connection. co_await conn.async_close(); } void main_impl(int argc, char** argv) { if (argc != 4) { std::cerr << "Usage: " << argv[0] << " \n"; exit(1); } // Create an I/O context, required by all I/O objects asio::io_context ctx; // Launch our coroutine asio::co_spawn( ctx, [=] { return coro_main(argv[3], argv[1], argv[2]); }, // If any exception is thrown in the coroutine body, rethrow it. [](std::exception_ptr ptr) { if (ptr) { std::rethrow_exception(ptr); } } ); // Calling run will actually execute the coroutine until completion ctx.run(); std::cout << "Done\n"; } int main(int argc, char** argv) { try { main_impl(argc, argv); } catch (const boost::mysql::error_with_diagnostics& err) { // Some errors include additional diagnostics, like server-provided error messages. // Security note: diagnostics::server_message may contain user-supplied values (e.g. the // field value that caused the error) and is encoded using to the connection's character set // (UTF-8 by default). Treat is as untrusted input. std::cerr << "Error: " << err.what() << ", error code: " << err.code() << '\n' << "Server diagnostics: " << err.get_diagnostics().server_message() << std::endl; return 1; } catch (const std::exception& err) { std::cerr << "Error: " << err.what() << std::endl; return 1; } } ``` -------------------------------- ### Start SQL Execution Asynchronously - C++ Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/ref/boost__mysql__any_connection/async_start_execution Initiates a SQL execution as a multi-function asynchronous operation using `any_connection::async_start_execution`. This function supports different completion token types and an optional diagnostics parameter. It is designed for use with Boost.Asio. ```cpp template< class _ExecutionRequest_, class _ExecutionStateType_, class _CompletionToken_ = with_diagnostics_t> auto async_start_execution( ExecutionRequest&& req, ExecutionStateType& st, CompletionToken&& token = {}); template< class _ExecutionRequest_, class _ExecutionStateType_, class _CompletionToken_ = with_diagnostics_t> auto async_start_execution( ExecutionRequest&& req, ExecutionStateType& st, diagnostics& diag, CompletionToken&& token = {}); ``` -------------------------------- ### Connect and Query MySQL with Boost.MySQL C++ Source: https://www.boost.org/doc/libs/latest/libs/mysql/doc/html/mysql/examples/tutorial_sync This C++ example demonstrates how to establish a connection to a MySQL server, execute a simple 'Hello world!' query, and handle potential errors using exceptions. It utilizes Boost.MySQL and Boost.Asio for asynchronous operations. ```cpp /** * Creates a connection, establishes a session and * runs a simple "Hello world!" query. * * This example uses synchronous functions and handles errors using exceptions. */ #include #include #include #include #include #include namespace mysql = boost::mysql; namespace asio = boost::asio; void main_impl(int argc, char** argv) { if (argc != 4) { std::cerr << "Usage: " << argv[0] << " \n"; exit(1); } const char* hostname = argv[3]; const char* username = argv[1]; const char* password = argv[2]; // The execution context, required to run I/O operations. asio::io_context ctx; // Represents a connection to the MySQL server. mysql::any_connection conn(ctx); // The hostname, username and password to use mysql::connect_params params; params.server_address.emplace_host_and_port(hostname); params.username = username; params.password = password; // Connect to the server conn.connect(params); // Issue the SQL query to the server const char* sql = "SELECT 'Hello world!'"; mysql::results result; conn.execute(sql, result); // Print the first field in the first row std::cout << result.rows().at(0).at(0) << std::endl; // Close the connection conn.close(); } int main(int argc, char** argv) { try { main_impl(argc, argv); } catch (const mysql::error_with_diagnostics& err) { // Some errors include additional diagnostics, like server-provided error messages. // Security note: diagnostics::server_message may contain user-supplied values (e.g. the // field value that caused the error) and is encoded using to the connection's character set // (UTF-8 by default). Treat is as untrusted input. std::cerr << "Error: " << err.what() << '\n' << "Server diagnostics: " << err.get_diagnostics().server_message() << std::endl; return 1; } catch (const std::exception& err) { std::cerr << "Error: " << err.what() << std::endl; return 1; } } ```