From 486bddc8ef227bdc3d7006632d5d354c9e045dbe Mon Sep 17 00:00:00 2001 From: Ruben Perez Date: Fri, 4 Nov 2022 19:08:07 +0100 Subject: [PATCH] Renamed qbks to include ordering --- doc/Jamfile | 2 +- doc/qbk/{main.qbk => 00_main.qbk} | 32 ++-- doc/qbk/{intro.qbk => 01_intro.qbk} | 0 doc/qbk/{tutorial.qbk => 02_tutorial.qbk} | 4 +- doc/qbk/03_concepts.qbk | 87 +++++++++ doc/qbk/{concepts.qbk => 04_values.qbk} | 5 +- doc/qbk/{queries.qbk => 05_queries.qbk} | 0 ...tements.qbk => 06_prepared_statements.qbk} | 0 doc/qbk/{resultsets.qbk => 07_resultsets.qbk} | 0 doc/qbk/{async.qbk => 08_async.qbk} | 0 doc/qbk/{ssl.qbk => 09_ssl.qbk} | 0 ...other_streams.qbk => 10_other_streams.qbk} | 0 ...ror_handling.qbk => 11_error_handling.qbk} | 0 doc/qbk/{connparams.qbk => 12_connparams.qbk} | 0 .../{reconnecting.qbk => 13_reconnecting.qbk} | 0 doc/qbk/{examples.qbk => 14_examples.qbk} | 0 doc/qbk/{types.qbk => 15_types.qbk} | 0 doc/qbk/{tests.qbk => 16_tests.qbk} | 0 doc/qbk/values.qbk | 174 ------------------ example/tutorial.cpp | 3 + tools/scripts/build_docs_local_docker.sh | 1 + 21 files changed, 113 insertions(+), 195 deletions(-) rename doc/qbk/{main.qbk => 00_main.qbk} (92%) rename doc/qbk/{intro.qbk => 01_intro.qbk} (100%) rename doc/qbk/{tutorial.qbk => 02_tutorial.qbk} (96%) create mode 100644 doc/qbk/03_concepts.qbk rename doc/qbk/{concepts.qbk => 04_values.qbk} (80%) rename doc/qbk/{queries.qbk => 05_queries.qbk} (100%) rename doc/qbk/{prepared_statements.qbk => 06_prepared_statements.qbk} (100%) rename doc/qbk/{resultsets.qbk => 07_resultsets.qbk} (100%) rename doc/qbk/{async.qbk => 08_async.qbk} (100%) rename doc/qbk/{ssl.qbk => 09_ssl.qbk} (100%) rename doc/qbk/{other_streams.qbk => 10_other_streams.qbk} (100%) rename doc/qbk/{error_handling.qbk => 11_error_handling.qbk} (100%) rename doc/qbk/{connparams.qbk => 12_connparams.qbk} (100%) rename doc/qbk/{reconnecting.qbk => 13_reconnecting.qbk} (100%) rename doc/qbk/{examples.qbk => 14_examples.qbk} (100%) rename doc/qbk/{types.qbk => 15_types.qbk} (100%) rename doc/qbk/{tests.qbk => 16_tests.qbk} (100%) delete mode 100644 doc/qbk/values.qbk diff --git a/doc/Jamfile b/doc/Jamfile index 7039faad..708cc728 100644 --- a/doc/Jamfile +++ b/doc/Jamfile @@ -259,7 +259,7 @@ explicit images ; xml mysql_doc : - qbk/main.qbk + qbk/00_main.qbk : qbk ; diff --git a/doc/qbk/main.qbk b/doc/qbk/00_main.qbk similarity index 92% rename from doc/qbk/main.qbk rename to doc/qbk/00_main.qbk index 4303b774..d04f6a8f 100644 --- a/doc/qbk/main.qbk +++ b/doc/qbk/00_main.qbk @@ -86,22 +86,22 @@ [def __USE__ [mysqllink use.html `USE`]] -[include intro.qbk] -[include tutorial.qbk] -[include concepts.qbk] -[include values.qbk] -[include queries.qbk] -[include prepared_statements.qbk] -[include resultsets.qbk] -[include async.qbk] -[include ssl.qbk] -[include other_streams.qbk] -[include error_handling.qbk] -[include connparams.qbk] -[include reconnecting.qbk] -[include examples.qbk] -[include types.qbk] -[include tests.qbk] +[include 01_intro.qbk] +[include 02_tutorial.qbk] +[include 03_concepts.qbk] +[include 04_values.qbk] +[include 05_queries.qbk] +[include 06_prepared_statements.qbk] +[include 07_resultsets.qbk] +[include 08_async.qbk] +[include 09_ssl.qbk] +[include 10_other_streams.qbk] +[include 11_error_handling.qbk] +[include 12_connparams.qbk] +[include 13_reconnecting.qbk] +[include 14_examples.qbk] +[include 15_types.qbk] +[include 16_tests.qbk] [section:quickref Reference] [xinclude helpers/quickref.xml] diff --git a/doc/qbk/intro.qbk b/doc/qbk/01_intro.qbk similarity index 100% rename from doc/qbk/intro.qbk rename to doc/qbk/01_intro.qbk diff --git a/doc/qbk/tutorial.qbk b/doc/qbk/02_tutorial.qbk similarity index 96% rename from doc/qbk/tutorial.qbk rename to doc/qbk/02_tutorial.qbk index c546f3d2..901d9272 100644 --- a/doc/qbk/tutorial.qbk +++ b/doc/qbk/02_tutorial.qbk @@ -81,8 +81,8 @@ object: [tutorial_read] -A [reflink rows] object is a matrix-like container of MySQL values. -Each value is represented as a [reflink field_view], a variant-like class that +A [reflink rows] object is a matrix-like container of MySQL fields. +Each field is represented as a [reflink field_view], a variant-like class that can hold any type allowed in MySQL. [tutorial_fields] diff --git a/doc/qbk/03_concepts.qbk b/doc/qbk/03_concepts.qbk new file mode 100644 index 00000000..b63840fd --- /dev/null +++ b/doc/qbk/03_concepts.qbk @@ -0,0 +1,87 @@ +[/ + Copyright (c) 2019-2022 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:concepts Concepts] +[nochunk] + +Purpose: briefly explain the library main classes and functions, and how to use them. +Links to specialized sections for further details. + +Connection: the main entry point. Stream-templated I/O object that contains an actual Stream. +connect/close, query, prepare_statement. + +resultset: proxy I/O object that represents the result of a query execution. +Contains metadata (call meta()) and state about the operation. Doesn't contain the actual rows. +Call read_xxx() to get them. + +statement: proxy I/O object representing a server-side prepared statement. Main purpose is calling execute(), +which yields a resultset. + +In all cases, communication will happen over the Stream contained in connection, even if the operation +is called on resultset or statement. Relevant for lifetimes and threading. + +query() gets passed a textual SQL string and "returns" a resultset. No safe string escaping right now. +Use only for queries known ahead of time, e.g. "START TRANSACTION", "SET NAMES utf8", etc. + +prepare_statement() gets passed a textual SQL string with placeholders and "returns" a statement object. +Statement objects are proxy I/O objects (reference the connection). Main purpose is calling execute(), +passing as many params as required. + +After getting a resultset, call read_xxx() to read the actual rows into memory (into row, rows, etc. - more on that later). +When the resultset has no more rows, we say it's complete(). For complete resultsets, you can access extra info, like last_insert_id. +Background: calling query() or execute() sends the request and reads the initial response, but not the rows. But the server has sent them, +so we need to read them before moving to the next operation. last_insert_id & co come in an EOF packet marking end of rows, complete() signals +that we've received it and it's safe to engage in the next operation. + +When calling read_xxx(), you get some combination of row, rows, etc. There are + rows rows_view + row row_view + field field_view + +field and field_view: the smallest unit of data; a single "cell" in a MySQL table. Variant-like types +that can represent any type MySQL will return. field is owning, regular value that may allocate. +field_view is a lightweight variation of field that may point to external memory (usually memory allocated by a row). + +row: owning, regular, vector-like collection of fields. Element type: field_view, valid as long as the memory allocated by row valid. +row_view: reference type for row; non-allocating; constructed from a row or rows object; valid as long as the memory allocated by the row is valid. +rows: owning, regular, matrix-like collection of fields. Represents several rows in an optimized way. Indexing it yields a row_view +rows_view: reference type for rows; same applies + +All row types are read-only; designed for memory re-use. If you need to modify them, copy to a separate collection of fields (e.g. to_vector()) + +Several row-reading functions + read_one, row read_one, row_view + read_some, rows read_some, rows_view + read_all, rows read_all, rows_view + +read_one read one row at a time. +read_some will read at least one, and as much as possible whithout allocating extra buffer space. +read_all will read the entire resultset +The non-owning functions may be faster, as they make less copies when the fields are strings. The returned rows are valid until the next network operation on the stream is called. + +Prefer owning functions if super efficiency is not key. Non-owning functions may be faster because they +tend to allocate memory, but 1) know what you're doing 2) not suitable for "process while reading next batch" + +Use read_one when you can/need to process one row at a time, or when the resultset is too big to fit in memory +Use read_all as the default for small resultsets that can fit in memory +Use read_some when you need maximum efficiency, in exchange for more complexity. Fine tune buffer sizes before going down that path + +Async: there are sync with err, exc, async and async with error_info. All operations may imply reads, writes, or both. +You can't call operations that imply reads and writes concurrently. At the moment, most ops are both, so one async at a time. +All operations end up modifying the Stream state, so not thread-safe, use strands. + +Encoding: set it on handshake or with SET NAMES and everything you send/receive will be in this encoding. +We don't do any handling. + +Streams: the most used tcp_ssl_connection, unix_ssl_connection. But you can always define your own by using connection +(e.g. other executors, default completion tokens). connect() and close() handle the physical level; you may handle +it yourself and use handshake() and quit(). When calling connect() you can pass credentials, default db, buffer sizes and SSL mode. (?) + +Error recovery: after any server error, you can still use the connection. After a client or network error, close/reopen. In the common case +of ssl streams, delete the object and create it again. + +[endsect] diff --git a/doc/qbk/concepts.qbk b/doc/qbk/04_values.qbk similarity index 80% rename from doc/qbk/concepts.qbk rename to doc/qbk/04_values.qbk index 35be869d..f8118e6a 100644 --- a/doc/qbk/concepts.qbk +++ b/doc/qbk/04_values.qbk @@ -5,10 +5,11 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:concepts Concepts] +[section:fields MySQL values] [nochunk] -Hola +[import ../../example/field.cpp] + [endsect] diff --git a/doc/qbk/queries.qbk b/doc/qbk/05_queries.qbk similarity index 100% rename from doc/qbk/queries.qbk rename to doc/qbk/05_queries.qbk diff --git a/doc/qbk/prepared_statements.qbk b/doc/qbk/06_prepared_statements.qbk similarity index 100% rename from doc/qbk/prepared_statements.qbk rename to doc/qbk/06_prepared_statements.qbk diff --git a/doc/qbk/resultsets.qbk b/doc/qbk/07_resultsets.qbk similarity index 100% rename from doc/qbk/resultsets.qbk rename to doc/qbk/07_resultsets.qbk diff --git a/doc/qbk/async.qbk b/doc/qbk/08_async.qbk similarity index 100% rename from doc/qbk/async.qbk rename to doc/qbk/08_async.qbk diff --git a/doc/qbk/ssl.qbk b/doc/qbk/09_ssl.qbk similarity index 100% rename from doc/qbk/ssl.qbk rename to doc/qbk/09_ssl.qbk diff --git a/doc/qbk/other_streams.qbk b/doc/qbk/10_other_streams.qbk similarity index 100% rename from doc/qbk/other_streams.qbk rename to doc/qbk/10_other_streams.qbk diff --git a/doc/qbk/error_handling.qbk b/doc/qbk/11_error_handling.qbk similarity index 100% rename from doc/qbk/error_handling.qbk rename to doc/qbk/11_error_handling.qbk diff --git a/doc/qbk/connparams.qbk b/doc/qbk/12_connparams.qbk similarity index 100% rename from doc/qbk/connparams.qbk rename to doc/qbk/12_connparams.qbk diff --git a/doc/qbk/reconnecting.qbk b/doc/qbk/13_reconnecting.qbk similarity index 100% rename from doc/qbk/reconnecting.qbk rename to doc/qbk/13_reconnecting.qbk diff --git a/doc/qbk/examples.qbk b/doc/qbk/14_examples.qbk similarity index 100% rename from doc/qbk/examples.qbk rename to doc/qbk/14_examples.qbk diff --git a/doc/qbk/types.qbk b/doc/qbk/15_types.qbk similarity index 100% rename from doc/qbk/types.qbk rename to doc/qbk/15_types.qbk diff --git a/doc/qbk/tests.qbk b/doc/qbk/16_tests.qbk similarity index 100% rename from doc/qbk/tests.qbk rename to doc/qbk/16_tests.qbk diff --git a/doc/qbk/values.qbk b/doc/qbk/values.qbk deleted file mode 100644 index c1bdb705..00000000 --- a/doc/qbk/values.qbk +++ /dev/null @@ -1,174 +0,0 @@ -[/ - Copyright (c) 2019-2022 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:values MySQL values] -[nochunk] - -[import ../../example/field.cpp] - -This section describes the [reflink2 value boost::mysql::value] class, presents -several examples and discusses some topics regarding its usage. - -A [reflink value] is a variant-like type. At a given time, -it always holds a value of one of the type alternatives. -See [refmem value variant_type] for the list of all -possible type alternatives. A value can be converted to an -actual variant using [refmem value to_variant]. -[@boost:/libs/variant2/doc/html/variant2.html Boost.Variant2] -is used to represent values as variants. - -[heading MySQL types in C++] - -MySQL supports a wide variety of types. There is no one-to-one mapping -between MySQL types and C++ types, as this would make -[refmem value variant_type] have a lot of options, -adding unnecessary complexity and overhead. - -The mappings are intended to be lossless and intuitive. -For more information about the type mappings, see [link mysql.types this section]. - -[heading NULL values] - -NULL values are represented as a [reflink value] containing the monostate -type [reflink null_t]. You can test if a value is NULL using -[refmem value is_null] - -[heading Accessing the underlying value] - -You can access the actual typed value of a `boost::mysql::value` using -one of the following accessors. All these methods are function -templates, where the only template parameter `T` is the type you -want to cast the value to. They differ in how they behave when the -underlying value cannot be converted to `T`: - -* [refmem value get]: returns a `T`, throws an exception if not convertible. -* [refmem value get_optional]: returns a __boost_optional__, - empty if not convertible. -* [refmem value get_std_optional]: same as [refmem value get_optional], but - using C++17 `std::optional`. - -Example of [refmem value get]: - -[value_example_get] - -Example of [refmem value get_optional]: - -[value_example_get_optional] - -Example of [refmem value get_std_optional] (requires C++17): - -[value_example_get_std_optional] - -[note - When calling these functions, unless otherwise noted, - `T` must be one of the types in [refmem value variant_type]. -] - -[section:conversions Conversions] - -In general, when calling accessor functions, the passed in `T` type -must match exactly the type alternative the value holds (e.g. if -the value contains a `double`, trying to retrieve a `std::uint64_t` -will fail). - -However, there are certain cases where this behavior does not -make sense, and an automatic conversion will happen evein if `T` -does not exactly match the stored type: - -* If the stored type is `std::uint64_t`, the requested type (`T`) - is `std::int64_t`, and the value is within the range - of a `std::int64_t`, it will be converted to this type. -* If the stored type is `std::int64_t`, the requested type (`T`) - is `std::uint64_t`, and the value is within the range - of a `std::uint64_t`, it will be converted to this type. -* If the stored type is `float`, and the requested type - is `double`, it will be converted. - -The motivation behind this conversions is: given the SQL query -`"SELECT COUNT(*) AS cnt FROM my_table"`, which should be `T` -for a [reflink value] representing the `cnt` column? -Is it `std::int64_t` or `std::uint64_t`? The answer is that -it actually depends on how the database represents `cnt`. -This information is transmitted to the client, but is not -obvious to the user. - -Example: - -[value_example_get_conversions] - -[endsect] - -[heading Querying the stored type] - -You may query if a [reflink value] has stored type `T` using one of -[refmem value is] and [refmem value is_convertible_to]. The difference -between the two is that the later will consider the above -[link mysql.values.conversions conversions], while the former won't: - -[value_example_is] - -[warning - Use the above functions when you don't need the underlying value. - The following pattern is inefficient, please avoid it: -] - -[value_example_inefficient] - -Instead, prefer the following: - -[value_example_inefficient_ok] - -[section:strings A note on string values] - -[warning - String types are represented as `boost::string_view`s, as detailed - [link mysql.types here]. This is a non-owning, lightweight - string type, that points to an externally owned piece of memory. - This makes the [reflink value] class [*non-owning] in the case of strings. -] - -In __Self__, the memory pointed to by string [reflink value]s -is owned by the [reflink row] objects the values belong to. -This avoids unnecessary copies and makes the [reflink value] -class lightweight and cheap to copy. In exchange, you must pay attention -to the lifetime of the [reflink row] object you used to obtain the [reflink value] to not incur in -undefined behavior. For more information on resultset mechanics, -see [link mysql.resultsets this section]. - -[endsect] - -[section:relational Relational operators] - -Values can be compared for equality ([reflink2 value.operator_eq__eq_ value::operator==] -and [reflink2 value.operator_not__eq_ value::operator!=]). These operators take into account both type and value, -so `value(std::int64_t(200)) != value(std::uint64_t(200))`. - -Values also define the four inequality operators ([reflink2 value.operator_gt_ value::operator>], -[reflink2 value.operator_gt__eq_ value::operator>=], [reflink2 value.operator_lt_ value::operator<] and -[reflink2 value.operator_lt__eq_ value::operator<=]). - -These operators use the underlying variant's definition -for inequality, so they also take into account both type and value. This may lead to counter-intuitive -results, such as `value(std::uint64_t(10)) > value(std::int64_t(20))`. The main purpose of these -operators is allowing [reflink value]s as keys to ordered containers. If you need to perform -actual logical comparisons between integers, cast the values to integer types using one of -the accessor functions, instead. This behavior may change in the future. - -Values do not define `std::hash` yet, as `boost::string_view` does not support it. -This means that [reflink value]s cannot be used as keys to unordered containers. - -[endsect] - -[heading Other operations] - -Values may also be streamed. If you need -to `visit()` a [reflink value], use [refmem value to_variant] -and use `visit()` on the returned variant. Additionally, -[reflink row] objects may also -be streamed and compared for equality. - -[endsect] diff --git a/example/tutorial.cpp b/example/tutorial.cpp index 299f6fbb..0da9afca 100644 --- a/example/tutorial.cpp +++ b/example/tutorial.cpp @@ -60,17 +60,20 @@ void main_impl(int argc, char** argv) //] //[tutorial_query + // Issue the SQL query to the server const char* sql = "SELECT \"Hello world!\""; boost::mysql::tcp_ssl_resultset result; conn.query(sql, result); //] //[tutorial_read + // Read the query results into memory boost::mysql::rows all_rows; result.read_all(all_rows); //] //[tutorial_fields + // Print the first field in the first row std::cout << all_rows.at(0).at(0) << std::endl; //] diff --git a/tools/scripts/build_docs_local_docker.sh b/tools/scripts/build_docs_local_docker.sh index 7367b365..7b9a50c6 100755 --- a/tools/scripts/build_docs_local_docker.sh +++ b/tools/scripts/build_docs_local_docker.sh @@ -11,4 +11,5 @@ set -e cd /opt/boost/ export BOOST_ROOT=$(pwd) cp libs/mysql/tools/user-config.jam ~/ +rm -rf bin.v2/libs/mysql ./b2 -j4 libs/mysql/doc//boostrelease