Lightweight 0.20261105.1
Loading...
Searching...
No Matches
SqlBackup.hpp
1// SPDX-License-Identifier: Apache-2.0
2#pragma once
3
4#include "../Api.hpp"
5#include "../SqlConnectInfo.hpp"
6#include "../SqlQuery/MigrationPlan.hpp"
7#include "../SqlRetryPolicy.hpp"
8#include "../SqlSchema.hpp"
9
10#include <chrono>
11#include <cstddef>
12#include <cstdint>
13#include <expected>
14#include <filesystem>
15#include <format>
16#include <map>
17#include <optional>
18#include <string>
19#include <string_view>
20#include <vector>
21
22/// @defgroup Backup Backup and Restore
23/// @brief Parallel chunked database dump and restore, with archive diffing.
24///
25/// Backups are taken online without a snapshot, so an archive carries no cross-table
26/// consistency guarantee.
27
28namespace Lightweight::SqlBackup
29{
30
31/// Compression methods supported for ZIP entries.
32///
33/// The values correspond to the ZIP compression method IDs used by libzip.
34/// Not all methods may be available at runtime depending on how libzip was compiled.
35/// Use IsCompressionMethodSupported() to check availability.
36// NOLINTNEXTLINE(performance-enum-size) - Values must match libzip ZIP_CM_* constants
37enum class CompressionMethod : std::int32_t
38{
39 Store = 0, ///< No compression (ZIP_CM_STORE)
40 Deflate = 8, ///< Deflate compression (ZIP_CM_DEFLATE) - most compatible
41 Bzip2 = 12, ///< Bzip2 compression (ZIP_CM_BZIP2)
42 Lzma = 14, ///< LZMA compression (ZIP_CM_LZMA)
43 Zstd = 93, ///< Zstandard compression (ZIP_CM_ZSTD)
44 Xz = 95, ///< XZ compression (ZIP_CM_XZ)
45};
46
47/// @ingroup Backup
48/// A caller-supplied file that a backup stores in its archive next to the table data.
49///
50/// The archive holds it as `attachments/<name>` and lists it in `checksums.json`; restore ignores it.
52{
53 /// The relative path within `attachments/` as UTF-8, with `/` separating folders (e.g. `notes/readme.txt`).
54 /// It must be well-formed UTF-8 without control characters, must not be empty, start or end with `/`,
55 /// contain a backslash or a colon, or have an empty, `.` or `..` path segment. Ignoring ASCII letter case,
56 /// it must differ from every other attachment's name and must not be the folder of another one.
57 std::string name {};
58
59 /// The bytes the archive stores for this attachment.
60 std::vector<std::uint8_t> content {};
61};
62
63/// @ingroup Backup
64/// Configuration for backup operations including compression and chunking.
66{
67 /// The compression method to use.
68 CompressionMethod method = CompressionMethod::Deflate;
69
70 /// The compression level (0-9).
71 /// - For Deflate: 1 = fastest, 9 = best compression, 6 = default
72 /// - For Bzip2: 1-9 (block size in 100k units)
73 /// - For Zstd: maps to zstd levels
74 /// - For Store: ignored
75 std::uint32_t level = 6;
76
77 /// The target size in bytes for each chunk before flushing.
78 /// Chunks are flushed when the buffer exceeds this size.
79 /// Default: 10 MB.
80 std::size_t chunkSizeBytes = 10 * 1024 * 1024;
81
82 /// Target rows per chunk window. Tables with a single numeric primary key are split into
83 /// windows of about this many keys (subject to a per-table window cap) that are backed up
84 /// in parallel by multiple workers.
85 std::size_t rowsPerChunk = 100'000;
86
87 /// Uncompressed bytes each worker accumulates in its private temp archive before sealing it
88 /// (the compression of that archive runs in the worker thread at that point, overlapped with
89 /// the network-bound fetch). Bounds worker memory at about jobs x workerArchiveBytes and
90 /// determines how many temp archives the finalize merge opens. Default: 256 MB.
91 std::size_t workerArchiveBytes = 256ULL * 1024 * 1024;
92
93 /// If true, only export schema metadata without backing up table data.
94 bool schemaOnly = false;
95
96 /// Deprecated no-op. Previously bypassed the MS SQL Server single-worker clamp; that clamp has
97 /// been removed (all databases now back up multi-threaded), so this flag no longer has any
98 /// effect. Retained temporarily to avoid an API/ABI break; pending removal.
100
101 /// Files to store in the archive, compressed with `method` and `level`, also by a schema-only
102 /// backup. An invalid or duplicate name fails the backup before it connects to the database.
103 std::vector<BackupAttachment> attachments {};
104};
105
106/// @ingroup Backup
107/// Configuration for restore operations including memory management.
109{
110 /// Batch size for insert operations (rows per batch).
111 /// Default: 0 (auto-calculated based on available memory).
112 std::size_t batchSize = 0;
113
114 /// The rows after which a chunk's transaction is committed and a new one begun, on a database
115 /// whose formatter bounds bulk-load transactions (SQLite, whose write-ahead log grows with the
116 /// open transaction); elsewhere a chunk commits as one transaction. 0 commits once per chunk.
117 /// Once a row of a chunk failed, the chunk commits batch by batch instead.
118 std::size_t maxRowsPerCommit = 10000;
119
120 /// Database page cache size in KB (used for SQLite PRAGMA cache_size,
121 /// could be extended for other DBMS memory hints).
122 /// Default: 65536 (64MB). Set to 0 to use database default.
123 std::size_t cacheSizeKB = 65536;
124
125 /// Memory limit in bytes (0 = auto-detect from system).
126 std::size_t memoryLimitBytes = 0;
127
128 /// If true, only recreate schema without importing data.
129 bool schemaOnly = false;
130};
131
132/// Returns available system memory in bytes.
133LIGHTWEIGHT_API std::size_t GetAvailableSystemMemory() noexcept;
134
135/// Calculates optimal restore settings based on available memory.
136///
137/// @param availableMemory Available system memory in bytes.
138/// @param concurrency Number of concurrent restore workers.
139/// @return RestoreSettings optimized for the given memory constraints.
140LIGHTWEIGHT_API RestoreSettings CalculateRestoreSettings(std::size_t availableMemory, unsigned concurrency);
141
142/// Checks if a compression method is supported by the current libzip installation.
143///
144/// @param method The compression method to check.
145/// @return true if the method is available for both compression and decompression.
146LIGHTWEIGHT_API bool IsCompressionMethodSupported(CompressionMethod method) noexcept;
147
148/// Returns a list of all compression methods that are supported by the current libzip installation.
149LIGHTWEIGHT_API std::vector<CompressionMethod> GetSupportedCompressionMethods() noexcept;
150
151/// Returns the human-readable name of a compression method.
152LIGHTWEIGHT_API std::string_view CompressionMethodName(CompressionMethod method) noexcept;
153
154/// Configuration for retry behavior on transient errors during backup/restore operations.
155///
156/// An alias for the library-wide @ref SqlRetrySettings: the backup engine was where this policy
157/// was first proven out, and it now shares one implementation with the rest of the library rather
158/// than keeping a parallel copy. The field names, types and defaults are unchanged, so existing
159/// designated-initializer call sites keep compiling verbatim.
160///
161/// @see SqlRetryPolicy
163
164/// Information about a table being backed up.
166{
167 /// The list of columns in the table in SQL format.
168 std::string fields;
169
170 /// The list of columns in the table.
171 std::vector<bool> isBinaryColumn;
172
173 /// The list of columns in the table.
174 std::vector<SqlColumnDeclaration> columns;
175
176 /// The list of foreign key constraints in the table.
177 std::vector<SqlSchema::ForeignKeyConstraint> foreignKeys;
178
179 /// The indexes on the table (excluding primary key index).
180 std::vector<SqlSchema::IndexDefinition> indexes;
181
182 /// The number of rows in the table.
183 size_t rowCount = 0;
184
185 /// The table's name in the database.
186 std::string name;
187
188 /// The table's schema as a multi-schema archive records it; empty for a single-schema archive,
189 /// whose tables all go into the schema the restore targets.
190 std::string schema;
191};
192
193/// @ingroup Backup
194/// Progress information for backup/restore operations status updates.
196{
197 /// The state of an individual backup/restore operation.
198 enum class State : std::uint8_t
199 {
200 Started,
201 InProgress,
202 Finished,
203 Error,
204 Warning
205 };
206
207 /// The state of an individual backup/restore operation.
209
210 /// The name of the table being backed up / restored.
211 std::string tableName;
212
213 /// The current number of rows processed.
214 size_t currentRows {};
215
216 /// The total number of rows to be processed, if known.
217 std::optional<size_t> totalRows;
218
219 /// A message associated with the progress update.
220 std::string message;
221};
222
223/// @ingroup Backup
224/// The interface for progress updates.
226{
227 virtual ~ProgressManager() = default;
228 /// Default constructor.
229 ProgressManager() = default;
230 /// Default copy constructor.
232 /// Default copy assignment operator.
234 /// Default move constructor.
236 /// Default move assignment operator.
238
239 /// Gets called when the progress of an individual backup/restore operation changes.
240 virtual void Update(Progress const& p) = 0;
241
242 /// Gets called when all backup/restore operations are finished.
243 virtual void AllDone() = 0;
244
245 /// Sets the maximum length of a table name.
246 /// This is used to align the output of the progress manager.
247 virtual void SetMaxTableNameLength(size_t /*len*/) {}
248
249 /// Returns the number of errors encountered during the operation.
250 [[nodiscard]] virtual size_t ErrorCount() const noexcept
251 {
252 return 0;
253 }
254
255 /// Sets the total number of items to be processed (for ETA calculation).
256 /// @param totalItems Total number of items (rows) to process across all tables.
257 virtual void SetTotalItems(size_t totalItems)
258 {
259 (void) totalItems;
260 }
261
262 /// Adds to the total number of items for progressive ETA calculation.
263 /// This is called as row counts become available during parallel counting.
264 /// @param additionalItems Number of additional items (rows) to add to the total.
265 virtual void AddTotalItems(size_t additionalItems)
266 {
267 (void) additionalItems;
268 }
269
270 /// Called when items are processed (for rate and ETA calculation).
271 /// @param count Number of items (rows) just processed.
272 virtual void OnItemsProcessed(size_t count)
273 {
274 (void) count;
275 }
276
277 /// Announces how many tables the operation will process, once, before any
278 /// per-table `Update()` is emitted.
279 ///
280 /// Backup knows the complete table set after its schema scan and Restore
281 /// after reading the archive manifest, i.e. both know the denominator before
282 /// any data moves. Without this hook a consumer can only count the distinct
283 /// table names it has seen so far, so a progress readout of the form
284 /// "processed / total" has a total that climbs as tables are discovered —
285 /// the GUI's per-table panel showed "12 / 12" then "12 / 47" then "12 / 700"
286 /// on the same run, which reads as the job getting bigger rather than as
287 /// progress being made.
288 ///
289 /// @param totalTables Number of tables that will be processed.
290 virtual void SetTotalTables(size_t totalTables)
291 {
292 (void) totalTables;
293 }
294};
295
296/// @ingroup Backup
297/// Base class for progress managers that tracks errors automatically.
299{
300 public:
301 void Update(Progress const& progress) override
302 {
303 if (progress.state == Progress::State::Error)
304 ++_errorCount;
305 }
306
307 [[nodiscard]] size_t ErrorCount() const noexcept override
308 {
309 return _errorCount;
310 }
311
312 private:
313 size_t _errorCount = 0;
314};
315
316struct NullProgressManager: ErrorTrackingProgressManager
317{
318 void Update(Progress const& progress) override
319 {
321 }
322 void AllDone() override {}
323};
324
325/// Backs up the database to a file.
326///
327/// @param outputFile the output file.
328/// @param connectionString the connection string used to connect to the database.
329/// @param concurrency the number of concurrent jobs.
330/// @param progress the progress manager to use for progress updates.
331/// @param schema the database schema to backup (optional).
332/// @param tableFilter comma-separated table filter patterns (default: "*" for all tables).
333/// Supports glob wildcards (* and ?) and schema.table notation.
334/// Examples: "Users,Products", "*_log", "dbo.Users", "sales.*"
335/// @param retrySettings configuration for retry behavior on transient errors.
336/// @param backupSettings configuration for compression method, level, and chunk size.
337LIGHTWEIGHT_API void Backup(std::filesystem::path const& outputFile,
338 SqlConnectionString const& connectionString,
339 unsigned concurrency,
340 ProgressManager& progress,
341 std::string const& schema = {},
342 std::string const& tableFilter = "*",
343 RetrySettings const& retrySettings = {},
344 BackupSettings const& backupSettings = {});
345
346/// Backs up the tables of several schemas to one file.
347///
348/// No schema or a single one writes exactly the archive @ref Backup writes for that schema. Two or
349/// more write a multi-schema archive (format version 2.0), which records each table's schema and
350/// each foreign key's referenced schema, so a restore recreates every table in its own schema.
351///
352/// @param outputFile the output file.
353/// @param connectionString the connection string used to connect to the database.
354/// @param concurrency the number of concurrent jobs.
355/// @param progress the progress manager to use for progress updates.
356/// @param schemas the database schemas to back up.
357/// @param tableFilter comma-separated table filter patterns, as for @ref Backup.
358/// @param retrySettings configuration for retry behavior on transient errors.
359/// @param backupSettings configuration for compression method, level, and chunk size.
360LIGHTWEIGHT_API void BackupSchemas(std::filesystem::path const& outputFile,
361 SqlConnectionString const& connectionString,
362 unsigned concurrency,
363 ProgressManager& progress,
364 std::vector<std::string> const& schemas,
365 std::string const& tableFilter = "*",
366 RetrySettings const& retrySettings = {},
367 BackupSettings const& backupSettings = {});
368
369/// Reads the schemas a backup archive records.
370///
371/// @param archiveFile the backup archive.
372/// @return One name (possibly empty) for a single-schema archive, several for a multi-schema
373/// archive, or an error message if the archive's metadata cannot be read.
374[[nodiscard]] LIGHTWEIGHT_API std::expected<std::vector<std::string>, std::string> ReadArchiveSchemas(
375 std::filesystem::path const& archiveFile);
376
377/// What `VerifyArchive` found.
379{
380 /// SHA-256 of the whole archive file, lowercase hex.
381 std::string archiveSha256;
382 /// Entries whose SHA-256 matched `checksums.json`.
383 std::size_t verifiedEntries = 0;
384 /// Whether the archive holds every table with its data: false for a filtered or schema-only backup
385 /// and for one in which a table failed (`metadata.json`'s `complete`; archives without it count as complete).
386 bool complete = true;
387};
388
389/// Checks that a backup archive is complete: it holds `metadata.json`, `checksums.json` lists every data
390/// entry (`data/...`) and every attachment (`attachments/...`, folder entries aside), and every listed
391/// entry's SHA-256 matches. An archive with neither data entries nor attachments (schema only) needs no
392/// `checksums.json`. Also hashes the whole file.
393///
394/// @param archiveFile The archive.
395/// @return The verification, or a message naming what is wrong.
396[[nodiscard]] LIGHTWEIGHT_API std::expected<ArchiveVerification, std::string> VerifyArchive(
397 std::filesystem::path const& archiveFile);
398
399/// Lists the attachments a backup archive holds (see @ref BackupAttachment).
400///
401/// The names are checked against the rules of @ref BackupAttachment::name, the ones a backup enforces, so
402/// a caller can use each name as a relative path, e.g. to extract the attachments below one folder.
403///
404/// @param archiveFile The archive.
405/// @return The attachment names without the `attachments/` prefix, sorted, or a message saying why the
406/// archive cannot be read or naming the first name that breaks those rules.
407[[nodiscard]] LIGHTWEIGHT_API std::expected<std::vector<std::string>, std::string> ListArchiveAttachments(
408 std::filesystem::path const& archiveFile);
409
410/// Reads one attachment of a backup archive (see @ref BackupAttachment).
411///
412/// `checksums.json` must list the attachment, with the SHA-256 of the bytes the archive holds.
413///
414/// @param archiveFile The archive.
415/// @param name The attachment's name, without the `attachments/` prefix.
416/// @return The attachment's bytes, or a message naming the attachment when it is missing, unreadable, not
417/// listed in `checksums.json` or does not match its checksum.
418[[nodiscard]] LIGHTWEIGHT_API std::expected<std::vector<std::uint8_t>, std::string> ReadArchiveAttachment(
419 std::filesystem::path const& archiveFile, std::string_view name);
420
421/// Decides what a schema that the caller did not ask for, but took from a default (a profile), means
422/// for restoring @p archiveFile.
423///
424/// A multi-schema archive refuses every target schema. A default that names one of its schemas is
425/// therefore dropped, so the archive restores into its own schemas; any other default is kept, so
426/// @ref Restore refuses it. Other archives keep the default.
427///
428/// @param archiveFile the backup archive.
429/// @param defaultSchema the default schema.
430/// @param caseInsensitive whether the target compares identifiers case-insensitively
431/// (`SqlQueryFormatter::IdentifiersAreCaseInsensitive()`).
432/// @return The schema to pass to @ref Restore.
433[[nodiscard]] LIGHTWEIGHT_API std::string DefaultRestoreSchema(std::filesystem::path const& archiveFile,
434 std::string const& defaultSchema,
435 bool caseInsensitive);
436
437/// Maximum number of failed-row ranges reported per table; further failing rows are only counted.
438inline constexpr std::size_t MaxReportedRowRanges = 100;
439/// Maximum number of distinct failure reasons reported per table; further occurrences are only counted.
440inline constexpr std::size_t MaxReportedReasons = 20;
441/// Maximum number of sample row keys kept per failure reason.
442inline constexpr std::size_t MaxSampleKeysPerReason = 3;
443
444/// Renders @p count with the noun that agrees with it.
445/// @param count The count.
446/// @param singular The noun for a count of 1, e.g. `"row"`.
447/// @param plural The noun for any other count, e.g. `"rows"`.
448/// @return `"<count> <singular>"` for a count of 1, `"<count> <plural>"` otherwise.
449[[nodiscard]] inline std::string CountOf(std::uint64_t count, std::string_view singular, std::string_view plural)
450{
451 return std::format("{} {}", count, count == 1 ? singular : plural);
452}
453
454/// A contiguous run of rows that failed to restore within one chunk.
456{
457 /// Archive path of the chunk the rows belong to.
458 std::string chunkPath;
459 /// First failed row (1-based, within the chunk).
460 std::uint64_t firstRow {};
461 /// Last failed row (1-based, within the chunk, inclusive).
462 std::uint64_t lastRow {};
463};
464
465/// One distinct failure cause of a table, with its occurrence count.
467{
468 /// SQLSTATE reported by the driver (may be empty).
469 std::string sqlState;
470 /// Message of the first occurrence, cut to at most 200 bytes (at a UTF-8 character boundary).
471 std::string message;
472 /// Number of failures sharing this reason.
473 std::uint64_t occurrences {};
474 /// A few example row keys (at most MaxSampleKeysPerReason).
475 std::vector<std::string> sampleKeys;
476};
477
478/// Cells of one column that were restored as NULL because their value could not be converted.
480{
481 /// Column name.
482 std::string column;
483 /// Number of cells set to NULL.
484 std::uint64_t cellsSetToNull {};
485 /// Reason of the first occurrence, cut to at most 200 bytes (at a UTF-8 character boundary).
486 std::string sampleReason;
487};
488
489/// Bounded failure report for one table.
491{
492 /// Name of the table.
493 std::string tableName;
494 /// Total number of rows that failed to restore. For a table that failed as a whole, the rows of
495 /// the archive that did not reach the target; that is 0 if the archive does not know the table's
496 /// row count, while tableFailure is still set.
497 std::uint64_t failedRowCount {};
498 /// Ranges of failed rows, capped at MaxReportedRowRanges.
499 std::vector<FailedRowRange> failedRowRanges;
500 /// Failed rows not represented in failedRowRanges because the cap was reached.
501 std::uint64_t rowsBeyondRangeCap {};
502 /// Distinct failure reasons, capped at MaxReportedReasons.
503 std::vector<FailureReason> reasons;
504 /// Failures not represented in reasons because the cap was reached.
506 /// Per-column value conversion failures.
507 std::vector<ColumnValueFailures> valueFailures;
508 /// Set if the whole table failed; holds the first reason.
509 std::optional<std::string> tableFailure;
510 /// Number of chunks of this table that could not be read.
511 std::uint64_t unreadableChunks {};
512
513 /// @return true if anything failed for this table.
514 [[nodiscard]] bool HasFailures() const noexcept
515 {
516 return failedRowCount != 0 || !failedRowRanges.empty() || !valueFailures.empty() || tableFailure.has_value()
517 || unreadableChunks != 0;
518 }
519
520 /// @return The number of cells of this table restored as NULL, over all columns.
521 [[nodiscard]] std::uint64_t NulledCellCount() const noexcept
522 {
523 auto count = std::uint64_t { 0 };
524 for (auto const& column: valueFailures)
525 count += column.cellsSetToNull;
526 return count;
527 }
528
529 /// @return The one-line summary of this table's failures, `"<n> rows failed, <m> cells set to NULL"`
530 /// (`"1 row failed"`, `"1 cell set to NULL"` for a count of 1).
531 [[nodiscard]] std::string FailureSummary() const
532 {
533 return std::format("{} failed, {} set to NULL",
534 CountOf(failedRowCount, "row", "rows"),
535 CountOf(NulledCellCount(), "cell", "cells"));
536 }
537};
538
539/// Bounded failure report of a whole restore.
541{
542 /// Only tables with failures, sorted by tableName.
543 std::vector<TableRestoreReport> tables;
544 /// Tables with chunks left unprocessed by a stopped worker.
545 std::vector<std::string> incompleteTables;
546 /// Unreadable archive entries no table could be named for.
547 std::uint64_t unattributedChunkErrors {};
548
549 /// @return The sum of TableRestoreReport::failedRowCount over all tables.
550 [[nodiscard]] std::uint64_t TotalFailedRows() const noexcept
551 {
552 auto count = std::uint64_t { 0 };
553 for (auto const& table: tables)
554 count += table.failedRowCount;
555 return count;
556 }
557
558 /// @return The sum of TableRestoreReport::NulledCellCount() over all tables.
559 [[nodiscard]] std::uint64_t NulledCellCount() const noexcept
560 {
561 auto count = std::uint64_t { 0 };
562 for (auto const& table: tables)
563 count += table.NulledCellCount();
564 return count;
565 }
566
567 /// @return true if a worker stopped early, leaving tables incomplete.
568 [[nodiscard]] bool WorkerStopped() const noexcept
569 {
570 return !incompleteTables.empty();
571 }
572
573 /// @return true if anything failed during the restore.
574 [[nodiscard]] bool HasFailures() const noexcept
575 {
576 return !tables.empty() || !incompleteTables.empty() || unattributedChunkErrors != 0;
577 }
578};
579
580/// Restores the database from a file.
581///
582/// A multi-schema archive restores every table into the schema it records, creating missing
583/// schemas; it refuses a target @p schema, and on a database without schemas (SQLite) it is
584/// refused unless every table name is unique across the schemas.
585///
586/// A value or row that fails to restore does not abort the restore: a value that does not convert
587/// to its nullable column becomes NULL, a row the database rejects (or whose NOT NULL value does not
588/// convert) is left out, and every other row is restored. A table fails as a whole only on an error
589/// that affects every row (e.g. the driver cannot bind a column type); its remaining chunks are
590/// skipped. A chunk that cannot be read is skipped. Only a lost connection that does not come back
591/// within @p retrySettings stops a worker. Errors are also reported through @p progress, at most one
592/// terminal update per table.
593///
594/// @param inputFile the input file.
595/// @param connectionString the connection string used to connect to the database.
596/// @param concurrency the number of concurrent jobs.
597/// @param progress the progress manager to use for progress updates.
598/// @param schema the database schema to restore into (optional, overrides backup metadata).
599/// @param tableFilter comma-separated table filter patterns (default: "*" for all tables).
600/// Supports glob wildcards (* and ?) and schema.table notation.
601/// Examples: "Users,Products", "*_log", "dbo.Users", "sales.*"
602/// @param retrySettings configuration for retry behavior on transient errors.
603/// @return The bounded report of what failed to restore; empty when everything was restored, and
604/// when the restore failed before restoring data (which @p progress reports).
605LIGHTWEIGHT_API RestoreReport Restore(std::filesystem::path const& inputFile,
606 SqlConnectionString const& connectionString,
607 unsigned concurrency,
608 ProgressManager& progress,
609 std::string const& schema = {},
610 std::string const& tableFilter = "*",
611 RetrySettings const& retrySettings = {});
612
613/// Restores the database from a file with explicit memory management settings.
614///
615/// @param inputFile the input file.
616/// @param connectionString the connection string used to connect to the database.
617/// @param concurrency the number of concurrent jobs.
618/// @param progress the progress manager to use for progress updates.
619/// @param schema the database schema to restore into (optional, overrides backup metadata).
620/// @param tableFilter comma-separated table filter patterns (default: "*" for all tables).
621/// @param retrySettings configuration for retry behavior on transient errors.
622/// @param restoreSettings configuration for memory management during restore.
623/// @return The bounded report of what failed to restore, as by the overload without @p restoreSettings.
624LIGHTWEIGHT_API RestoreReport Restore(std::filesystem::path const& inputFile,
625 SqlConnectionString const& connectionString,
626 unsigned concurrency,
627 ProgressManager& progress,
628 std::string const& schema,
629 std::string const& tableFilter,
630 RetrySettings const& retrySettings,
631 RestoreSettings const& restoreSettings);
632
633/// Returns a copy of `connectionString` with the values of `PWD=` and
634/// `Password=` attributes replaced by `***`.
635///
636/// Same as @ref SqlConnectionString::SanitizePwd, which defines the quoting
637/// and key-matching rules and is also what dbtool's `list-profiles` applies.
638/// Applied by CreateMetadata() so a secretRef-resolved plaintext password
639/// never lands in an archive's metadata.json.
640///
641/// @param connectionString Raw ODBC connection string.
642/// @return The connection string with password values masked.
643[[nodiscard]] LIGHTWEIGHT_API std::string RedactConnectionStringSecrets(std::string_view connectionString);
644
645/// Creates the metadata JSON content.
646///
647/// @param connectionString the connection string used to connect to the database.
648/// @param tables the list of tables to backup.
649/// @param schema the database schema used for these tables (optional).
650LIGHTWEIGHT_API std::string CreateMetadata(SqlConnectionString const& connectionString,
651 SqlSchema::TableList const& tables,
652 std::string const& schema = {});
653
654/// Parses the metadata JSON content and returns a map of table info.
655///
656/// A single-schema archive keys each table by its name, a multi-schema archive by `schema.name`.
657///
658/// @param metadataJson content of the metadata.json file.
659LIGHTWEIGHT_API std::map<std::string, TableInfo> ParseSchema(std::string_view metadataJson,
660 ProgressManager* progress = nullptr);
661
662} // namespace Lightweight::SqlBackup
size_t ErrorCount() const noexcept override
Returns the number of errors encountered during the operation.
void Update(Progress const &progress) override
Gets called when the progress of an individual backup/restore operation changes.
std::string archiveSha256
SHA-256 of the whole archive file, lowercase hex.
std::size_t verifiedEntries
Entries whose SHA-256 matched checksums.json.
std::vector< std::uint8_t > content
The bytes the archive stores for this attachment.
Definition SqlBackup.hpp:60
CompressionMethod method
The compression method to use.
Definition SqlBackup.hpp:68
std::vector< BackupAttachment > attachments
bool schemaOnly
If true, only export schema metadata without backing up table data.
Definition SqlBackup.hpp:94
Cells of one column that were restored as NULL because their value could not be converted.
std::uint64_t cellsSetToNull
Number of cells set to NULL.
std::string sampleReason
Reason of the first occurrence, cut to at most 200 bytes (at a UTF-8 character boundary).
A contiguous run of rows that failed to restore within one chunk.
std::uint64_t lastRow
Last failed row (1-based, within the chunk, inclusive).
std::string chunkPath
Archive path of the chunk the rows belong to.
std::uint64_t firstRow
First failed row (1-based, within the chunk).
One distinct failure cause of a table, with its occurrence count.
std::string sqlState
SQLSTATE reported by the driver (may be empty).
std::vector< std::string > sampleKeys
A few example row keys (at most MaxSampleKeysPerReason).
std::string message
Message of the first occurrence, cut to at most 200 bytes (at a UTF-8 character boundary).
std::uint64_t occurrences
Number of failures sharing this reason.
virtual void SetTotalItems(size_t totalItems)
ProgressManager()=default
Default constructor.
virtual void SetTotalTables(size_t totalTables)
virtual void Update(Progress const &p)=0
Gets called when the progress of an individual backup/restore operation changes.
virtual void SetMaxTableNameLength(size_t)
virtual size_t ErrorCount() const noexcept
Returns the number of errors encountered during the operation.
ProgressManager & operator=(ProgressManager const &)=default
Default copy assignment operator.
virtual void OnItemsProcessed(size_t count)
ProgressManager(ProgressManager &&)=default
Default move constructor.
ProgressManager & operator=(ProgressManager &&)=default
Default move assignment operator.
virtual void AddTotalItems(size_t additionalItems)
virtual void AllDone()=0
Gets called when all backup/restore operations are finished.
ProgressManager(ProgressManager const &)=default
Default copy constructor.
size_t currentRows
The current number of rows processed.
State state
The state of an individual backup/restore operation.
std::string message
A message associated with the progress update.
std::optional< size_t > totalRows
The total number of rows to be processed, if known.
std::string tableName
The name of the table being backed up / restored.
State
The state of an individual backup/restore operation.
Bounded failure report of a whole restore.
std::vector< std::string > incompleteTables
Tables with chunks left unprocessed by a stopped worker.
std::uint64_t TotalFailedRows() const noexcept
std::uint64_t unattributedChunkErrors
Unreadable archive entries no table could be named for.
std::uint64_t NulledCellCount() const noexcept
std::vector< TableRestoreReport > tables
Only tables with failures, sorted by tableName.
bool WorkerStopped() const noexcept
std::size_t memoryLimitBytes
Memory limit in bytes (0 = auto-detect from system).
bool schemaOnly
If true, only recreate schema without importing data.
Information about a table being backed up.
std::string name
The table's name in the database.
std::vector< SqlColumnDeclaration > columns
The list of columns in the table.
std::vector< SqlSchema::IndexDefinition > indexes
The indexes on the table (excluding primary key index).
std::vector< bool > isBinaryColumn
The list of columns in the table.
std::vector< SqlSchema::ForeignKeyConstraint > foreignKeys
The list of foreign key constraints in the table.
std::string fields
The list of columns in the table in SQL format.
Bounded failure report for one table.
std::vector< FailureReason > reasons
Distinct failure reasons, capped at MaxReportedReasons.
std::string tableName
Name of the table.
std::uint64_t occurrencesBeyondReasonCap
Failures not represented in reasons because the cap was reached.
std::uint64_t rowsBeyondRangeCap
Failed rows not represented in failedRowRanges because the cap was reached.
std::vector< FailedRowRange > failedRowRanges
Ranges of failed rows, capped at MaxReportedRowRanges.
std::uint64_t NulledCellCount() const noexcept
std::vector< ColumnValueFailures > valueFailures
Per-column value conversion failures.
std::uint64_t unreadableChunks
Number of chunks of this table that could not be read.
std::optional< std::string > tableFailure
Set if the whole table failed; holds the first reason.