src/prepared_query.cpp
| 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 | #include <sqlon/prepared_query.h> | ||
| 19 | |||
| 20 | #include <unordered_set> | ||
| 21 | #include <utility> | ||
| 22 | |||
| 23 | namespace sqlon { | ||
| 24 | |||
| 25 | 7 | prepared_query::prepared_query(std::string sql, std::vector<prepared_parameter> parameters) | |
| 26 | 7 | : m_sql(std::move(sql)) | |
| 27 | 7 | , m_parameters(std::move(parameters)) | |
| 28 | { | ||
| 29 |
1/1✓ Branch 2 taken 7 times.
|
7 | m_bindings.reserve(m_parameters.size()); |
| 30 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 7 times.
|
13 | for (std::size_t index = 0; index < m_parameters.size(); ++index) |
| 31 |
1/1✓ Branch 1 taken 6 times.
|
6 | m_bindings.push_back({index, std::nullopt}); |
| 32 |
1/1✓ Branch 1 taken 7 times.
|
7 | validate_layout(); |
| 33 | 7 | } | |
| 34 | |||
| 35 | 26 | prepared_query::prepared_query(std::string sql, std::vector<prepared_parameter> parameters, | |
| 36 | 26 | std::vector<prepared_binding> bindings) | |
| 37 | 26 | : m_sql(std::move(sql)) | |
| 38 | 26 | , m_parameters(std::move(parameters)) | |
| 39 | 26 | , m_bindings(std::move(bindings)) | |
| 40 | { | ||
| 41 |
1/1✓ Branch 1 taken 20 times.
|
26 | validate_layout(); |
| 42 | 44 | } | |
| 43 | |||
| 44 | 12 | const std::string& prepared_query::sql() const noexcept | |
| 45 | { | ||
| 46 | 12 | return m_sql; | |
| 47 | } | ||
| 48 | |||
| 49 | 17 | const std::vector<prepared_parameter>& prepared_query::parameters() const noexcept | |
| 50 | { | ||
| 51 | 17 | return m_parameters; | |
| 52 | } | ||
| 53 | |||
| 54 | 22 | bound_parameters prepared_query::materialize(const std::vector<std::optional<rendered_parameter>>& values) const | |
| 55 | { | ||
| 56 |
2/2✓ Branch 5 taken 28 times.
✓ Branch 6 taken 21 times.
|
49 | for (const std::optional<rendered_parameter>& value : values) |
| 57 |
3/3✓ Branch 1 taken 1 time.
✓ Branch 2 taken 27 times.
✓ Branch 5 taken 1 time.
|
28 | if (!value) throw invalid_query{"not all prepared parameters were bound"}; |
| 58 | |||
| 59 | 21 | bound_parameters result; | |
| 60 |
1/1✓ Branch 2 taken 21 times.
|
21 | result.reserve(m_bindings.size()); |
| 61 |
2/2✓ Branch 5 taken 29 times.
✓ Branch 6 taken 21 times.
|
50 | for (const prepared_binding& binding : m_bindings) { |
| 62 |
1/1✓ Branch 3 taken 29 times.
|
29 | rendered_parameter parameter = *values[binding.parameter_index]; |
| 63 |
1/1✓ Branch 1 taken 29 times.
|
29 | parameter.placeholder = binding.placeholder; |
| 64 |
1/1✓ Branch 2 taken 29 times.
|
29 | result.push_back(std::move(parameter)); |
| 65 | 29 | } | |
| 66 | 21 | return result; | |
| 67 | ✗ | } | |
| 68 | |||
| 69 | 33 | void prepared_query::validate_layout() | |
| 70 | { | ||
| 71 |
3/3✓ Branch 1 taken 1 time.
✓ Branch 2 taken 32 times.
✓ Branch 5 taken 1 time.
|
33 | if (m_sql.empty()) throw invalid_query{"prepared SQL cannot be empty"}; |
| 72 | |||
| 73 |
1/1✓ Branch 2 taken 32 times.
|
32 | std::vector<bool> referenced(m_parameters.size()); |
| 74 |
2/2✓ Branch 4 taken 42 times.
✓ Branch 5 taken 31 times.
|
73 | for (const prepared_binding& binding : m_bindings) { |
| 75 |
3/3✓ Branch 1 taken 1 time.
✓ Branch 2 taken 41 times.
✓ Branch 5 taken 1 time.
|
42 | if (binding.parameter_index >= m_parameters.size()) throw invalid_query{"prepared binding layout is out of range"}; |
| 76 |
1/1✓ Branch 1 taken 41 times.
|
41 | referenced[binding.parameter_index] = true; |
| 77 | } | ||
| 78 | |||
| 79 |
2/2✓ Branch 6 taken 40 times.
✓ Branch 7 taken 30 times.
|
70 | for (const bool is_referenced : referenced) |
| 80 |
3/3✓ Branch 0 taken 1 time.
✓ Branch 1 taken 39 times.
✓ Branch 4 taken 1 time.
|
40 | if (!is_referenced) throw invalid_query{"prepared parameter is missing from the binding layout"}; |
| 81 | |||
| 82 | 30 | std::unordered_set<std::string> names; | |
| 83 |
2/2✓ Branch 1 taken 38 times.
✓ Branch 2 taken 27 times.
|
65 | for (std::size_t index = 0; index < m_parameters.size(); ++index) { |
| 84 |
3/3✓ Branch 2 taken 1 time.
✓ Branch 3 taken 37 times.
✓ Branch 6 taken 1 time.
|
38 | if (m_parameters[index].name.empty()) throw invalid_query{"a prepared parameter name cannot be empty"}; |
| 85 |
4/4✓ Branch 2 taken 37 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 36 times.
✓ Branch 8 taken 1 time.
|
37 | if (!names.insert(m_parameters[index].name).second) throw invalid_query{"prepared parameter names must be unique"}; |
| 86 |
1/1✓ Branch 2 taken 36 times.
|
36 | const bool inserted = m_parameter_indices.emplace(m_parameters[index].identity, index).second; |
| 87 |
3/3✓ Branch 0 taken 1 time.
✓ Branch 1 taken 35 times.
✓ Branch 4 taken 1 time.
|
36 | if (!inserted) throw invalid_query{"prepared parameter identities must be unique"}; |
| 88 | } | ||
| 89 | 35 | } | |
| 90 | |||
| 91 | } // namespace sqlon | ||
| 92 |