userver: /data/code/userver/odbc/include/userver/storages/odbc/bulk.hpp Source File
Loading...
Searching...
No Matches
bulk.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/odbc/bulk.hpp
4/// @brief Owning parameters and execution outcome for ODBC bulk DML.
5
6#include <cstddef>
7#include <optional>
8#include <utility>
9#include <vector>
10
11#include <userver/storages/odbc/exception.hpp>
12#include <userver/storages/odbc/parameter_store.hpp>
13
14USERVER_NAMESPACE_BEGIN
15
16namespace storages::odbc {
17
18inline constexpr std::size_t kDefaultBulkRows = 1000;
19
20/// Status of one input row in an ODBC bulk execution.
21enum class BulkRowStatus {
22 /// Driver confirmed successful execution without diagnostics.
24 /// Driver confirmed success and reported warning-class diagnostics.
26 /// Driver reported that this row failed.
28 /// Driver reported that this row was not used.
30 /// The row was processed, but row-specific diagnostics are unavailable.
32 /// The driver did not provide a trustworthy per-row status.
34};
35
36/// @brief Owning, ordered rows of parameters for ODBC bulk DML.
37///
38/// The first row fixes the column count and every later row must match it.
39/// Columns must also have one normalized type in every row. Use an empty
40/// `std::optional<T>` for SQL NULL; raw `nullptr` and `std::nullopt` are
41/// untyped and are rejected by bulk preflight.
42class BulkParameterStore final {
43public:
44 BulkParameterStore() = default;
45 BulkParameterStore(const BulkParameterStore&) = delete;
46 BulkParameterStore(BulkParameterStore&&) noexcept = default;
47 BulkParameterStore& operator=(const BulkParameterStore&) = delete;
48 BulkParameterStore& operator=(BulkParameterStore&&) noexcept = default;
49
50 /// Append a row copied from values accepted by ParameterStore.
51 template <typename... Args>
52 requires((impl::kIsParameterArgument<Args> && ...))
53 BulkParameterStore& PushBackRow(const Args&... args) {
54 AppendRow(impl::MakeParameterList(args...));
55 return *this;
56 }
57
58 /// Append a row, transferring its owned parameter values.
59 BulkParameterStore& PushBackRow(ParameterStore&& row);
60
61 bool IsEmpty() const noexcept { return rows_.empty(); }
62 std::size_t RowsCount() const noexcept { return rows_.size(); }
63 std::size_t ColumnsCount() const noexcept { return columns_count_; }
64
65private:
66 friend class Cluster;
67 friend class Transaction;
68
69 void AppendRow(impl::ParameterList row);
70 const impl::ParameterRows& GetRows() const noexcept { return rows_; }
71
72 impl::ParameterRows rows_;
73 std::size_t columns_count_{0};
74};
75
76/// @brief Outcome snapshot of an ODBC bulk execution.
77///
78/// `Processed()` is absent when the driver did not provide a reliable count.
79/// `RowsAffected()` is absent when any DML result reported an unknown count.
80/// `Succeeded()` counts only kSuccess and kSuccessWithInfo rows; unknown and
81/// diagnostics-unavailable rows are deliberately not assumed successful.
82class BulkResult final {
83public:
84 BulkResult() = default;
85 BulkResult(
86 std::size_t requested,
87 std::optional<std::size_t> processed,
88 std::optional<std::size_t> rows_affected,
89 std::vector<BulkRowStatus> statuses
90 );
91
92 /// Number of input rows. Always equals `Statuses().size()`.
93 std::size_t Requested() const noexcept { return requested_; }
94 /// Reliable processed-row count, if supplied by the driver.
95 std::optional<std::size_t> Processed() const noexcept { return processed_; }
96 /// Number of rows with a confirmed successful status.
97 std::size_t Succeeded() const noexcept { return succeeded_; }
98 /// Checked aggregate DML row count, or null when any count is unknown.
99 std::optional<std::size_t> RowsAffected() const noexcept { return rows_affected_; }
100 /// One status for every requested row, including unused tail rows.
101 const std::vector<BulkRowStatus>& Statuses() const noexcept { return statuses_; }
102
103private:
104 std::size_t requested_{0};
105 std::optional<std::size_t> processed_{0};
106 std::size_t succeeded_{0};
107 std::optional<std::size_t> rows_affected_{0};
108 std::vector<BulkRowStatus> statuses_;
109};
110
111/// Bulk DML failed after possibly executing a subset of the requested rows.
112///
113/// The result snapshot is observational: execution is never retried after
114/// `SQLExecute` starts. In direct autocommit mode, completed chunks or scalar
115/// fallback rows may already be committed. Use `Transaction::ExecuteBulk` and
116/// roll back on failure when atomicity is required.
118public:
119 BulkExecutionError(
120 std::string message,
121 std::vector<DiagnosticRecord> diagnostics,
122 BulkResult result,
123 bool invalid_handle = false
124 );
125
126 const BulkResult& GetResult() const noexcept { return result_; }
127
128private:
129 BulkResult result_;
130};
131
132} // namespace storages::odbc
133
134USERVER_NAMESPACE_END