Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Tutorial 4: the static interface

Until now we've read the rows generated by our queries into results objects. As we've seen, results is a 2D structure that contains variant-like values. Throughout the documentation, these variant-based APIs are called the dynamic interface.

Dynamic interface limitations

Working with variant-like objects can be cumbersome. Recall the following lines from our previous tutorial, where we used the retrieved rows:

// Did we find an employee with that ID?
if (result.rows().empty())
{
    std::cout << "Employee not found" << std::endl;
}
else
{
    // Print the retrieved details. The first field is the first name,
    // and the second, the last name.
    mysql::row_view employee = result.rows().at(0);
    std::cout << "Employee's name is: " << employee.at(0) << ' ' << employee.at(1) << std::endl;
}

An employee is represented here by a row_view, which is a collection of field_view objects. field_view is a variant-like type that can represent all the types supported by MySQL.

Since field_view supports streaming, this code doesn't require any casting. However, consider refactoring our code to split the printing logic to a separate function:

void print_employee(std::string_view first_name, std::string_view last_name)
{
    std::cout << "Employee's name is: " << first_name << ' ' << last_name << std::endl;
}

Looking at our database schema, we know that both values are strings. We can use field_view::as_string to perform the casts:

mysql::row_view employee = result.rows().at(0);
print_employee(employee.at(0).as_string(), employee.at(1).as_string());

While this code works, it can create maintenance problems:

If we know the types returned by our queries at compile time, we can use the static interface, instead. This interface can parse the rows returned by a query into instances of a C++ struct defined by us.

[Note] Note

The static interface requires C++14 or later.

Using static_results with Boost.Pfr

In C++20 and later, we can use Boost.Pfr and the static_results class to parse the rows. The first step is to define a plain C++ struct with the fields we expect in our query:

// Should contain a member for each field of interest present in our query.
// Declaration order doesn't need to match field order in the query.
// Field names should match the ones in our query
struct employee
{
    std::string first_name;
    std::string last_name;
};

We now replace the results object by a static_results. The marker type pfr_by_name indicates Boot.MySQL that it should use Boost.Pfr for reflection.

// Using static_results will parse the result of our query
// into instances of the employee type. Fields will be matched
// by name, instead of by position.
// pfr_by_name tells the library to use Boost.Pfr for reflection,
// and to match fields by name.
mysql::static_results<mysql::pfr_by_name<employee>> result;

// Execute the query with the given parameters, performing the required
// escaping to prevent SQL injection.
co_await conn.async_execute(
    mysql::with_params("SELECT first_name, last_name FROM employee WHERE id = {}", employee_id),
    result
);

Using the retrieved data is now much easier, since static_results::rows returns a span<const employee>:

// Did we find an employee with that ID?
if (result.rows().empty())
{
    std::cout << "Employee not found" << std::endl;
}
else
{
    // Print the retrieved details
    const employee& emp = result.rows()[0];
    print_employee(emp.first_name, emp.last_name);
}

When using the static interface, async_execute will perform a set of checks on the query results to ensure compatibility between the C++ types and what MySQL returns. These checks aim to discover potential problems as early as possible, and are called metadata checks.

Using the static interface in C++14

C++20 makes it possible to use Boost.Pfr as described here, which is the easiest option. Boost.MySQL also supports Boost.Describe and std::tuple's, which can be used in C++14. The mechanics are quite similar to what's been explained here.

Wrapping up

This section contains more information about the static interface.

Full program listing for this tutorial is here.

You can now proceed to the next tutorial.


PrevUpHomeNext