SQLon test coverage


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 86.6% 161 / 0 / 186
Functions: 100.0% 23 / 0 / 23
Branches: 49.6% 115 / 0 / 232

include/sqlon/prepared_query.h
Line Branch Exec Source
1 /******************************************************************************
2 **
3 ** Copyright (C) 2026 Ivan Pinezhaninov <ivan.pinezhaninov@gmail.com>
4 **
5 ** This file is part of the SQLon - which can be found at
6 ** https://github.com/IvanPinezhaninov/sqlon/.
7 **
8 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10 ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
11 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
12 ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
13 ** OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
14 ** THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 **
16 ******************************************************************************/
17
18 #ifndef SQLON_PREPARED_QUERY_H
19 #define SQLON_PREPARED_QUERY_H
20
21 #include <sqlon/error.h>
22 #include <sqlon/export.h>
23 #include <sqlon/query.h>
24 #include <sqlon/render.h>
25
26 #include <cstddef>
27 #include <optional>
28 #include <string>
29 #include <type_traits>
30 #include <unordered_map>
31 #include <utility>
32 #include <vector>
33
34 namespace sqlon {
35
36 /** @brief Metadata for one logical prepared-query parameter. */
37 struct prepared_parameter final {
38 /** @brief Stable identity of the parameter handle. */
39 std::size_t identity{};
40
41 /** @brief Logical parameter name. */
42 std::string name;
43
44 /** @brief Expected runtime value category. */
45 parameter_kind kind{};
46
47 /** @brief Whether the parameter accepts SQL NULL. */
48 bool nullable{};
49
50 /** @brief Opaque concrete type identity for an application-defined parameter. */
51 const void* custom_type_id{};
52 };
53
54 /** @brief One rendered binding position in a prepared query. */
55 struct prepared_binding final {
56 /** @brief Index of the logical parameter supplying this binding. */
57 std::size_t parameter_index{};
58
59 /** @brief Exact placeholder emitted for this binding, if known. */
60 std::optional<std::string> placeholder{};
61 };
62
63 /** @brief Bound parameter values ready for a database adapter. */
64 using bound_parameters = std::vector<rendered_parameter>;
65
66 /** @brief Reusable rendered SQL and stable parameter layout. */
67 class prepared_query final {
68 public:
69 /** @brief Creates a prepared query whose binding layout matches its logical parameters. */
70 SQLON_API prepared_query(std::string sql, std::vector<prepared_parameter> parameters);
71
72 /** @brief Creates a prepared query with explicit rendered bindings. */
73 SQLON_API prepared_query(std::string sql, std::vector<prepared_parameter> parameters,
74 std::vector<prepared_binding> bindings);
75
76 /** @brief Returns the SQL rendered during preparation. */
77 SQLON_API const std::string& sql() const noexcept;
78
79 /** @brief Returns the logical parameter layout. */
80 SQLON_API const std::vector<prepared_parameter>& parameters() const noexcept;
81
82 /** @brief Binds values through typed parameter assignments. */
83 template<typename... Bindings>
84 21 bound_parameters bind(Bindings&&... bindings) const
85 {
86 static_assert((detail::is_parameter_binding<std::decay_t<Bindings>>::value && ...),
87 "prepared_query::bind expects typed parameter assignments");
88
11/11
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<>() const:
✓ Branch 2 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<PreparedUuid> >(sqlon::parameter_binding<PreparedUuid>&&) const:
✓ Branch 2 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<bool>, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(sqlon::parameter_binding<bool>&&, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&) const:
✓ Branch 2 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<long> >(sqlon::parameter_binding<long>&&) const:
✓ Branch 2 taken 4 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<long>, sqlon::parameter_binding<long> >(sqlon::parameter_binding<long>&&, sqlon::parameter_binding<long>&&) const:
✓ Branch 2 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&) const:
✓ Branch 2 taken 4 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, sqlon::parameter_binding<bool> >(sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&, sqlon::parameter_binding<bool>&&) const:
✓ Branch 2 taken 2 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, sqlon::parameter_binding<long> >(sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&, sqlon::parameter_binding<long>&&) const:
✓ Branch 2 taken 2 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, sqlon::parameter_binding<bool> >(sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&, sqlon::parameter_binding<bool>&&) const:
✓ Branch 2 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >(sqlon::parameter_binding<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&&) const:
✓ Branch 2 taken 3 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<unsigned long>, sqlon::parameter_binding<long> >(sqlon::parameter_binding<unsigned long>&&, sqlon::parameter_binding<long>&&) const:
✓ Branch 2 taken 1 time.
21 std::vector<std::optional<rendered_parameter>> values(m_parameters.size());
89
15/17
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<PreparedUuid> >(sqlon::parameter_binding<PreparedUuid>&&) const:
✓ Branch 3 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<bool>, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(sqlon::parameter_binding<bool>&&, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&) const:
✓ Branch 3 taken 1 time.
✓ Branch 8 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<long> >(sqlon::parameter_binding<long>&&) const:
✓ Branch 3 taken 4 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<long>, sqlon::parameter_binding<long> >(sqlon::parameter_binding<long>&&, sqlon::parameter_binding<long>&&) const:
✓ Branch 3 taken 1 time.
✓ Branch 8 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&) const:
✓ Branch 3 taken 3 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, sqlon::parameter_binding<bool> >(sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&, sqlon::parameter_binding<bool>&&) const:
✓ Branch 3 taken 2 times.
✓ Branch 8 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, sqlon::parameter_binding<long> >(sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&, sqlon::parameter_binding<long>&&) const:
✓ Branch 3 taken 2 times.
✓ Branch 8 taken 2 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, sqlon::parameter_binding<bool> >(sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&, sqlon::parameter_binding<bool>&&) const:
✓ Branch 3 taken 1 time.
✗ Branch 8 not taken.
✗ Branch 13 not taken.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >(sqlon::parameter_binding<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&&) const:
✓ Branch 3 taken 2 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<unsigned long>, sqlon::parameter_binding<long> >(sqlon::parameter_binding<unsigned long>&&, sqlon::parameter_binding<long>&&) const:
✓ Branch 3 taken 1 time.
✓ Branch 8 taken 1 time.
26 (bind_one(values, std::forward<Bindings>(bindings)), ...);
90
10/11
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<>() const:
✓ Branch 1 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<PreparedUuid> >(sqlon::parameter_binding<PreparedUuid>&&) const:
✓ Branch 1 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<bool>, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(sqlon::parameter_binding<bool>&&, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&) const:
✓ Branch 1 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<long> >(sqlon::parameter_binding<long>&&) const:
✓ Branch 1 taken 4 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<long>, sqlon::parameter_binding<long> >(sqlon::parameter_binding<long>&&, sqlon::parameter_binding<long>&&) const:
✓ Branch 1 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&) const:
✓ Branch 1 taken 2 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, sqlon::parameter_binding<bool> >(sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&, sqlon::parameter_binding<bool>&&) const:
✓ Branch 1 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, sqlon::parameter_binding<long> >(sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&, sqlon::parameter_binding<long>&&) const:
✓ Branch 1 taken 2 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, sqlon::parameter_binding<bool> >(sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&, sqlon::parameter_binding<bool>&&) const:
✗ Branch 1 not taken.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >(sqlon::parameter_binding<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&&) const:
✓ Branch 1 taken 2 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind<sqlon::parameter_binding<unsigned long>, sqlon::parameter_binding<long> >(sqlon::parameter_binding<unsigned long>&&, sqlon::parameter_binding<long>&&) const:
✓ Branch 1 taken 1 time.
33 return materialize(values);
91 21 }
92
93 /** @brief Binds values in logical parameter order. */
94 template<typename... Values>
95 10 bound_parameters bind_positional(Values&&... values) const
96 {
97
7/18
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<PreparedDate>(PreparedDate&&) const:
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<PreparedUuid const&>(PreparedUuid const&) const:
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<decltype(nullptr)>(decltype(nullptr)&&) const:
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 5 not taken.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<int, int>(int&&, int&&) const:
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<int>(int&&) const:
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 5 not taken.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&) const:
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
10 if (sizeof...(Values) != m_parameters.size()) throw invalid_query{"incorrect positional parameter count"};
98
99
5/6
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<PreparedDate>(PreparedDate&&) const:
✓ Branch 2 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<PreparedUuid const&>(PreparedUuid const&) const:
✓ Branch 2 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<decltype(nullptr)>(decltype(nullptr)&&) const:
✓ Branch 2 taken 4 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<int, int>(int&&, int&&) const:
✗ Branch 2 not taken.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<int>(int&&) const:
✓ Branch 2 taken 2 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&) const:
✓ Branch 2 taken 1 time.
9 std::vector<std::optional<rendered_parameter>> bound_values(m_parameters.size());
100 9 std::size_t index = 0;
101 9 const auto append = [&](auto&& value) {
102 const prepared_parameter& slot = m_parameters[index++];
103 const parameter_kind bound_kind = detail::parameter_kind_of<decltype(value)>();
104 if (slot.kind != bound_kind && !(slot.nullable && bound_kind == parameter_kind::null))
105 throw invalid_query{"prepared positional parameter type mismatch"};
106 if (bound_kind == parameter_kind::custom && slot.custom_type_id &&
107 slot.custom_type_id != detail::custom_parameter_type_id<decltype(value)>())
108 throw invalid_query{"prepared positional parameter type mismatch"};
109
110 parameter_storage storage = detail::make_parameter_value(std::forward<decltype(value)>(value));
111 if (std::holds_alternative<std::nullptr_t>(storage) && !slot.nullable)
112 throw invalid_query{"a non-nullable prepared parameter cannot be bound to NULL"};
113 bound_values[index - 1].emplace(rendered_parameter{slot.name, parameter_value{std::move(storage)}, std::nullopt});
114 };
115
3/7
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<PreparedDate>(PreparedDate&&) const:
✗ Branch 2 not taken.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<PreparedUuid const&>(PreparedUuid const&) const:
✓ Branch 2 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<decltype(nullptr)>(decltype(nullptr)&&) const:
✓ Branch 2 taken 2 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<int, int>(int&&, int&&) const:
✗ Branch 2 not taken.
✗ Branch 6 not taken.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<int>(int&&) const:
✓ Branch 2 taken 2 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&) const:
✗ Branch 2 not taken.
9 (append(std::forward<Values>(values)), ...);
116
3/6
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<PreparedDate>(PreparedDate&&) const:
✗ Branch 1 not taken.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<PreparedUuid const&>(PreparedUuid const&) const:
✓ Branch 1 taken 1 time.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<decltype(nullptr)>(decltype(nullptr)&&) const:
✓ Branch 1 taken 2 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<int, int>(int&&, int&&) const:
✗ Branch 1 not taken.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<int>(int&&) const:
✓ Branch 1 taken 2 times.
std::vector<sqlon::rendered_parameter, std::allocator<sqlon::rendered_parameter> > sqlon::prepared_query::bind_positional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&) const:
✗ Branch 1 not taken.
10 return materialize(bound_values);
117 9 }
118
119 private:
120 template<typename T>
121 28 void bind_one(std::vector<std::optional<rendered_parameter>>& values, parameter_binding<T> binding) const
122 {
123 const std::unordered_map<std::size_t, std::size_t>::const_iterator position =
124
6/6
void sqlon::prepared_query::bind_one<PreparedUuid>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<PreparedUuid>) const:
✓ Branch 1 taken 1 time.
void sqlon::prepared_query::bind_one<bool>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<bool>) const:
✓ Branch 1 taken 3 times.
void sqlon::prepared_query::bind_one<long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<long>) const:
✓ Branch 1 taken 9 times.
void sqlon::prepared_query::bind_one<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >) const:
✓ Branch 1 taken 11 times.
void sqlon::prepared_query::bind_one<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) const:
✓ Branch 1 taken 3 times.
void sqlon::prepared_query::bind_one<unsigned long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<unsigned long>) const:
✓ Branch 1 taken 1 time.
28 m_parameter_indices.find(binding.identity);
125
8/18
void sqlon::prepared_query::bind_one<PreparedUuid>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<PreparedUuid>) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
void sqlon::prepared_query::bind_one<bool>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<bool>) const:
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 2 times.
✓ Branch 6 taken 1 time.
void sqlon::prepared_query::bind_one<long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<long>) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 6 not taken.
void sqlon::prepared_query::bind_one<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✗ Branch 6 not taken.
void sqlon::prepared_query::bind_one<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 6 not taken.
void sqlon::prepared_query::bind_one<unsigned long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<unsigned long>) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
28 if (position == m_parameter_indices.end()) throw invalid_query{"parameter does not belong to this prepared query"};
126
127 27 const std::size_t index = position->second;
128 27 const prepared_parameter& slot = m_parameters[index];
129
8/18
void sqlon::prepared_query::bind_one<PreparedUuid>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<PreparedUuid>) const:
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
void sqlon::prepared_query::bind_one<bool>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<bool>) const:
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 5 not taken.
void sqlon::prepared_query::bind_one<long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<long>) const:
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 5 not taken.
void sqlon::prepared_query::bind_one<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >) const:
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 10 times.
✓ Branch 5 taken 1 time.
void sqlon::prepared_query::bind_one<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) const:
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 5 not taken.
void sqlon::prepared_query::bind_one<unsigned long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<unsigned long>) const:
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
27 if (slot.kind != detail::parameter_kind_of<T>()) throw invalid_query{"prepared parameter type mismatch"};
130
14/48
void sqlon::prepared_query::bind_one<PreparedUuid>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<PreparedUuid>) const:
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
void sqlon::prepared_query::bind_one<bool>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<bool>) const:
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
void sqlon::prepared_query::bind_one<long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<long>) const:
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
void sqlon::prepared_query::bind_one<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >) const:
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 10 times.
void sqlon::prepared_query::bind_one<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) const:
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
void sqlon::prepared_query::bind_one<unsigned long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<unsigned long>) const:
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
27 if (slot.kind == parameter_kind::custom && slot.custom_type_id &&
131 1 slot.custom_type_id != detail::custom_parameter_type_id<T>())
132 ✗ throw invalid_query{"prepared parameter type mismatch"};
133
8/18
void sqlon::prepared_query::bind_one<PreparedUuid>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<PreparedUuid>) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
void sqlon::prepared_query::bind_one<bool>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<bool>) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 6 not taken.
void sqlon::prepared_query::bind_one<long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<long>) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 6 not taken.
void sqlon::prepared_query::bind_one<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >) const:
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 9 times.
✓ Branch 6 taken 1 time.
void sqlon::prepared_query::bind_one<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 6 not taken.
void sqlon::prepared_query::bind_one<unsigned long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<unsigned long>) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
26 if (values[index]) throw invalid_query{"prepared parameter was bound more than once"};
134
16/36
void sqlon::prepared_query::bind_one<PreparedUuid>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<PreparedUuid>) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
void sqlon::prepared_query::bind_one<bool>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<bool>) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
void sqlon::prepared_query::bind_one<long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<long>) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
void sqlon::prepared_query::bind_one<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
void sqlon::prepared_query::bind_one<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) const:
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 7 taken 2 times.
void sqlon::prepared_query::bind_one<unsigned long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<unsigned long>) const:
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
25 if (std::holds_alternative<std::nullptr_t>(binding.value.value()) && !slot.nullable)
135
1/6
void sqlon::prepared_query::bind_one<PreparedUuid>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<PreparedUuid>) const:
✗ Branch 2 not taken.
void sqlon::prepared_query::bind_one<bool>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<bool>) const:
✗ Branch 2 not taken.
void sqlon::prepared_query::bind_one<long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<long>) const:
✗ Branch 2 not taken.
void sqlon::prepared_query::bind_one<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >) const:
✗ Branch 2 not taken.
void sqlon::prepared_query::bind_one<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) const:
✓ Branch 2 taken 1 time.
void sqlon::prepared_query::bind_one<unsigned long>(std::vector<std::optional<sqlon::rendered_parameter>, std::allocator<std::optional<sqlon::rendered_parameter> > >&, sqlon::parameter_binding<unsigned long>) const:
✗ Branch 2 not taken.
1 throw invalid_query{"a non-nullable prepared parameter cannot be bound to NULL"};
136 48 values[index].emplace(rendered_parameter{slot.name, std::move(binding.value), std::nullopt});
137 48 }
138
139 SQLON_API bound_parameters materialize(const std::vector<std::optional<rendered_parameter>>& values) const;
140
141 void validate_layout();
142
143 std::string m_sql;
144 std::vector<prepared_parameter> m_parameters;
145 std::vector<prepared_binding> m_bindings;
146 std::unordered_map<std::size_t, std::size_t> m_parameter_indices;
147 };
148
149 /** @brief Renders a slot-only query and records its reusable parameter layout. */
150 SQLON_API prepared_query prepare(const query& value, const sql_options& options);
151
152 } // namespace sqlon
153
154 #endif // SQLON_PREPARED_QUERY_H
155