Lightweight 0.20261105.1
Loading...
Searching...
No Matches
RowIsolation.hpp
1// SPDX-License-Identifier: Apache-2.0
2#pragma once
3
4#include "../Api.hpp"
5#include "../SqlError.hpp"
6
7#include <cstddef>
8#include <cstdint>
9#include <expected>
10#include <functional>
11#include <stdexcept>
12#include <vector>
13
14namespace Lightweight::detail
15{
16
17/// How a failed batch insert is handled.
18enum class FailureDisposition : std::uint8_t
19{
20 /// The failure is caused by individual rows: isolate them and insert every other row.
21 IsolateRows,
22 /// The failure affects the whole table: give up on it (throws @ref TableRestoreFailure).
23 FailTable,
24 /// The failure is not about the data (e.g. a lost connection): rethrow it as @ref SqlException.
25 Propagate,
26};
27
28/// Error returned by a @ref RangeInserter for a range it rolled back.
29struct BatchInsertError
30{
31 /// The diagnostics of the failure.
32 SqlErrorInfo error;
33 /// Row indices the driver reported as failed, in the inserter's coordinates (absolute for a
34 /// @ref RangeInserter); empty if the driver did not tell which rows failed.
35 ///
36 /// Row isolation trusts this list: a row in it is reported failed without another attempt.
37 /// It may therefore only hold rows whose parameter status is exactly `SQL_PARAM_ERROR` —
38 /// never `SQL_PARAM_UNUSED` (a driver that stops at the first error leaves later rows so),
39 /// `SQL_PARAM_DIAG_UNAVAILABLE` or `SQL_PARAM_SUCCESS_WITH_INFO`.
40 std::vector<std::size_t> reportedFailedRows;
41};
42
43#if defined(_MSC_VER)
44 #pragma warning(push)
45 #pragma warning(disable : 4251) // STL types in DLL interface
46 #pragma warning(disable : 4275) // non-DLL-interface base class
47#endif
48
49/// Thrown by @ref InsertIsolatingFailures when an error is classified @ref FailureDisposition::FailTable.
50struct LIGHTWEIGHT_API TableRestoreFailure: std::runtime_error
51{
52 /// Constructs the exception; what() names the SQLSTATE and the message of @p error.
53 /// @param error The error that failed the table.
54 explicit TableRestoreFailure(SqlErrorInfo error);
55
56 /// The error that failed the table.
57 SqlErrorInfo error;
58};
59
60#if defined(_MSC_VER)
61 #pragma warning(pop)
62#endif
63
64/// Executes and commits rows [firstRow, firstRow + rowCount), or rolls them back and returns the error,
65/// leaving the connection ready for the next call. Never called with @c rowCount == 0.
66using RangeInserter = std::function<std::expected<void, BatchInsertError>(std::size_t firstRow, std::size_t rowCount)>;
67
68/// Decides how a failed insert is handled.
69using FailureClassifier = std::function<FailureDisposition(SqlErrorInfo const&)>;
70
71/// Receives a row that could not be inserted, together with the error of the insert that isolated it.
72using RowFailureSink = std::function<void(std::size_t row, SqlErrorInfo const&)>;
73
74/// Receives a row that was excluded up front and therefore not inserted.
75using ExcludedRowSink = std::function<void(std::size_t row)>;
76
77/// Receives the resume watermark: rows [0, settledPrefix) are each inserted, excluded or reported failed.
78using SettledSink = std::function<void(std::size_t settledPrefix)>;
79
80/// Inserts rows [0, rowCount) except those in @p excluded, isolating failing rows.
81///
82/// Rows are settled strictly in ascending order. Each maximal run of non-excluded rows is passed to
83/// @p tryInsert. A run whose failure is classified @ref FailureDisposition::IsolateRows is split at
84/// the rows the driver reported as failed, or bisected when it reported none, until every failing
85/// row is isolated and reported via @p onRowFailed; all other rows are still inserted.
86///
87/// @param rowCount Number of rows.
88/// @param excluded Rows not to insert; an index beyond its size counts as not excluded.
89/// @param tryInsert Inserts one contiguous range of rows.
90/// @param classify Classifies the error of a failed insert.
91/// @param onRowFailed Called for each isolated failing row, in ascending order.
92/// @param onExcludedRow Called for each excluded row when it is reached, in ascending order.
93/// @param onSettled Called with the new settled prefix after every committed run, reported row or
94/// excluded row. The value never decreases; when an exception propagates, the last
95/// value reported equals the gap-free settled prefix at that moment.
96/// @throws SqlException for an error classified @ref FailureDisposition::Propagate.
97/// @throws TableRestoreFailure for an error classified @ref FailureDisposition::FailTable.
98LIGHTWEIGHT_API void InsertIsolatingFailures(std::size_t rowCount,
99 std::vector<bool> const& excluded,
100 RangeInserter const& tryInsert,
101 FailureClassifier const& classify,
102 RowFailureSink const& onRowFailed,
103 ExcludedRowSink const& onExcludedRow,
104 SettledSink const& onSettled);
105
106} // namespace Lightweight::detail