dbgate-sqlite-dumper 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,3902 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ BufferDumpWriter: () => BufferDumpWriter,
24
+ COMPLETE_TRANSITIONS: () => COMPLETE_TRANSITIONS,
25
+ CompleteToken: () => CompleteToken,
26
+ DEFENSIVE_WARNING_COMMENT: () => DEFENSIVE_WARNING_COMMENT,
27
+ InvalidTextEncodingError: () => InvalidTextEncodingError,
28
+ MalformedSqlDumpError: () => MalformedSqlDumpError,
29
+ OperationCancelledError: () => OperationCancelledError,
30
+ RestoreError: () => RestoreError,
31
+ RestoreExecutionError: () => RestoreExecutionError,
32
+ RestoreSessionState: () => RestoreSessionState,
33
+ SEQUENCE_TABLE_NAME: () => SEQUENCE_TABLE_NAME,
34
+ SESSION_GUARD_FOOTER: () => SESSION_GUARD_FOOTER,
35
+ SESSION_GUARD_HEADER: () => SESSION_GUARD_HEADER,
36
+ SQLITE_KEYWORD_COUNT: () => SQLITE_KEYWORD_COUNT,
37
+ SqlChunkBuilder: () => SqlChunkBuilder,
38
+ SqlParseError: () => SqlParseError,
39
+ SqlStatementParser: () => SqlStatementParser,
40
+ SqliteDumperError: () => SqliteDumperError,
41
+ StatementTooLargeError: () => StatementTooLargeError,
42
+ StreamDumpWriter: () => StreamDumpWriter,
43
+ UNSUPPORTED_FEATURES: () => UNSUPPORTED_FEATURES,
44
+ UnsupportedClientCommandError: () => UnsupportedClientCommandError,
45
+ WRITABLE_SCHEMA_OFF: () => WRITABLE_SCHEMA_OFF,
46
+ WRITABLE_SCHEMA_ON: () => WRITABLE_SCHEMA_ON,
47
+ acquireSqliteConnection: () => acquireSqliteConnection,
48
+ assignDumpSection: () => assignDumpSection,
49
+ beginSqliteDumpSession: () => beginSqliteDumpSession,
50
+ checkTargetCompatibility: () => checkTargetCompatibility,
51
+ classifyWord: () => classifyWord,
52
+ columnValueSelect: () => columnValueSelect,
53
+ completeTransition: () => completeTransition,
54
+ createArchiveIdentity: () => createArchiveIdentity,
55
+ createCanonicalIdentity: () => createCanonicalIdentity,
56
+ createDumpId: () => createDumpId,
57
+ declaresAutoincrement: () => declaresAutoincrement,
58
+ decodeStatementBytes: () => decodeStatementBytes,
59
+ describeStatement: () => describeStatement,
60
+ detectSqliteCapabilities: () => detectSqliteCapabilities,
61
+ detectSqliteVersion: () => detectSqliteVersion,
62
+ detectTargetCapabilities: () => detectSqliteCapabilities,
63
+ dumpSectionPriority: () => dumpSectionPriority,
64
+ dumpSqlite: () => dumpSqlite,
65
+ executeStatement: () => executeStatement,
66
+ exportTableDataAsInserts: () => exportTableDataAsInserts,
67
+ foldSqliteName: () => foldSqliteName,
68
+ insertableColumns: () => insertableColumns,
69
+ inspectDumpArchive: () => inspectDumpArchive,
70
+ introspectSqlite: () => introspectSqlite,
71
+ isAbortError: () => isAbortError,
72
+ isCompleteStatement: () => isCompleteStatement,
73
+ isIdentifierCharCode: () => isIdentifierCharCode,
74
+ isIndexSelected: () => isIndexSelected,
75
+ isSchemaTableName: () => isSchemaTableName,
76
+ isSqliteConnectionSource: () => isSqliteConnectionSource,
77
+ isSqliteDump: () => isSqliteDump,
78
+ isSqliteKeyword: () => isSqliteKeyword,
79
+ isStatisticsTableName: () => isStatisticsTableName,
80
+ isTableDataExcluded: () => isTableDataExcluded,
81
+ isTableSelected: () => isTableSelected,
82
+ isTriggerSelected: () => isTriggerSelected,
83
+ isTruthyPragmaValue: () => isTruthyPragmaValue,
84
+ isViewSelected: () => isViewSelected,
85
+ maskSqlLiterals: () => maskSqlLiterals,
86
+ needsIdentifierQuoting: () => needsIdentifierQuoting,
87
+ normalizeDumpSelection: () => normalizeDumpSelection,
88
+ parseSqlStatements: () => parseSqlStatements,
89
+ parseSqliteVersion: () => parseSqliteVersion,
90
+ parseTableOptions: () => parseTableOptions,
91
+ parseVirtualTableModule: () => parseVirtualTableModule,
92
+ preflightRestore: () => preflightRestore,
93
+ preservableRowidName: () => preservableRowidName,
94
+ quoteIdentifier: () => quoteIdentifier,
95
+ quoteIdentifierIfNeeded: () => quoteIdentifierIfNeeded,
96
+ quoteQualifiedIdentifier: () => quoteQualifiedIdentifier,
97
+ quoteStringLiteral: () => quoteStringLiteral,
98
+ redactSecrets: () => redactSecrets,
99
+ renderBlobLiteral: () => renderBlobLiteral,
100
+ renderColumnLiteral: () => renderColumnLiteral,
101
+ renderDatabaseSettings: () => renderDatabaseSettings,
102
+ renderDrop: () => renderDrop,
103
+ renderEscapedStringLiteral: () => renderEscapedStringLiteral,
104
+ renderPlainSql: () => renderPlainSql,
105
+ renderQuotedStringLiteral: () => renderQuotedStringLiteral,
106
+ renderSchemaLine: () => renderSchemaLine,
107
+ renderSchemaObject: () => renderSchemaObject,
108
+ renderSystemTablePrelude: () => renderSystemTablePrelude,
109
+ renderTextLiteral: () => renderTextLiteral,
110
+ renderVirtualTable: () => renderVirtualTable,
111
+ resolvePlainSqlRenderOptions: () => resolvePlainSqlRenderOptions,
112
+ restoreSqlDump: () => restoreSqlDump,
113
+ safeSqlPreview: () => safeSqlPreview,
114
+ streamSqlStatements: () => streamSqlStatements,
115
+ streamWithParser: () => streamWithParser,
116
+ tableGroupPriority: () => tableGroupPriority,
117
+ throwIfAborted: () => throwIfAborted2,
118
+ toAsciiLowerCase: () => toAsciiLowerCase,
119
+ toAsciiUpperCase: () => toAsciiUpperCase,
120
+ toByteStringChunks: () => toByteStringChunks,
121
+ toNumber: () => toNumber,
122
+ toText: () => toText,
123
+ unsupportedFeatureDiagnostics: () => unsupportedFeatureDiagnostics
124
+ });
125
+ module.exports = __toCommonJS(src_exports);
126
+
127
+ // src/connection/types.ts
128
+ function isSqliteConnectionSource(input) {
129
+ return typeof input.acquire === "function";
130
+ }
131
+
132
+ // src/connection/acquire.ts
133
+ async function acquireSqliteConnection(input, signal) {
134
+ if (isSqliteConnectionSource(input)) {
135
+ return input.acquire(signal);
136
+ }
137
+ return {
138
+ connection: input,
139
+ dedicated: false,
140
+ release: async () => {
141
+ }
142
+ };
143
+ }
144
+ async function executeStatement(connection, sql, signal) {
145
+ if (connection.execute) {
146
+ return connection.execute(sql, signal);
147
+ }
148
+ await connection.query({ sql }, signal);
149
+ return { changes: 0 };
150
+ }
151
+ function toNumber(value, fallback = 0) {
152
+ if (typeof value === "number") {
153
+ return value;
154
+ }
155
+ if (typeof value === "bigint") {
156
+ return Number(value);
157
+ }
158
+ if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) {
159
+ return Number(value);
160
+ }
161
+ return fallback;
162
+ }
163
+ function toText(value) {
164
+ if (value === null || value === void 0) {
165
+ return null;
166
+ }
167
+ if (typeof value === "string") {
168
+ return value;
169
+ }
170
+ if (value instanceof Uint8Array) {
171
+ return Buffer.from(value).toString("utf8");
172
+ }
173
+ return String(value);
174
+ }
175
+
176
+ // src/connection/session.ts
177
+ var DUMP_SAVEPOINT = "dbgate_sqlite_dump";
178
+ async function beginSqliteDumpSession(connection, options, signal) {
179
+ const consistency = options?.consistency ?? "snapshot";
180
+ const joinedExistingTransaction = connection.isInTransaction?.() ?? false;
181
+ if (consistency === "none") {
182
+ return { consistency, joinedExistingTransaction, finish: async () => {
183
+ } };
184
+ }
185
+ await executeStatement(connection, `SAVEPOINT ${DUMP_SAVEPOINT}`, signal);
186
+ let finished = false;
187
+ const finish = async () => {
188
+ if (finished) {
189
+ return;
190
+ }
191
+ finished = true;
192
+ await executeStatement(connection, `RELEASE ${DUMP_SAVEPOINT}`).catch(() => {
193
+ });
194
+ };
195
+ try {
196
+ await connection.query({ sql: "SELECT count(*) AS n FROM sqlite_master" }, signal);
197
+ } catch (error) {
198
+ await finish();
199
+ throw error;
200
+ }
201
+ return { consistency, joinedExistingTransaction, finish };
202
+ }
203
+
204
+ // src/version/types.ts
205
+ function parseSqliteVersion(versionString) {
206
+ const match = /^(\d+)\.(\d+)(?:\.(\d+))?/.exec(versionString.trim());
207
+ if (!match) {
208
+ throw new Error(`Cannot parse SQLite version string: ${JSON.stringify(versionString)}`);
209
+ }
210
+ const majorVersion = Number(match[1]);
211
+ const minorVersion = Number(match[2]);
212
+ const patchVersion = match[3] === void 0 ? 0 : Number(match[3]);
213
+ return {
214
+ majorVersion,
215
+ minorVersion,
216
+ patchVersion,
217
+ versionNumber: majorVersion * 1e6 + minorVersion * 1e3 + patchVersion
218
+ };
219
+ }
220
+
221
+ // src/version/detect.ts
222
+ async function detectSqliteVersion(connection, signal) {
223
+ const result = await connection.query(
224
+ { sql: "SELECT sqlite_version() AS versionString" },
225
+ signal
226
+ );
227
+ const versionString = toText(result.rows[0]?.versionString);
228
+ if (!versionString) {
229
+ throw new Error("Unable to detect SQLite version: sqlite_version() returned no data");
230
+ }
231
+ let sourceId;
232
+ try {
233
+ const source = await connection.query(
234
+ { sql: "SELECT sqlite_source_id() AS sourceId" },
235
+ signal
236
+ );
237
+ sourceId = toText(source.rows[0]?.sourceId) ?? void 0;
238
+ } catch {
239
+ }
240
+ return {
241
+ versionString,
242
+ ...parseSqliteVersion(versionString),
243
+ ...sourceId === void 0 ? {} : { sourceId }
244
+ };
245
+ }
246
+
247
+ // src/version/capabilities.ts
248
+ function detectSqliteCapabilities(version) {
249
+ const atLeast = (target) => version.versionNumber >= target;
250
+ return {
251
+ supportsWithoutRowid: atLeast(3008002),
252
+ supportsMultiRowValues: atLeast(3007011),
253
+ supportsPragmaFunctions: atLeast(3016e3),
254
+ supportsTableXinfo: atLeast(3026e3),
255
+ supportsGeneratedColumns: atLeast(3031e3),
256
+ supportsSqliteSchemaAlias: atLeast(3033e3),
257
+ supportsWritableSchemaReset: atLeast(3035e3),
258
+ supportsStrictTables: atLeast(3037e3),
259
+ supportsTableList: atLeast(3037e3)
260
+ };
261
+ }
262
+
263
+ // src/security/identifiers.ts
264
+ var SQLITE_KEYWORDS = new Set(
265
+ `ABORT ACTION ADD AFTER ALL ALTER ALWAYS ANALYZE AND AS ASC ATTACH AUTOINCREMENT BEFORE BEGIN
266
+ BETWEEN BY CASCADE CASE CAST CHECK COLLATE COLUMN COMMIT CONFLICT CONSTRAINT CREATE CROSS
267
+ CURRENT CURRENT_DATE CURRENT_TIME CURRENT_TIMESTAMP DATABASE DEFAULT DEFERRABLE DEFERRED DELETE
268
+ DESC DETACH DISTINCT DO DROP EACH ELSE END ESCAPE EXCEPT EXCLUDE EXCLUSIVE EXISTS EXPLAIN FAIL
269
+ FILTER FIRST FOLLOWING FOR FOREIGN FROM FULL GENERATED GLOB GROUP GROUPS HAVING IF IGNORE
270
+ IMMEDIATE IN INDEX INDEXED INITIALLY INNER INSERT INSTEAD INTERSECT INTO IS ISNULL JOIN KEY LAST
271
+ LEFT LIKE LIMIT MATCH MATERIALIZED NATURAL NO NOT NOTHING NOTNULL NULL NULLS OF OFFSET ON OR
272
+ ORDER OTHERS OUTER OVER PARTITION PLAN PRAGMA PRECEDING PRIMARY QUERY RAISE RANGE RECURSIVE
273
+ REFERENCES REGEXP REINDEX RELEASE RENAME REPLACE RESTRICT RETURNING RIGHT ROLLBACK ROW ROWS
274
+ SAVEPOINT SELECT SET TABLE TEMP TEMPORARY THEN TIES TO TRANSACTION TRIGGER UNBOUNDED UNION
275
+ UNIQUE UPDATE USING VACUUM VALUES VIEW VIRTUAL WHEN WHERE WINDOW WITH WITHOUT`.split(/\s+/).filter((word) => word !== "")
276
+ );
277
+ function isSqliteKeyword(name) {
278
+ return SQLITE_KEYWORDS.has(toAsciiUpperCase(name));
279
+ }
280
+ var SQLITE_KEYWORD_COUNT = SQLITE_KEYWORDS.size;
281
+ function isAsciiAlpha(code) {
282
+ return code >= 65 && code <= 90 || code >= 97 && code <= 122;
283
+ }
284
+ function isAsciiDigit(code) {
285
+ return code >= 48 && code <= 57;
286
+ }
287
+ function toAsciiUpperCase(value) {
288
+ return value.replace(/[a-z]+/g, (run) => run.toUpperCase());
289
+ }
290
+ function toAsciiLowerCase(value) {
291
+ return value.replace(/[A-Z]+/g, (run) => run.toLowerCase());
292
+ }
293
+ function needsIdentifierQuoting(name) {
294
+ if (name.length === 0) {
295
+ return true;
296
+ }
297
+ const first = name.charCodeAt(0);
298
+ if (!isAsciiAlpha(first) && first !== 95) {
299
+ return true;
300
+ }
301
+ for (let index = 0; index < name.length; index++) {
302
+ const code = name.charCodeAt(index);
303
+ if (!isAsciiAlpha(code) && !isAsciiDigit(code) && code !== 95) {
304
+ return true;
305
+ }
306
+ }
307
+ return isSqliteKeyword(name);
308
+ }
309
+ function quoteIdentifier(name) {
310
+ return `"${name.replace(/"/g, '""')}"`;
311
+ }
312
+ function quoteIdentifierIfNeeded(name) {
313
+ return needsIdentifierQuoting(name) ? quoteIdentifier(name) : name;
314
+ }
315
+ function quoteQualifiedIdentifier(schemaName, name) {
316
+ return `${quoteIdentifier(schemaName)}.${quoteIdentifier(name)}`;
317
+ }
318
+
319
+ // src/selection/normalize.ts
320
+ function foldSqliteName(name) {
321
+ return toAsciiLowerCase(name);
322
+ }
323
+ function toSet(names) {
324
+ return names ? new Set(names.map(foldSqliteName)) : void 0;
325
+ }
326
+ function normalizeDumpSelection(selection) {
327
+ const normalized = {
328
+ tables: toSet(selection?.tables),
329
+ excludeTables: new Set((selection?.excludeTables ?? []).map(foldSqliteName)),
330
+ views: toSet(selection?.views),
331
+ excludeViews: new Set((selection?.excludeViews ?? []).map(foldSqliteName)),
332
+ triggers: toSet(selection?.triggers),
333
+ excludeTriggers: new Set((selection?.excludeTriggers ?? []).map(foldSqliteName)),
334
+ excludeIndexes: new Set((selection?.excludeIndexes ?? []).map(foldSqliteName)),
335
+ dataExcludedTables: new Set((selection?.dataExcludedTables ?? []).map(foldSqliteName))
336
+ };
337
+ const isPartial = normalized.tables !== void 0 || normalized.views !== void 0 || normalized.triggers !== void 0 || normalized.excludeTables.size > 0 || normalized.excludeViews.size > 0 || normalized.excludeTriggers.size > 0 || normalized.excludeIndexes.size > 0;
338
+ return { ...normalized, isPartial };
339
+ }
340
+ function isSelected(name, include, exclude) {
341
+ const key = foldSqliteName(name);
342
+ if (exclude.has(key)) {
343
+ return false;
344
+ }
345
+ return include ? include.has(key) : true;
346
+ }
347
+ function isTableSelected(name, selection) {
348
+ return isSelected(name, selection.tables, selection.excludeTables);
349
+ }
350
+ function isViewSelected(name, selection) {
351
+ return isSelected(name, selection.views, selection.excludeViews);
352
+ }
353
+ function isTriggerSelected(name, selection) {
354
+ return isSelected(name, selection.triggers, selection.excludeTriggers);
355
+ }
356
+ function isIndexSelected(name, selection) {
357
+ return !selection.excludeIndexes.has(foldSqliteName(name));
358
+ }
359
+ function isTableDataExcluded(name, selection) {
360
+ return selection.dataExcludedTables.has(foldSqliteName(name));
361
+ }
362
+
363
+ // src/security/literals.ts
364
+ function unusedString(text, a, b) {
365
+ if (!text.includes(a)) {
366
+ return a;
367
+ }
368
+ if (!text.includes(b)) {
369
+ return b;
370
+ }
371
+ for (let counter = 0; ; counter++) {
372
+ const candidate = `(${a}${counter})`;
373
+ if (!text.includes(candidate)) {
374
+ return candidate;
375
+ }
376
+ }
377
+ }
378
+ function renderQuotedStringLiteral(text) {
379
+ return `'${text.replace(/'/g, "''")}'`;
380
+ }
381
+ function renderEscapedStringLiteral(text) {
382
+ if (!text.includes("\n") && !text.includes("\r")) {
383
+ return renderQuotedStringLiteral(text);
384
+ }
385
+ const hasNewline = text.includes("\n");
386
+ const hasCarriageReturn = text.includes("\r");
387
+ const newlinePlaceholder = hasNewline ? unusedString(text, "\\n", "\\012") : "";
388
+ const carriageReturnPlaceholder = hasCarriageReturn ? unusedString(text, "\\r", "\\015") : "";
389
+ let body = "";
390
+ for (let index = 0; index < text.length; index++) {
391
+ const character = text[index];
392
+ if (character === "'") {
393
+ body += "''";
394
+ } else if (character === "\n") {
395
+ body += newlinePlaceholder;
396
+ } else if (character === "\r") {
397
+ body += carriageReturnPlaceholder;
398
+ } else {
399
+ body += character;
400
+ }
401
+ }
402
+ let literal = `${hasNewline ? "replace(" : ""}${hasCarriageReturn ? "replace(" : ""}'${body}'`;
403
+ if (hasCarriageReturn) {
404
+ literal += `,'${carriageReturnPlaceholder}',char(13))`;
405
+ }
406
+ if (hasNewline) {
407
+ literal += `,'${newlinePlaceholder}',char(10))`;
408
+ }
409
+ return literal;
410
+ }
411
+ function renderTextLiteral(text, style = "escaped") {
412
+ const render = style === "escaped" ? renderEscapedStringLiteral : renderQuotedStringLiteral;
413
+ if (!text.includes("\0")) {
414
+ return render(text);
415
+ }
416
+ return text.split("\0").map(render).join("||char(0)||");
417
+ }
418
+ function renderBlobLiteral(value) {
419
+ return `X'${Buffer.from(value.buffer, value.byteOffset, value.byteLength).toString("hex")}'`;
420
+ }
421
+ function quoteStringLiteral(text) {
422
+ return renderQuotedStringLiteral(text);
423
+ }
424
+
425
+ // src/security/redact.ts
426
+ var SQL_SECRET_PATTERNS = [
427
+ // PRAGMA [schema.]key = 'secret' / PRAGMA key('secret'), and the rekey/hexkey/textkey forms
428
+ /(\bPRAGMA\s+(?:[\w"`[\]]+\s*\.\s*)?(?:hex|text)?(?:re)?key\s*(?:=\s*|\(\s*))(?:'(?:[^']|'')*'|"(?:[^"]|"")*"|[^\s;)]+)/gi,
429
+ // ATTACH DATABASE 'file' AS name KEY 'secret'
430
+ /(\bATTACH\b[\s\S]*?\bKEY\s+)(?:'(?:[^']|'')*'|"(?:[^"]|"")*"|X'[0-9A-Fa-f]*'|[^\s;)]+)/gi
431
+ ];
432
+ function redactSecrets(text) {
433
+ return SQL_SECRET_PATTERNS.reduce(
434
+ (result, pattern) => result.replace(pattern, (_match, prefix) => `${prefix}'***REDACTED***'`),
435
+ text
436
+ );
437
+ }
438
+
439
+ // src/writer/streamWriter.ts
440
+ function throwIfAborted(signal) {
441
+ if (signal?.aborted) {
442
+ throw new DOMException("The operation was aborted.", "AbortError");
443
+ }
444
+ }
445
+ var StreamDumpWriter = class {
446
+ stream;
447
+ bytes = 0;
448
+ writeError = null;
449
+ constructor(stream) {
450
+ this.stream = stream;
451
+ }
452
+ get bytesWritten() {
453
+ return this.bytes;
454
+ }
455
+ async write(chunk, signal) {
456
+ if (chunk.length === 0) {
457
+ return;
458
+ }
459
+ if (this.writeError) {
460
+ throw this.writeError;
461
+ }
462
+ throwIfAborted(signal);
463
+ const isBuffer = Buffer.isBuffer(chunk);
464
+ this.bytes += isBuffer ? chunk.length : Buffer.byteLength(chunk, "utf8");
465
+ const onWritten = (error) => {
466
+ if (error && !this.writeError) {
467
+ this.writeError = error;
468
+ }
469
+ };
470
+ const canWriteMore = isBuffer ? this.stream.write(chunk, onWritten) : this.stream.write(chunk, "utf8", onWritten);
471
+ if (canWriteMore === false) {
472
+ await new Promise((resolve, reject) => {
473
+ const cleanup = () => {
474
+ this.stream.removeListener("drain", onDrain);
475
+ this.stream.removeListener("error", onError);
476
+ signal?.removeEventListener("abort", onAbort);
477
+ };
478
+ const onDrain = () => {
479
+ cleanup();
480
+ resolve();
481
+ };
482
+ const onError = (error) => {
483
+ cleanup();
484
+ reject(error);
485
+ };
486
+ const onAbort = () => {
487
+ cleanup();
488
+ reject(new DOMException("The operation was aborted.", "AbortError"));
489
+ };
490
+ this.stream.once("drain", onDrain);
491
+ this.stream.once("error", onError);
492
+ signal?.addEventListener("abort", onAbort, { once: true });
493
+ });
494
+ }
495
+ if (this.writeError) {
496
+ throw this.writeError;
497
+ }
498
+ throwIfAborted(signal);
499
+ }
500
+ };
501
+
502
+ // src/writer/bufferWriter.ts
503
+ var BufferDumpWriter = class {
504
+ chunks = [];
505
+ bytes = 0;
506
+ get bytesWritten() {
507
+ return this.bytes;
508
+ }
509
+ async write(chunk, signal) {
510
+ if (signal?.aborted) {
511
+ throw new DOMException("The operation was aborted.", "AbortError");
512
+ }
513
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
514
+ this.chunks.push(buffer);
515
+ this.bytes += buffer.length;
516
+ }
517
+ toBuffer() {
518
+ return Buffer.concat(this.chunks);
519
+ }
520
+ toString() {
521
+ return this.toBuffer().toString("utf8");
522
+ }
523
+ };
524
+
525
+ // src/archive/sectionRules.ts
526
+ var SECTION_BY_OBJECT_TYPE = {
527
+ table: "tables",
528
+ tableData: "tables",
529
+ virtualTable: "tables",
530
+ index: "schema",
531
+ trigger: "schema",
532
+ view: "schema"
533
+ };
534
+ var SECTION_PRIORITY = {
535
+ tables: 0,
536
+ schema: 1
537
+ };
538
+ var TABLE_GROUP_PRIORITY = {
539
+ table: 0,
540
+ virtualTable: 0,
541
+ tableData: 1,
542
+ index: 0,
543
+ trigger: 0,
544
+ view: 0
545
+ };
546
+ function assignDumpSection(objectType) {
547
+ return SECTION_BY_OBJECT_TYPE[objectType];
548
+ }
549
+ function dumpSectionPriority(section) {
550
+ return SECTION_PRIORITY[section];
551
+ }
552
+ function tableGroupPriority(objectType) {
553
+ return TABLE_GROUP_PRIORITY[objectType];
554
+ }
555
+
556
+ // src/utils/hash.ts
557
+ var import_node_crypto = require("crypto");
558
+ function createCanonicalIdentity(parts) {
559
+ return parts.map((part) => `${part.length}:${part}`).join("|");
560
+ }
561
+ function createDumpId(identity) {
562
+ return (0, import_node_crypto.createHash)("sha1").update(identity, "utf8").digest("hex").slice(0, 16);
563
+ }
564
+
565
+ // src/archive/identity.ts
566
+ function createArchiveIdentity(input) {
567
+ return createCanonicalIdentity([
568
+ input.objectType,
569
+ input.schemaName,
570
+ input.name,
571
+ input.parentName ?? ""
572
+ ]);
573
+ }
574
+
575
+ // src/archive/planner.ts
576
+ function isStatisticsTableName(name) {
577
+ return /^sqlite_stat[\s\S]$/.test(name);
578
+ }
579
+ var SEQUENCE_TABLE_NAME = "sqlite_sequence";
580
+ function inspectDumpArchive(database, options = {}) {
581
+ const mode = options.mode ?? "full";
582
+ const selection = options.selection ?? normalizeDumpSelection();
583
+ const kinds = options.objectKinds ?? {};
584
+ const includeTables = kinds.includeTables ?? true;
585
+ const includeViews = kinds.includeViews ?? true;
586
+ const includeIndexes = kinds.includeIndexes ?? true;
587
+ const includeTriggers = kinds.includeTriggers ?? true;
588
+ const includeVirtualTables = kinds.includeVirtualTables ?? true;
589
+ const includeSystemTables = kinds.includeSystemTables ?? true;
590
+ const wantsSchema = mode !== "data-only";
591
+ const wantsData = mode !== "schema-only";
592
+ const schemaName = database.schemaName;
593
+ const diagnostics = [];
594
+ const entries = [];
595
+ const byDumpId = /* @__PURE__ */ new Map();
596
+ function addEntry(objectType, name, extra = {}) {
597
+ const identity = createArchiveIdentity({
598
+ objectType,
599
+ schemaName,
600
+ name,
601
+ ...extra.parentName === void 0 ? {} : { parentName: extra.parentName }
602
+ });
603
+ const dumpId = createDumpId(identity);
604
+ if (byDumpId.has(dumpId)) {
605
+ diagnostics.push({
606
+ severity: "error",
607
+ code: "duplicate-archive-identity",
608
+ message: `Duplicate archive identity for ${objectType} "${name}" in schema "${schemaName}"`,
609
+ objectReference: { kind: "table", schemaName, name }
610
+ });
611
+ return dumpId;
612
+ }
613
+ const entry = { dumpId, identity, objectType, name, ...extra, dependsOn: [] };
614
+ entries.push(entry);
615
+ byDumpId.set(dumpId, entry);
616
+ return dumpId;
617
+ }
618
+ function addDependency(fromDumpId, toDumpId, strength) {
619
+ if (!toDumpId || fromDumpId === toDumpId) {
620
+ return;
621
+ }
622
+ const entry = byDumpId.get(fromDumpId);
623
+ if (!entry) {
624
+ return;
625
+ }
626
+ const existing = entry.dependsOn.find((dependency) => dependency.targetDumpId === toDumpId);
627
+ if (existing) {
628
+ if (strength === "hard" && existing.strength === "preference") {
629
+ entry.dependsOn = entry.dependsOn.filter(
630
+ (dependency) => dependency.targetDumpId !== toDumpId
631
+ );
632
+ entry.dependsOn.push({ targetDumpId: toDumpId, strength: "hard" });
633
+ }
634
+ return;
635
+ }
636
+ entry.dependsOn.push({ targetDumpId: toDumpId, strength });
637
+ }
638
+ const tablesByName = new Map(database.tables.map((table) => [foldSqliteName(table.name), table]));
639
+ const isUserTableSelected = (table) => {
640
+ switch (table.kind) {
641
+ case "table":
642
+ return includeTables && isTableSelected(table.name, selection);
643
+ case "virtual":
644
+ return includeVirtualTables && isTableSelected(table.name, selection);
645
+ case "shadow": {
646
+ const owner = table.ownerVirtualTable === void 0 ? void 0 : tablesByName.get(foldSqliteName(table.ownerVirtualTable));
647
+ if (!owner) {
648
+ return includeTables && isTableSelected(table.name, selection);
649
+ }
650
+ return includeVirtualTables && isTableSelected(owner.name, selection);
651
+ }
652
+ case "system":
653
+ return false;
654
+ }
655
+ };
656
+ const selectedUserTables = database.tables.filter(isUserTableSelected);
657
+ const selectedTableNames = selectedUserTables.map((table) => table.name);
658
+ const tableDumpId = /* @__PURE__ */ new Map();
659
+ const tableDataDumpId = /* @__PURE__ */ new Map();
660
+ const orderedTables = [...database.tables].sort((a, b) => {
661
+ const aLast = a.name === SEQUENCE_TABLE_NAME ? 1 : 0;
662
+ const bLast = b.name === SEQUENCE_TABLE_NAME ? 1 : 0;
663
+ return aLast - bLast || a.schemaRowid - b.schemaRowid;
664
+ });
665
+ for (const table of orderedTables) {
666
+ const key = foldSqliteName(table.name);
667
+ if (table.kind === "system") {
668
+ const isSequence = table.name === SEQUENCE_TABLE_NAME;
669
+ if (!includeSystemTables || !isSequence && !isStatisticsTableName(table.name)) {
670
+ continue;
671
+ }
672
+ const systemRowFilter = selection.isPartial ? selectedTableNames : void 0;
673
+ if (systemRowFilter && systemRowFilter.length === 0) {
674
+ continue;
675
+ }
676
+ const extra = {
677
+ tableKind: table.kind,
678
+ ...systemRowFilter === void 0 ? {} : { systemRowFilter }
679
+ };
680
+ let structureId2;
681
+ if (wantsSchema && wantsData) {
682
+ structureId2 = addEntry("table", table.name, extra);
683
+ tableDumpId.set(key, structureId2);
684
+ }
685
+ if (wantsData) {
686
+ const dataId = addEntry("tableData", table.name, { ...extra, parentName: table.name });
687
+ tableDataDumpId.set(key, dataId);
688
+ addDependency(dataId, structureId2, "hard");
689
+ if (!wantsSchema) {
690
+ diagnostics.push({
691
+ severity: "warning",
692
+ code: "data-only-system-table",
693
+ message: isSequence ? "A data-only dump inserts the sqlite_sequence rows without first clearing the table, exactly as the native .dump --data-only does; restoring it into a database whose tables already advanced their AUTOINCREMENT counters leaves duplicate counter rows. Set objectKinds.includeSystemTables to false to leave the counters to the inserts themselves." : `A data-only dump inserts into ${table.name} without creating it first, exactly as the native .dump --data-only does; restoring it into a database that has never been analyzed fails with "no such table". Set objectKinds.includeSystemTables to false to leave statistics out.`,
694
+ objectReference: { kind: "table", schemaName, name: table.name }
695
+ });
696
+ }
697
+ }
698
+ continue;
699
+ }
700
+ if (!isUserTableSelected(table)) {
701
+ continue;
702
+ }
703
+ if (table.kind === "virtual") {
704
+ if (wantsSchema) {
705
+ tableDumpId.set(key, addEntry("virtualTable", table.name, { tableKind: table.kind }));
706
+ } else if (!isTableDataExcluded(table.name, selection)) {
707
+ tableDataDumpId.set(
708
+ key,
709
+ addEntry("tableData", table.name, { tableKind: table.kind, parentName: table.name })
710
+ );
711
+ diagnostics.push({
712
+ severity: "warning",
713
+ code: "data-only-virtual-table",
714
+ message: `A data-only dump carries the rows of virtual table "${table.name}" twice \u2014 through the table itself and in its shadow tables \u2014 exactly as the native .dump --data-only does. Restoring it into a database where "${table.name}" already exists conflicts with that table's own shadow rows; exclude the shadow tables through selection.dataExcludedTables to load the rows through the virtual table only.`,
715
+ objectReference: { kind: "virtualTable", schemaName, name: table.name }
716
+ });
717
+ }
718
+ continue;
719
+ }
720
+ if (table.kind === "shadow" && !wantsData && table.ownerVirtualTable !== void 0) {
721
+ continue;
722
+ }
723
+ let structureId;
724
+ if (wantsSchema) {
725
+ structureId = addEntry("table", table.name, { tableKind: table.kind });
726
+ tableDumpId.set(key, structureId);
727
+ if (table.kind === "shadow" && table.ownerVirtualTable !== void 0) {
728
+ addDependency(
729
+ structureId,
730
+ tableDumpId.get(foldSqliteName(table.ownerVirtualTable)),
731
+ "preference"
732
+ );
733
+ }
734
+ }
735
+ if (wantsData && !isTableDataExcluded(table.name, selection)) {
736
+ const dataId = addEntry("tableData", table.name, {
737
+ tableKind: table.kind,
738
+ parentName: table.name
739
+ });
740
+ tableDataDumpId.set(key, dataId);
741
+ addDependency(dataId, structureId, "hard");
742
+ }
743
+ }
744
+ for (const foreignKey of database.foreignKeys) {
745
+ const from = tableDumpId.get(foldSqliteName(foreignKey.tableName));
746
+ const to = tableDumpId.get(foldSqliteName(foreignKey.referencedTableName));
747
+ if (from && to) {
748
+ addDependency(from, to, "preference");
749
+ }
750
+ }
751
+ if (wantsSchema) {
752
+ const selectedViewNames = new Set(
753
+ includeViews ? database.views.filter((view) => isViewSelected(view.name, selection)).map((view) => foldSqliteName(view.name)) : []
754
+ );
755
+ const viewDumpId = /* @__PURE__ */ new Map();
756
+ const objects = [
757
+ ...database.indexes.map((index) => ({
758
+ kind: "index",
759
+ schemaRowid: index.schemaRowid,
760
+ index
761
+ })),
762
+ ...database.triggers.map((trigger) => ({
763
+ kind: "trigger",
764
+ schemaRowid: trigger.schemaRowid,
765
+ trigger
766
+ })),
767
+ ...database.views.map((view) => ({
768
+ kind: "view",
769
+ schemaRowid: view.schemaRowid,
770
+ view
771
+ }))
772
+ ].sort((a, b) => a.schemaRowid - b.schemaRowid);
773
+ for (const object of objects) {
774
+ switch (object.kind) {
775
+ case "index": {
776
+ const { index } = object;
777
+ if (index.sql === null || !includeIndexes || !isIndexSelected(index.name, selection)) {
778
+ continue;
779
+ }
780
+ const tableId = tableDumpId.get(foldSqliteName(index.tableName));
781
+ if (!tableId) {
782
+ continue;
783
+ }
784
+ const dumpId = addEntry("index", index.name, { parentName: index.tableName });
785
+ addDependency(dumpId, tableId, "hard");
786
+ addDependency(dumpId, tableDataDumpId.get(foldSqliteName(index.tableName)), "preference");
787
+ break;
788
+ }
789
+ case "trigger": {
790
+ const { trigger } = object;
791
+ if (!includeTriggers || !isTriggerSelected(trigger.name, selection)) {
792
+ continue;
793
+ }
794
+ const parentKey = foldSqliteName(trigger.tableName);
795
+ const parentId = tableDumpId.get(parentKey) ?? viewDumpId.get(parentKey);
796
+ if (!parentId) {
797
+ diagnostics.push({
798
+ severity: "info",
799
+ code: "trigger-table-not-selected",
800
+ message: `Trigger "${trigger.name}" is not dumped because its table "${trigger.tableName}" is not part of the dump`,
801
+ objectReference: {
802
+ kind: "trigger",
803
+ schemaName,
804
+ name: trigger.name,
805
+ parentName: trigger.tableName
806
+ }
807
+ });
808
+ continue;
809
+ }
810
+ const dumpId = addEntry("trigger", trigger.name, { parentName: trigger.tableName });
811
+ addDependency(dumpId, parentId, "hard");
812
+ addDependency(dumpId, tableDataDumpId.get(parentKey), "hard");
813
+ break;
814
+ }
815
+ case "view": {
816
+ const { view } = object;
817
+ const key = foldSqliteName(view.name);
818
+ if (!selectedViewNames.has(key)) {
819
+ continue;
820
+ }
821
+ const dumpId = addEntry("view", view.name);
822
+ viewDumpId.set(key, dumpId);
823
+ for (const tableId of tableDumpId.values()) {
824
+ addDependency(dumpId, tableId, "preference");
825
+ }
826
+ break;
827
+ }
828
+ }
829
+ }
830
+ }
831
+ const { cycles, unsatisfiedDependencies } = validateOrder(entries);
832
+ const valid = cycles.length === 0 && unsatisfiedDependencies.length === 0 && !diagnostics.some((diagnostic) => diagnostic.severity === "error");
833
+ for (const cycle of cycles) {
834
+ diagnostics.push({
835
+ severity: "error",
836
+ code: "archive-dependency-cycle",
837
+ message: `Hard dependency cycle between archive entries: ${cycle.memberDumpIds.join(", ")}`
838
+ });
839
+ }
840
+ for (const violation of unsatisfiedDependencies) {
841
+ diagnostics.push({
842
+ severity: "error",
843
+ code: "archive-order-violation",
844
+ message: `Archive entry ${violation.fromDumpId} is emitted before its hard dependency ${violation.toDumpId}`
845
+ });
846
+ }
847
+ return {
848
+ valid,
849
+ entries: entries.map(
850
+ (entry, index) => toArchiveEntry(entry, schemaName, valid ? index : void 0)
851
+ ),
852
+ diagnostics,
853
+ cycles,
854
+ unsatisfiedDependencies
855
+ };
856
+ }
857
+ function toArchiveEntry(entry, schemaName, sequenceNumber) {
858
+ return {
859
+ dumpId: entry.dumpId,
860
+ identity: entry.identity,
861
+ objectType: entry.objectType,
862
+ section: assignDumpSection(entry.objectType),
863
+ schemaName,
864
+ name: entry.name,
865
+ ...entry.parentName === void 0 ? {} : { parentName: entry.parentName },
866
+ ...entry.tableKind === void 0 ? {} : { tableKind: entry.tableKind },
867
+ ...entry.systemRowFilter === void 0 ? {} : { systemRowFilter: entry.systemRowFilter },
868
+ dependsOn: entry.dependsOn,
869
+ ...sequenceNumber === void 0 ? {} : { sequenceNumber }
870
+ };
871
+ }
872
+ function validateOrder(ordered) {
873
+ const positionByDumpId = new Map(ordered.map((entry, index) => [entry.dumpId, index]));
874
+ const unsatisfiedDependencies = [];
875
+ for (const entry of ordered) {
876
+ const fromPosition = positionByDumpId.get(entry.dumpId);
877
+ for (const dependency of entry.dependsOn) {
878
+ if (dependency.strength !== "hard") {
879
+ continue;
880
+ }
881
+ const toPosition = positionByDumpId.get(dependency.targetDumpId);
882
+ if (toPosition !== void 0 && toPosition > fromPosition) {
883
+ unsatisfiedDependencies.push({
884
+ fromDumpId: entry.dumpId,
885
+ toDumpId: dependency.targetDumpId
886
+ });
887
+ }
888
+ }
889
+ }
890
+ return { cycles: findHardCycles(ordered), unsatisfiedDependencies };
891
+ }
892
+ function byCodepoint(a, b) {
893
+ return a < b ? -1 : a > b ? 1 : 0;
894
+ }
895
+ function findHardCycles(entries) {
896
+ const indexByDumpId = /* @__PURE__ */ new Map();
897
+ const lowLink = /* @__PURE__ */ new Map();
898
+ const onStack = /* @__PURE__ */ new Set();
899
+ const stack = [];
900
+ const byDumpId = new Map(entries.map((entry) => [entry.dumpId, entry]));
901
+ const cycles = [];
902
+ let nextIndex = 0;
903
+ const strongConnect = (dumpId) => {
904
+ indexByDumpId.set(dumpId, nextIndex);
905
+ lowLink.set(dumpId, nextIndex);
906
+ nextIndex++;
907
+ stack.push(dumpId);
908
+ onStack.add(dumpId);
909
+ for (const dependency of byDumpId.get(dumpId)?.dependsOn ?? []) {
910
+ if (dependency.strength !== "hard" || !byDumpId.has(dependency.targetDumpId)) {
911
+ continue;
912
+ }
913
+ const target = dependency.targetDumpId;
914
+ if (!indexByDumpId.has(target)) {
915
+ strongConnect(target);
916
+ lowLink.set(dumpId, Math.min(lowLink.get(dumpId), lowLink.get(target)));
917
+ } else if (onStack.has(target)) {
918
+ lowLink.set(
919
+ dumpId,
920
+ Math.min(lowLink.get(dumpId), indexByDumpId.get(target))
921
+ );
922
+ }
923
+ }
924
+ if (lowLink.get(dumpId) === indexByDumpId.get(dumpId)) {
925
+ const component = [];
926
+ for (; ; ) {
927
+ const member = stack.pop();
928
+ onStack.delete(member);
929
+ component.push(member);
930
+ if (member === dumpId) {
931
+ break;
932
+ }
933
+ }
934
+ if (component.length > 1) {
935
+ cycles.push({ memberDumpIds: component.sort(byCodepoint) });
936
+ }
937
+ }
938
+ };
939
+ for (const entry of entries) {
940
+ if (!indexByDumpId.has(entry.dumpId)) {
941
+ strongConnect(entry.dumpId);
942
+ }
943
+ }
944
+ return cycles;
945
+ }
946
+
947
+ // src/utils/errors.ts
948
+ var SqliteDumperError = class extends Error {
949
+ code;
950
+ constructor(code, message, options) {
951
+ super(message, options);
952
+ this.name = "SqliteDumperError";
953
+ this.code = code;
954
+ }
955
+ };
956
+ var OperationCancelledError = class extends SqliteDumperError {
957
+ constructor(message = "The operation was cancelled") {
958
+ super("operation-cancelled", message);
959
+ this.name = "OperationCancelledError";
960
+ }
961
+ };
962
+ function throwIfAborted2(signal) {
963
+ if (signal?.aborted) {
964
+ throw new OperationCancelledError();
965
+ }
966
+ }
967
+ function isAbortError(error) {
968
+ return error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "OperationCancelledError";
969
+ }
970
+
971
+ // src/introspection/sqlText.ts
972
+ function maskSqlLiterals(sql) {
973
+ let output = "";
974
+ let index = 0;
975
+ while (index < sql.length) {
976
+ const character = sql[index];
977
+ if (character === "'" || character === '"' || character === "`" || character === "[") {
978
+ const close = character === "[" ? "]" : character;
979
+ let end = sql.indexOf(close, index + 1);
980
+ end = end === -1 ? sql.length : end + 1;
981
+ output += " ".repeat(end - index);
982
+ index = end;
983
+ continue;
984
+ }
985
+ if (character === "-" && sql[index + 1] === "-") {
986
+ let end = sql.indexOf("\n", index);
987
+ end = end === -1 ? sql.length : end;
988
+ output += " ".repeat(end - index);
989
+ index = end;
990
+ continue;
991
+ }
992
+ if (character === "/" && sql[index + 1] === "*") {
993
+ let end = sql.indexOf("*/", index + 2);
994
+ end = end === -1 ? sql.length : end + 2;
995
+ output += " ".repeat(end - index);
996
+ index = end;
997
+ continue;
998
+ }
999
+ output += character;
1000
+ index++;
1001
+ }
1002
+ return output;
1003
+ }
1004
+ function declaresAutoincrement(sql) {
1005
+ return /\bAUTOINCREMENT\b/i.test(maskSqlLiterals(sql));
1006
+ }
1007
+ function parseTableOptions(sql) {
1008
+ const masked = maskSqlLiterals(sql);
1009
+ const close = masked.lastIndexOf(")");
1010
+ const tail = close === -1 ? "" : masked.slice(close + 1);
1011
+ return {
1012
+ withoutRowid: /\bWITHOUT\s+ROWID\b/i.test(tail),
1013
+ strict: /\bSTRICT\b/i.test(tail)
1014
+ };
1015
+ }
1016
+ function parseVirtualTableModule(sql) {
1017
+ const masked = maskSqlLiterals(sql);
1018
+ const match = /\bUSING\s+([A-Za-z0-9_$\u0080-\uffff]+)/i.exec(masked);
1019
+ return match ? sql.slice(match.index, match.index + match[0].length).replace(/^USING\s+/i, "") : void 0;
1020
+ }
1021
+
1022
+ // src/introspection/introspect.ts
1023
+ async function introspectSqlite(connection, options, signal) {
1024
+ const schemaName = options?.schemaName ?? "main";
1025
+ const version = await detectSqliteVersion(connection, signal);
1026
+ const capabilities = detectSqliteCapabilities(version);
1027
+ const diagnostics = [];
1028
+ const catalog = new CatalogReader(connection, schemaName, capabilities, signal);
1029
+ const schemaRows = await catalog.schemaRows();
1030
+ if (schemaRows === null) {
1031
+ throw new SqliteDumperError(
1032
+ "schema-not-found",
1033
+ `No database named ${JSON.stringify(schemaName)} is attached to this connection`
1034
+ );
1035
+ }
1036
+ const tableList = await catalog.tableList();
1037
+ const virtualTableNames = schemaRows.filter((row) => row.type === "table" && isVirtualTableSql(row.sql)).map((row) => row.name);
1038
+ const tables = [];
1039
+ const indexes = [];
1040
+ const foreignKeys = [];
1041
+ const indexRowsByName = new Map(
1042
+ schemaRows.filter((row) => row.type === "index").map((row) => [toAsciiLowerCase(row.name), row])
1043
+ );
1044
+ for (const row of schemaRows) {
1045
+ throwIfAborted2(signal);
1046
+ if (row.type !== "table" || row.sql === null) {
1047
+ continue;
1048
+ }
1049
+ const listed = tableList?.get(toAsciiLowerCase(row.name));
1050
+ const kind = classifyTable(row, listed?.type, virtualTableNames);
1051
+ let columns = [];
1052
+ try {
1053
+ columns = await catalog.columns(row.name);
1054
+ } catch (error) {
1055
+ if (isAbortError(error)) throw error;
1056
+ diagnostics.push({
1057
+ severity: kind === "virtual" ? "warning" : "error",
1058
+ code: kind === "virtual" ? "virtual-table-module-unavailable" : "table-columns-unreadable",
1059
+ message: kind === "virtual" ? `The columns of virtual table "${row.name}" cannot be read, most likely because its module is not available in this SQLite build (${errorMessage(error)}). Its definition and its shadow tables are still dumped, which is all a restore needs.` : `The columns of table "${row.name}" cannot be read: ${errorMessage(error)}`,
1060
+ objectReference: {
1061
+ kind: kind === "virtual" ? "virtualTable" : "table",
1062
+ schemaName,
1063
+ name: row.name
1064
+ }
1065
+ });
1066
+ }
1067
+ const parsedOptions = parseTableOptions(row.sql);
1068
+ const withoutRowid = listed ? listed.withoutRowid : kind === "table" || kind === "shadow" ? parsedOptions.withoutRowid : false;
1069
+ const strict = listed ? listed.strict : parsedOptions.strict;
1070
+ let tableIndexes = [];
1071
+ let tableForeignKeys = [];
1072
+ if (kind !== "virtual") {
1073
+ tableIndexes = await catalog.indexes(row.name, indexRowsByName);
1074
+ tableForeignKeys = await catalog.foreignKeys(row.name);
1075
+ }
1076
+ indexes.push(...tableIndexes);
1077
+ foreignKeys.push(...tableForeignKeys);
1078
+ const virtualModule = kind === "virtual" ? parseVirtualTableModule(row.sql) : void 0;
1079
+ const ownerVirtualTable = kind === "shadow" ? findOwner(row.name, virtualTableNames) : void 0;
1080
+ tables.push({
1081
+ name: row.name,
1082
+ kind,
1083
+ schemaRowid: row.schemaRowid,
1084
+ sql: row.sql,
1085
+ withoutRowid,
1086
+ strict,
1087
+ hasAutoincrement: kind === "table" && declaresAutoincrement(row.sql),
1088
+ ...virtualModule === void 0 ? {} : { virtualModule },
1089
+ ...ownerVirtualTable === void 0 ? {} : { ownerVirtualTable },
1090
+ rowidAliasColumn: kind === "virtual" || withoutRowid ? null : findRowidAlias(columns, tableIndexes),
1091
+ columns
1092
+ });
1093
+ }
1094
+ const seenIndexes = new Set(indexes.map((index) => toAsciiLowerCase(index.name)));
1095
+ for (const row of schemaRows) {
1096
+ if (row.type === "index" && row.sql !== null && !seenIndexes.has(toAsciiLowerCase(row.name))) {
1097
+ indexes.push({
1098
+ name: row.name,
1099
+ tableName: row.tableName,
1100
+ schemaRowid: row.schemaRowid,
1101
+ sql: row.sql,
1102
+ isUnique: /^CREATE\s+UNIQUE\b/i.test(row.sql),
1103
+ origin: "c",
1104
+ isPartial: false,
1105
+ columns: []
1106
+ });
1107
+ }
1108
+ }
1109
+ indexes.sort((a, b) => a.schemaRowid - b.schemaRowid);
1110
+ const views = schemaRows.filter((row) => row.type === "view" && row.sql !== null).map((row) => ({ name: row.name, schemaRowid: row.schemaRowid, sql: row.sql }));
1111
+ const triggers = schemaRows.filter((row) => row.type === "trigger" && row.sql !== null).map((row) => ({
1112
+ name: row.name,
1113
+ tableName: row.tableName,
1114
+ schemaRowid: row.schemaRowid,
1115
+ sql: row.sql
1116
+ }));
1117
+ const sequences = tables.some((table) => table.name === "sqlite_sequence") ? await catalog.sequences() : [];
1118
+ const settings = await catalog.settings();
1119
+ return {
1120
+ database: {
1121
+ schemaName,
1122
+ ...settings,
1123
+ tables,
1124
+ indexes,
1125
+ views,
1126
+ triggers,
1127
+ foreignKeys,
1128
+ sequences
1129
+ },
1130
+ version,
1131
+ capabilities,
1132
+ diagnostics
1133
+ };
1134
+ }
1135
+ function errorMessage(error) {
1136
+ return error instanceof Error ? error.message : String(error);
1137
+ }
1138
+ function isVirtualTableSql(sql) {
1139
+ return sql !== null && sql.startsWith("CREATE VIRTUAL TABLE");
1140
+ }
1141
+ function classifyTable(row, listedType, virtualTableNames) {
1142
+ if (row.name.startsWith("sqlite_")) {
1143
+ return "system";
1144
+ }
1145
+ if (isVirtualTableSql(row.sql)) {
1146
+ return "virtual";
1147
+ }
1148
+ if (listedType !== void 0) {
1149
+ return listedType === "shadow" ? "shadow" : "table";
1150
+ }
1151
+ return findOwner(row.name, virtualTableNames) === void 0 ? "table" : "shadow";
1152
+ }
1153
+ function findOwner(tableName, virtualTableNames) {
1154
+ const lower = toAsciiLowerCase(tableName);
1155
+ let owner;
1156
+ for (const name of virtualTableNames) {
1157
+ const prefix = `${toAsciiLowerCase(name)}_`;
1158
+ if (lower.startsWith(prefix) && lower.length > prefix.length) {
1159
+ if (owner === void 0 || name.length > owner.length) {
1160
+ owner = name;
1161
+ }
1162
+ }
1163
+ }
1164
+ return owner;
1165
+ }
1166
+ function findRowidAlias(columns, indexes) {
1167
+ const primaryKey = columns.filter((column2) => column2.primaryKeyPosition > 0);
1168
+ if (primaryKey.length !== 1) {
1169
+ return null;
1170
+ }
1171
+ const column = primaryKey[0];
1172
+ if (toAsciiUpperCase(column.declaredType) !== "INTEGER") {
1173
+ return null;
1174
+ }
1175
+ if (indexes.some((index) => index.origin === "pk")) {
1176
+ return null;
1177
+ }
1178
+ return column.name;
1179
+ }
1180
+ var CatalogReader = class {
1181
+ constructor(connection, schemaName, capabilities, signal) {
1182
+ this.connection = connection;
1183
+ this.schemaName = schemaName;
1184
+ this.capabilities = capabilities;
1185
+ this.signal = signal;
1186
+ this.qualifier = quoteIdentifier(schemaName);
1187
+ }
1188
+ connection;
1189
+ schemaName;
1190
+ capabilities;
1191
+ signal;
1192
+ qualifier;
1193
+ async rows(sql, parameters) {
1194
+ const result = await this.connection.query(
1195
+ parameters === void 0 ? { sql } : { sql, parameters },
1196
+ this.signal
1197
+ );
1198
+ return result.rows;
1199
+ }
1200
+ /** Runs `PRAGMA schema.name(argument)`, as a table-valued function when the library has them. */
1201
+ async pragma(name, argument, columns) {
1202
+ if (this.capabilities.supportsPragmaFunctions) {
1203
+ return this.rows(`SELECT ${columns} FROM pragma_${name}(?, ?)`, [argument, this.schemaName]);
1204
+ }
1205
+ return this.rows(`PRAGMA ${this.qualifier}.${name}(${quoteStringLiteral(argument)})`);
1206
+ }
1207
+ async schemaRows() {
1208
+ const databases = await this.rows("PRAGMA database_list");
1209
+ const known = databases.some(
1210
+ (row) => toAsciiLowerCase(toText(row.name) ?? "") === toAsciiLowerCase(this.schemaName)
1211
+ );
1212
+ if (!known) {
1213
+ return null;
1214
+ }
1215
+ const master = toAsciiLowerCase(this.schemaName) === "temp" ? "sqlite_temp_master" : "sqlite_master";
1216
+ const rows = await this.rows(
1217
+ `SELECT rowid AS schemaRowid, type, name, tbl_name AS tableName, sql FROM ${this.qualifier}.${master} ORDER BY rowid`
1218
+ );
1219
+ return rows.map((row) => ({
1220
+ schemaRowid: toNumber(row.schemaRowid),
1221
+ type: toText(row.type) ?? "",
1222
+ name: toText(row.name) ?? "",
1223
+ tableName: toText(row.tableName) ?? "",
1224
+ sql: toText(row.sql)
1225
+ }));
1226
+ }
1227
+ async tableList() {
1228
+ if (!this.capabilities.supportsTableList) {
1229
+ return void 0;
1230
+ }
1231
+ try {
1232
+ const rows = await this.rows(
1233
+ "SELECT name, type, wr, strict FROM pragma_table_list WHERE schema = ?",
1234
+ [this.schemaName]
1235
+ );
1236
+ return new Map(
1237
+ rows.map((row) => [
1238
+ toAsciiLowerCase(toText(row.name) ?? ""),
1239
+ {
1240
+ type: toText(row.type) ?? "table",
1241
+ withoutRowid: toNumber(row.wr) !== 0,
1242
+ strict: toNumber(row.strict) !== 0
1243
+ }
1244
+ ])
1245
+ );
1246
+ } catch (error) {
1247
+ if (isAbortError(error)) throw error;
1248
+ return void 0;
1249
+ }
1250
+ }
1251
+ async columns(tableName) {
1252
+ const withHidden = this.capabilities.supportsTableXinfo;
1253
+ const rows = await this.pragma(
1254
+ withHidden ? "table_xinfo" : "table_info",
1255
+ tableName,
1256
+ `cid, name, type, "notnull" AS isNotNull, dflt_value AS defaultValue, pk${withHidden ? ", hidden" : ""}`
1257
+ );
1258
+ return rows.map((row) => {
1259
+ const hidden = withHidden ? toNumber(row.hidden) : 0;
1260
+ return {
1261
+ cid: toNumber(row.cid),
1262
+ name: toText(row.name) ?? "",
1263
+ declaredType: toText(row.type) ?? "",
1264
+ notNull: toNumber(row.isNotNull ?? row.notnull) !== 0,
1265
+ defaultValue: toText(row.defaultValue ?? row.dflt_value),
1266
+ primaryKeyPosition: toNumber(row.pk),
1267
+ hidden,
1268
+ generated: hidden === 2 ? "virtual" : hidden === 3 ? "stored" : "none"
1269
+ };
1270
+ });
1271
+ }
1272
+ async indexes(tableName, schemaRows) {
1273
+ const list = await this.pragma(
1274
+ "index_list",
1275
+ tableName,
1276
+ 'seq, name, "unique" AS isUnique, origin, partial'
1277
+ );
1278
+ const result = [];
1279
+ for (const row of list) {
1280
+ const name = toText(row.name) ?? "";
1281
+ const schemaRow = schemaRows.get(toAsciiLowerCase(name));
1282
+ const origin = toText(row.origin) ?? "c";
1283
+ let columns = [];
1284
+ try {
1285
+ const keyRows = await this.pragma(
1286
+ "index_xinfo",
1287
+ name,
1288
+ 'seqno, cid, name, "desc" AS isDesc, coll, "key" AS isKey'
1289
+ );
1290
+ columns = keyRows.filter((keyRow) => toNumber(keyRow.isKey ?? keyRow.key) !== 0).map((keyRow) => ({
1291
+ name: toText(keyRow.name),
1292
+ cid: toNumber(keyRow.cid),
1293
+ descending: toNumber(keyRow.isDesc ?? keyRow.desc) !== 0,
1294
+ collation: toText(keyRow.coll)
1295
+ }));
1296
+ } catch (error) {
1297
+ if (isAbortError(error)) throw error;
1298
+ }
1299
+ result.push({
1300
+ name,
1301
+ tableName,
1302
+ // A WITHOUT ROWID table's primary-key index is the table itself and
1303
+ // has no sqlite_schema row; it sorts with its table.
1304
+ schemaRowid: schemaRow?.schemaRowid ?? 0,
1305
+ sql: schemaRow?.sql ?? null,
1306
+ isUnique: toNumber(row.isUnique ?? row.unique) !== 0,
1307
+ origin: origin === "u" || origin === "pk" ? origin : "c",
1308
+ isPartial: toNumber(row.partial) !== 0,
1309
+ columns
1310
+ });
1311
+ }
1312
+ return result;
1313
+ }
1314
+ async foreignKeys(tableName) {
1315
+ const rows = await this.pragma(
1316
+ "foreign_key_list",
1317
+ tableName,
1318
+ 'id, seq, "table" AS referencedTable, "from" AS fromColumn, "to" AS toColumn, on_update AS onUpdate, on_delete AS onDelete, "match" AS matchMode'
1319
+ );
1320
+ const byId = /* @__PURE__ */ new Map();
1321
+ const ordered = [...rows].sort(
1322
+ (a, b) => toNumber(a.id) - toNumber(b.id) || toNumber(a.seq) - toNumber(b.seq)
1323
+ );
1324
+ for (const row of ordered) {
1325
+ const id = toNumber(row.id);
1326
+ let foreignKey = byId.get(id);
1327
+ if (!foreignKey) {
1328
+ foreignKey = {
1329
+ tableName,
1330
+ id,
1331
+ referencedTableName: toText(row.referencedTable ?? row.table) ?? "",
1332
+ columns: [],
1333
+ onUpdate: toText(row.onUpdate ?? row.on_update) ?? "NO ACTION",
1334
+ onDelete: toText(row.onDelete ?? row.on_delete) ?? "NO ACTION",
1335
+ match: toText(row.matchMode ?? row.match) ?? "NONE"
1336
+ };
1337
+ byId.set(id, foreignKey);
1338
+ }
1339
+ foreignKey.columns.push({
1340
+ from: toText(row.fromColumn ?? row.from) ?? "",
1341
+ to: toText(row.toColumn ?? row.to)
1342
+ });
1343
+ }
1344
+ return [...byId.values()];
1345
+ }
1346
+ async sequences() {
1347
+ const rows = await this.rows(
1348
+ `SELECT name, CAST(seq AS TEXT) AS value FROM ${this.qualifier}.sqlite_sequence`
1349
+ );
1350
+ return rows.map((row) => ({
1351
+ tableName: toText(row.name) ?? "",
1352
+ value: toText(row.value) ?? "0"
1353
+ }));
1354
+ }
1355
+ async settings() {
1356
+ const read = async (pragma) => {
1357
+ try {
1358
+ const rows = await this.rows(`PRAGMA ${this.qualifier}.${pragma}`);
1359
+ const first = rows[0];
1360
+ return first === void 0 ? void 0 : Object.values(first)[0];
1361
+ } catch (error) {
1362
+ if (isAbortError(error)) throw error;
1363
+ return void 0;
1364
+ }
1365
+ };
1366
+ let encoding;
1367
+ try {
1368
+ const rows = await this.rows("PRAGMA encoding");
1369
+ encoding = rows[0] === void 0 ? void 0 : Object.values(rows[0])[0];
1370
+ } catch (error) {
1371
+ if (isAbortError(error)) throw error;
1372
+ }
1373
+ const pageSize = await read("page_size");
1374
+ return {
1375
+ encoding: toText(encoding) ?? "UTF-8",
1376
+ userVersion: toNumber(await read("user_version")),
1377
+ applicationId: toNumber(await read("application_id")),
1378
+ ...pageSize === void 0 ? {} : { pageSize: toNumber(pageSize) }
1379
+ };
1380
+ }
1381
+ };
1382
+
1383
+ // src/renderer/types.ts
1384
+ function resolvePlainSqlRenderOptions(options) {
1385
+ return {
1386
+ includeSessionGuards: options?.includeSessionGuards ?? true,
1387
+ includeHeaderComments: options?.includeHeaderComments ?? true,
1388
+ addDropStatements: options?.addDropStatements ?? false,
1389
+ includeDatabaseSettings: options?.includeDatabaseSettings ?? false,
1390
+ legacySchemaTableName: options?.legacySchemaTableName ?? false,
1391
+ unsupportedFeaturePolicy: options?.unsupportedFeaturePolicy ?? "error"
1392
+ };
1393
+ }
1394
+
1395
+ // src/restore/complete.ts
1396
+ var CompleteToken = {
1397
+ Semi: 0,
1398
+ Whitespace: 1,
1399
+ Other: 2,
1400
+ Explain: 3,
1401
+ Create: 4,
1402
+ Temp: 5,
1403
+ Trigger: 6,
1404
+ End: 7
1405
+ };
1406
+ var COMPLETE_TRANSITIONS = [
1407
+ // SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END
1408
+ /* 0 */
1409
+ [1, 0, 2, 3, 4, 2, 2, 2],
1410
+ /* 1 */
1411
+ [1, 1, 2, 3, 4, 2, 2, 2],
1412
+ /* 2 */
1413
+ [1, 2, 2, 2, 2, 2, 2, 2],
1414
+ /* 3 */
1415
+ [1, 3, 3, 2, 4, 2, 2, 2],
1416
+ /* 4 */
1417
+ [1, 4, 2, 2, 2, 4, 5, 2],
1418
+ /* 5 */
1419
+ [6, 5, 5, 5, 5, 5, 5, 5],
1420
+ /* 6 */
1421
+ [6, 6, 5, 5, 5, 5, 5, 7],
1422
+ /* 7 */
1423
+ [1, 7, 5, 5, 5, 5, 5, 5]
1424
+ ];
1425
+ function completeTransition(state, token) {
1426
+ return COMPLETE_TRANSITIONS[state][token];
1427
+ }
1428
+ function isIdentifierCharCode(code) {
1429
+ return code >= 97 && code <= 122 || code >= 65 && code <= 90 || code >= 48 && code <= 57 || code === 95 || code === 36 || code >= 128;
1430
+ }
1431
+ function classifyWord(word) {
1432
+ switch (word.length) {
1433
+ case 3:
1434
+ return word.toLowerCase() === "end" ? CompleteToken.End : CompleteToken.Other;
1435
+ case 4:
1436
+ return word.toLowerCase() === "temp" ? CompleteToken.Temp : CompleteToken.Other;
1437
+ case 6:
1438
+ return word.toLowerCase() === "create" ? CompleteToken.Create : CompleteToken.Other;
1439
+ case 7: {
1440
+ const lower = word.toLowerCase();
1441
+ if (lower === "trigger") return CompleteToken.Trigger;
1442
+ if (lower === "explain") return CompleteToken.Explain;
1443
+ return CompleteToken.Other;
1444
+ }
1445
+ case 9:
1446
+ return word.toLowerCase() === "temporary" ? CompleteToken.Temp : CompleteToken.Other;
1447
+ default:
1448
+ return CompleteToken.Other;
1449
+ }
1450
+ }
1451
+ function isCompleteWhitespace(character) {
1452
+ return character === " " || character === "\r" || character === " " || character === "\n" || character === "\f";
1453
+ }
1454
+ function isCompleteStatement(sql) {
1455
+ let state = 0;
1456
+ let index = 0;
1457
+ const length = sql.length;
1458
+ while (index < length) {
1459
+ const character = sql[index];
1460
+ let token;
1461
+ if (character === ";") {
1462
+ token = CompleteToken.Semi;
1463
+ } else if (isCompleteWhitespace(character)) {
1464
+ token = CompleteToken.Whitespace;
1465
+ } else if (character === "/") {
1466
+ if (sql[index + 1] !== "*") {
1467
+ token = CompleteToken.Other;
1468
+ } else {
1469
+ index += 2;
1470
+ while (index < length && !(sql[index] === "*" && sql[index + 1] === "/")) {
1471
+ index++;
1472
+ }
1473
+ if (index >= length) {
1474
+ return false;
1475
+ }
1476
+ index++;
1477
+ token = CompleteToken.Whitespace;
1478
+ }
1479
+ } else if (character === "-") {
1480
+ if (sql[index + 1] !== "-") {
1481
+ token = CompleteToken.Other;
1482
+ } else {
1483
+ while (index < length && sql[index] !== "\n") {
1484
+ index++;
1485
+ }
1486
+ if (index >= length) {
1487
+ return state === 1;
1488
+ }
1489
+ token = CompleteToken.Whitespace;
1490
+ }
1491
+ } else if (character === "[") {
1492
+ index++;
1493
+ while (index < length && sql[index] !== "]") {
1494
+ index++;
1495
+ }
1496
+ if (index >= length) {
1497
+ return false;
1498
+ }
1499
+ token = CompleteToken.Other;
1500
+ } else if (character === "`" || character === '"' || character === "'") {
1501
+ index++;
1502
+ while (index < length && sql[index] !== character) {
1503
+ index++;
1504
+ }
1505
+ if (index >= length) {
1506
+ return false;
1507
+ }
1508
+ token = CompleteToken.Other;
1509
+ } else if (isIdentifierCharCode(sql.charCodeAt(index))) {
1510
+ let end = index + 1;
1511
+ while (end < length && isIdentifierCharCode(sql.charCodeAt(end))) {
1512
+ end++;
1513
+ }
1514
+ token = classifyWord(sql.slice(index, end));
1515
+ index = end - 1;
1516
+ } else {
1517
+ token = CompleteToken.Other;
1518
+ }
1519
+ state = completeTransition(state, token);
1520
+ index++;
1521
+ }
1522
+ return state === 1;
1523
+ }
1524
+
1525
+ // src/renderer/objectRenderers.ts
1526
+ var SESSION_GUARD_HEADER = "PRAGMA foreign_keys=OFF;\nBEGIN TRANSACTION;\n";
1527
+ var SESSION_GUARD_FOOTER = "COMMIT;\n";
1528
+ var WRITABLE_SCHEMA_ON = "PRAGMA writable_schema=ON;\n";
1529
+ var WRITABLE_SCHEMA_OFF = "PRAGMA writable_schema=OFF;\n";
1530
+ function renderSchemaLine(sql, tail = ";\n") {
1531
+ let text = sql;
1532
+ if (tail.startsWith(";") && (text.includes("/*") || text.includes("--"))) {
1533
+ for (const terminator of ["", "*/", "\n"]) {
1534
+ if (isCompleteStatement(`${text}${terminator};`)) {
1535
+ text = `${text}${terminator}`;
1536
+ break;
1537
+ }
1538
+ }
1539
+ }
1540
+ if (/^CREATE TABLE ['"]/.test(text)) {
1541
+ return `CREATE TABLE IF NOT EXISTS ${text.slice(13)}${tail}`;
1542
+ }
1543
+ return `${text}${tail}`;
1544
+ }
1545
+ function renderSchemaObject(sql) {
1546
+ return sql.includes("--") ? `${sql}
1547
+ ;
1548
+ ` : `${sql};
1549
+ `;
1550
+ }
1551
+ function renderVirtualTable(name, sql, schemaTableName) {
1552
+ const quotedName = quoteStringLiteral(name);
1553
+ return `INSERT INTO ${schemaTableName}(type,name,tbl_name,rootpage,sql)VALUES('table',${quotedName},${quotedName},0,${quoteStringLiteral(sql)});
1554
+ `;
1555
+ }
1556
+ function renderSystemTablePrelude(name, schemaTableName, systemRowFilter) {
1557
+ if (name === "sqlite_sequence") {
1558
+ if (systemRowFilter === void 0) {
1559
+ return "DELETE FROM sqlite_sequence;\n";
1560
+ }
1561
+ const names = [...new Set(systemRowFilter.map(toAsciiLowerCase))].map(quoteStringLiteral);
1562
+ return `DELETE FROM sqlite_sequence WHERE lower(name) IN (${names.join(",")});
1563
+ `;
1564
+ }
1565
+ return `ANALYZE ${schemaTableName};
1566
+ `;
1567
+ }
1568
+ function renderDrop(kind, name) {
1569
+ return `DROP ${kind} IF EXISTS ${quoteIdentifierIfNeeded(name)};
1570
+ `;
1571
+ }
1572
+ function renderDatabaseSettings(userVersion, applicationId) {
1573
+ let text = "";
1574
+ if (userVersion !== 0) {
1575
+ text += `PRAGMA user_version=${userVersion};
1576
+ `;
1577
+ }
1578
+ if (applicationId !== 0) {
1579
+ text += `PRAGMA application_id=${applicationId};
1580
+ `;
1581
+ }
1582
+ return text;
1583
+ }
1584
+
1585
+ // src/restore/preview.ts
1586
+ function safeSqlPreview(sql, maximumLength = 200) {
1587
+ const normalized = redactSecrets(sql).trim().replace(/\s+/g, " ");
1588
+ if (normalized.length <= maximumLength) {
1589
+ return normalized;
1590
+ }
1591
+ let cut = normalized.slice(0, maximumLength);
1592
+ const lastUnit = cut.charCodeAt(cut.length - 1);
1593
+ if (lastUnit >= 55296 && lastUnit <= 56319) {
1594
+ cut = cut.slice(0, -1);
1595
+ }
1596
+ return `${cut}\u2026`;
1597
+ }
1598
+ var DEFENSIVE_WARNING_COMMENT = "/* WARNING: Script requires that SQLITE_DBCONFIG_DEFENSIVE be disabled */";
1599
+ function isSqliteDump(sample) {
1600
+ const text = typeof sample === "string" ? sample : Buffer.from(sample).toString("utf8");
1601
+ const head = text.slice(0, 8192).replace(/^\uFEFF/, "").replace(/\r\n/g, "\n");
1602
+ let rest = head.trimStart();
1603
+ if (rest.startsWith(DEFENSIVE_WARNING_COMMENT)) {
1604
+ rest = rest.slice(DEFENSIVE_WARNING_COMMENT.length).trimStart();
1605
+ if (rest === "" || /^INSERT INTO /.test(rest) || rest.startsWith("PRAGMA foreign_keys=OFF;")) {
1606
+ return true;
1607
+ }
1608
+ }
1609
+ return /^PRAGMA foreign_keys=OFF;\s*\nBEGIN TRANSACTION;/.test(rest);
1610
+ }
1611
+
1612
+ // src/renderer/plainSql.ts
1613
+ var SECTION_BY_ENTRY = {
1614
+ table: "table-structure",
1615
+ tableData: "table-data",
1616
+ virtualTable: "virtual-table",
1617
+ index: "index",
1618
+ trigger: "trigger",
1619
+ view: "view"
1620
+ };
1621
+ async function renderPlainSql(request) {
1622
+ const options = resolvePlainSqlRenderOptions(request.options);
1623
+ const { database, archive, writer, signal, onProgress, onTableData } = request;
1624
+ const mode = request.mode ?? "full";
1625
+ if (!archive.valid) {
1626
+ throw new SqliteDumperError(
1627
+ "invalid-archive",
1628
+ "Cannot render an archive inspection that failed validation; see archive.diagnostics, archive.cycles and archive.unsatisfiedDependencies"
1629
+ );
1630
+ }
1631
+ const warnings = [];
1632
+ const renderedDumpIds = [];
1633
+ const skippedDumpIds = [];
1634
+ const schemaTableName = options.legacySchemaTableName ? "sqlite_master" : "sqlite_schema";
1635
+ const tables = new Map(database.tables.map((table) => [foldSqliteName(table.name), table]));
1636
+ const indexes = new Map(database.indexes.map((index) => [foldSqliteName(index.name), index]));
1637
+ const triggers = new Map(
1638
+ database.triggers.map((trigger) => [foldSqliteName(trigger.name), trigger])
1639
+ );
1640
+ const views = new Map(database.views.map((view) => [foldSqliteName(view.name), view]));
1641
+ const emit = async (text) => {
1642
+ if (text !== "") {
1643
+ await writer.write(text, signal);
1644
+ }
1645
+ };
1646
+ const guards = options.includeSessionGuards && mode !== "data-only";
1647
+ if (!options.includeSessionGuards && mode !== "data-only") {
1648
+ warnings.push({
1649
+ severity: "warning",
1650
+ code: "session-guards-disabled",
1651
+ message: "render.includeSessionGuards is false, so the dump omits PRAGMA foreign_keys=OFF and its BEGIN TRANSACTION / COMMIT. Tables that reference each other may fail to restore in the emitted order, and every INSERT runs as its own transaction, which makes restoring a large dump dramatically slower."
1652
+ });
1653
+ }
1654
+ reportUnDumpedSettings(request, options, warnings);
1655
+ const containsVirtualTables = mode !== "schema-only" && archive.entries.some(
1656
+ (entry) => entry.objectType === "virtualTable" || entry.tableKind === "virtual" || entry.tableKind === "shadow" && tables.get(foldSqliteName(entry.name))?.ownerVirtualTable !== void 0
1657
+ );
1658
+ let writableSchema = false;
1659
+ try {
1660
+ if (options.includeHeaderComments && containsVirtualTables) {
1661
+ await emit(`${DEFENSIVE_WARNING_COMMENT}
1662
+ `);
1663
+ }
1664
+ if (guards) {
1665
+ await emit(SESSION_GUARD_HEADER);
1666
+ }
1667
+ let processed = 0;
1668
+ const total = archive.entries.length;
1669
+ for (const entry of archive.entries) {
1670
+ throwIfAborted2(signal);
1671
+ processed++;
1672
+ onProgress?.({
1673
+ phase: "rendering-schema",
1674
+ section: SECTION_BY_ENTRY[entry.objectType],
1675
+ objectsProcessed: processed,
1676
+ objectsTotal: total,
1677
+ objectName: entry.name,
1678
+ schemaName: entry.schemaName,
1679
+ bytesWritten: writer.bytesWritten
1680
+ });
1681
+ let handled;
1682
+ switch (entry.objectType) {
1683
+ case "table": {
1684
+ const table = tables.get(foldSqliteName(entry.name));
1685
+ if (!table) {
1686
+ handled = missing(entry, "table", warnings, options);
1687
+ break;
1688
+ }
1689
+ if (table.kind === "system") {
1690
+ await emit(
1691
+ renderSystemTablePrelude(table.name, schemaTableName, entry.systemRowFilter)
1692
+ );
1693
+ } else {
1694
+ if (options.addDropStatements) {
1695
+ await emit(renderDrop("TABLE", table.name));
1696
+ }
1697
+ await emit(renderSchemaLine(table.sql));
1698
+ }
1699
+ handled = true;
1700
+ break;
1701
+ }
1702
+ case "virtualTable": {
1703
+ const table = tables.get(foldSqliteName(entry.name));
1704
+ if (!table) {
1705
+ handled = missing(entry, "virtual table", warnings, options);
1706
+ break;
1707
+ }
1708
+ if (options.addDropStatements) {
1709
+ await emit(renderDrop("TABLE", table.name));
1710
+ }
1711
+ if (mode === "schema-only") {
1712
+ await emit(renderSchemaLine(table.sql));
1713
+ } else {
1714
+ if (!writableSchema) {
1715
+ await emit(WRITABLE_SCHEMA_ON);
1716
+ writableSchema = true;
1717
+ }
1718
+ await emit(renderVirtualTable(table.name, table.sql, schemaTableName));
1719
+ }
1720
+ handled = true;
1721
+ break;
1722
+ }
1723
+ case "tableData": {
1724
+ const table = tables.get(foldSqliteName(entry.name));
1725
+ if (!table) {
1726
+ handled = missing(entry, "table", warnings, options);
1727
+ break;
1728
+ }
1729
+ if (onTableData) {
1730
+ handled = await onTableData(entry);
1731
+ } else {
1732
+ warnings.push({
1733
+ severity: "warning",
1734
+ code: "data-not-rendered",
1735
+ message: `Row data for table "${entry.name}" was selected, but renderPlainSql only renders schema objects; use dumpSqlite (or supply onTableData) with a live connection to stream rows.`,
1736
+ objectReference: { kind: "table", schemaName: entry.schemaName, name: entry.name }
1737
+ });
1738
+ handled = true;
1739
+ }
1740
+ break;
1741
+ }
1742
+ case "index":
1743
+ case "trigger":
1744
+ case "view": {
1745
+ const object = lookupSchemaObject(entry, indexes, triggers, views);
1746
+ if (!object || object.sql === null) {
1747
+ handled = missing(entry, entry.objectType, warnings, options);
1748
+ break;
1749
+ }
1750
+ if (options.addDropStatements) {
1751
+ await emit(
1752
+ renderDrop(
1753
+ entry.objectType === "index" ? "INDEX" : entry.objectType === "trigger" ? "TRIGGER" : "VIEW",
1754
+ entry.name
1755
+ )
1756
+ );
1757
+ }
1758
+ await emit(renderSchemaObject(object.sql));
1759
+ handled = true;
1760
+ break;
1761
+ }
1762
+ default: {
1763
+ const unreachable = entry.objectType;
1764
+ throw new SqliteDumperError(
1765
+ "unsupported-object",
1766
+ `Unhandled archive object type: ${String(unreachable)}`
1767
+ );
1768
+ }
1769
+ }
1770
+ if (handled) {
1771
+ renderedDumpIds.push(entry.dumpId);
1772
+ } else {
1773
+ skippedDumpIds.push(entry.dumpId);
1774
+ }
1775
+ }
1776
+ if (writableSchema) {
1777
+ await emit(WRITABLE_SCHEMA_OFF);
1778
+ }
1779
+ if (options.includeDatabaseSettings) {
1780
+ await emit(renderDatabaseSettings(database.userVersion, database.applicationId));
1781
+ }
1782
+ if (guards) {
1783
+ await emit(SESSION_GUARD_FOOTER);
1784
+ }
1785
+ return {
1786
+ bytesWritten: writer.bytesWritten,
1787
+ renderedDumpIds,
1788
+ skippedDumpIds,
1789
+ warnings,
1790
+ cancelled: false
1791
+ };
1792
+ } catch (error) {
1793
+ if (isAbortError(error)) {
1794
+ return {
1795
+ bytesWritten: writer.bytesWritten,
1796
+ renderedDumpIds,
1797
+ skippedDumpIds,
1798
+ warnings,
1799
+ cancelled: true
1800
+ };
1801
+ }
1802
+ throw error;
1803
+ }
1804
+ }
1805
+ function lookupSchemaObject(entry, indexes, triggers, views) {
1806
+ const key = foldSqliteName(entry.name);
1807
+ switch (entry.objectType) {
1808
+ case "index":
1809
+ return indexes.get(key);
1810
+ case "trigger":
1811
+ return triggers.get(key);
1812
+ default:
1813
+ return views.get(key);
1814
+ }
1815
+ }
1816
+ function reportUnDumpedSettings(request, options, warnings) {
1817
+ if (options.includeDatabaseSettings) {
1818
+ return;
1819
+ }
1820
+ const { database } = request;
1821
+ if (database.userVersion !== 0) {
1822
+ warnings.push({
1823
+ severity: "warning",
1824
+ code: "user-version-not-dumped",
1825
+ message: `The database's PRAGMA user_version is ${database.userVersion}, which the dump does not carry (the native .dump does not either). Set render.includeDatabaseSettings to include it; applications often track schema migrations in it.`,
1826
+ objectReference: {
1827
+ kind: "database",
1828
+ schemaName: database.schemaName,
1829
+ name: database.schemaName
1830
+ }
1831
+ });
1832
+ }
1833
+ if (database.applicationId !== 0) {
1834
+ warnings.push({
1835
+ severity: "warning",
1836
+ code: "application-id-not-dumped",
1837
+ message: `The database's PRAGMA application_id is ${database.applicationId}, which the dump does not carry (the native .dump does not either). Set render.includeDatabaseSettings to include it.`,
1838
+ objectReference: {
1839
+ kind: "database",
1840
+ schemaName: database.schemaName,
1841
+ name: database.schemaName
1842
+ }
1843
+ });
1844
+ }
1845
+ }
1846
+ function missing(entry, kind, warnings, options) {
1847
+ const message = `Archive entry references ${kind} "${entry.name}", which was not found in the introspected model`;
1848
+ if (options.unsupportedFeaturePolicy === "warn-omit") {
1849
+ warnings.push({ severity: "warning", code: "model-object-missing", message });
1850
+ return false;
1851
+ }
1852
+ throw new SqliteDumperError("model-object-missing", message);
1853
+ }
1854
+
1855
+ // src/data/chunkBuilder.ts
1856
+ var SqlChunkBuilder = class {
1857
+ parts = [];
1858
+ byteLength = 0;
1859
+ hasBytes = false;
1860
+ /** UTF-8 byte length of everything appended so far. */
1861
+ get length() {
1862
+ return this.byteLength;
1863
+ }
1864
+ get isEmpty() {
1865
+ return this.parts.length === 0;
1866
+ }
1867
+ append(part) {
1868
+ if (typeof part === "string") {
1869
+ if (part.length === 0) {
1870
+ return this;
1871
+ }
1872
+ this.parts.push(part);
1873
+ this.byteLength += Buffer.byteLength(part, "utf8");
1874
+ return this;
1875
+ }
1876
+ if (part.length === 0) {
1877
+ return this;
1878
+ }
1879
+ this.parts.push(part);
1880
+ this.byteLength += part.length;
1881
+ this.hasBytes = true;
1882
+ return this;
1883
+ }
1884
+ /** Appends everything from `other`, leaving `other` untouched. */
1885
+ appendBuilder(other) {
1886
+ for (const part of other.parts) {
1887
+ this.append(part);
1888
+ }
1889
+ return this;
1890
+ }
1891
+ /** The accumulated content, as a `string` when it is all text and a `Buffer` otherwise. */
1892
+ build() {
1893
+ if (!this.hasBytes) {
1894
+ return this.parts.join("");
1895
+ }
1896
+ return Buffer.concat(
1897
+ this.parts.map((part) => typeof part === "string" ? Buffer.from(part, "utf8") : part)
1898
+ );
1899
+ }
1900
+ };
1901
+
1902
+ // src/data/valueQuery.ts
1903
+ var import_node_buffer = require("buffer");
1904
+ function realLiteralExpression(column) {
1905
+ return `CASE WHEN ${column} = 9e999 THEN '9.0e+999' WHEN ${column} = -9e999 THEN '-9.0e+999' WHEN ${column} >= -9223372036854775808.0 AND ${column} < 9223372036854775808.0 AND ${column} = CAST(${column} AS INTEGER) THEN CAST(CAST(${column} AS INTEGER) AS TEXT) || '.0' ELSE printf('%!.20g', ${column}) END`;
1906
+ }
1907
+ function columnValueSelect(column, index, utf8Database) {
1908
+ const textBranch = utf8Database ? `CAST(${column} AS BLOB)` : column;
1909
+ return `typeof(${column}) AS "t${index}", CASE typeof(${column}) WHEN 'integer' THEN CAST(${column} AS TEXT) WHEN 'real' THEN ${realLiteralExpression(column)} WHEN 'text' THEN ${textBranch} ELSE ${column} END AS "v${index}"`;
1910
+ }
1911
+ function asBytes(value) {
1912
+ if (Buffer.isBuffer(value)) {
1913
+ return value;
1914
+ }
1915
+ if (value instanceof Uint8Array) {
1916
+ return Buffer.from(value.buffer, value.byteOffset, value.byteLength);
1917
+ }
1918
+ return Buffer.from(String(value), "utf8");
1919
+ }
1920
+ function renderColumnLiteral(row, index, textStyle) {
1921
+ const storageClass = row[`t${index}`];
1922
+ const value = row[`v${index}`] ?? null;
1923
+ switch (storageClass) {
1924
+ case "integer":
1925
+ case "real":
1926
+ return String(value);
1927
+ case "text": {
1928
+ if (typeof value === "string") {
1929
+ return renderTextLiteral(value, textStyle);
1930
+ }
1931
+ const bytes = asBytes(value);
1932
+ if ((0, import_node_buffer.isUtf8)(bytes)) {
1933
+ return renderTextLiteral(bytes.toString("utf8"), textStyle);
1934
+ }
1935
+ return Buffer.from(renderTextLiteral(bytes.toString("latin1"), textStyle), "latin1");
1936
+ }
1937
+ case "blob":
1938
+ return renderBlobLiteral(asBytes(value));
1939
+ default:
1940
+ return "NULL";
1941
+ }
1942
+ }
1943
+
1944
+ // src/data/insertExport.ts
1945
+ var DEFAULT_MAX_STATEMENT_BYTES = 1024 * 1024;
1946
+ var DEFAULT_MAX_ROWS_PER_STATEMENT = 500;
1947
+ var OUTPUT_CHUNK_BYTES = 64 * 1024;
1948
+ var ROWID_NAMES = ["rowid", "_rowid_", "oid"];
1949
+ function insertableColumns(table) {
1950
+ return [...table.columns].sort((a, b) => a.cid - b.cid).filter((column) => column.hidden === 0);
1951
+ }
1952
+ function preservableRowidName(table) {
1953
+ if (table.withoutRowid || table.rowidAliasColumn !== null || table.kind === "virtual") {
1954
+ return null;
1955
+ }
1956
+ const names = new Set(insertableColumns(table).map((column) => toAsciiLowerCase(column.name)));
1957
+ for (const candidate of ROWID_NAMES) {
1958
+ if (!names.has(candidate)) {
1959
+ return candidate;
1960
+ }
1961
+ }
1962
+ return null;
1963
+ }
1964
+ async function exportTableDataAsInserts(request) {
1965
+ const { connection, schemaName, table, writer, signal, onProgress } = request;
1966
+ const options = request.options ?? {};
1967
+ const extendedInsert = options.extendedInsert ?? false;
1968
+ const maxRowsPerStatement = extendedInsert ? Math.max(1, options.maxRowsPerStatement ?? DEFAULT_MAX_ROWS_PER_STATEMENT) : 1;
1969
+ const maxStatementBytes = Math.max(
1970
+ 1024,
1971
+ options.maxStatementBytes ?? DEFAULT_MAX_STATEMENT_BYTES
1972
+ );
1973
+ const textStyle = options.rawNewlines ? "raw-newlines" : "escaped";
1974
+ const utf8Database = (request.encoding ?? "UTF-8").toUpperCase() === "UTF-8";
1975
+ const warnings = [];
1976
+ const columns = insertableColumns(table);
1977
+ const rowidName = options.preserveRowids ? preservableRowidName(table) : null;
1978
+ for (const column of table.columns) {
1979
+ if (column.generated !== "none") {
1980
+ warnings.push({
1981
+ severity: "info",
1982
+ code: "generated-column-not-exported",
1983
+ message: `Column "${table.name}"."${column.name}" is a ${column.generated.toUpperCase()} generated column; SQLite derives its value, so it is excluded from INSERT and recomputed on restore.`,
1984
+ objectReference: { kind: "column", schemaName, name: column.name, parentName: table.name }
1985
+ });
1986
+ }
1987
+ }
1988
+ if (columns.length === 0) {
1989
+ warnings.push({
1990
+ severity: "warning",
1991
+ code: "table-has-no-insertable-columns",
1992
+ message: `Table "${table.name}" has no insertable columns, so no row data is dumped for it.`,
1993
+ objectReference: { kind: "table", schemaName, name: table.name }
1994
+ });
1995
+ return {
1996
+ rowsExported: 0,
1997
+ bytesWritten: writer.bytesWritten,
1998
+ statementsWritten: 0,
1999
+ cancelled: false,
2000
+ warnings
2001
+ };
2002
+ }
2003
+ const columnList = rowidName ? `(${[rowidName, ...columns.map((column) => quoteIdentifierIfNeeded(column.name))].join(",")})` : "";
2004
+ const statementPrefix = `INSERT INTO ${quoteIdentifierIfNeeded(table.name)}${columnList} VALUES`;
2005
+ const selectList = [
2006
+ ...rowidName ? [columnValueSelect(rowidName, 0, utf8Database)] : [],
2007
+ ...columns.map(
2008
+ (column, index) => columnValueSelect(quoteIdentifier(column.name), index + (rowidName ? 1 : 0), utf8Database)
2009
+ )
2010
+ ].join(", ");
2011
+ const valueCount = columns.length + (rowidName ? 1 : 0);
2012
+ const sql = `SELECT ${selectList} FROM ${quoteQualifiedIdentifier(schemaName, table.name)}${systemRowFilterClause(table, request.systemRowFilter)}`;
2013
+ let rowsExported = 0;
2014
+ let statementsWritten = 0;
2015
+ let output = new SqlChunkBuilder();
2016
+ let statement = null;
2017
+ let statementRows = 0;
2018
+ const flushOutput = async () => {
2019
+ if (output.isEmpty) {
2020
+ return;
2021
+ }
2022
+ const chunk = output.build();
2023
+ output = new SqlChunkBuilder();
2024
+ await writer.write(chunk, signal);
2025
+ };
2026
+ const closeStatement = async () => {
2027
+ if (!statement || statementRows === 0) {
2028
+ return;
2029
+ }
2030
+ statement.append(";\n");
2031
+ output.appendBuilder(statement);
2032
+ statement = null;
2033
+ statementRows = 0;
2034
+ statementsWritten++;
2035
+ if (output.length >= OUTPUT_CHUNK_BYTES) {
2036
+ await flushOutput();
2037
+ }
2038
+ };
2039
+ const progress = (exportState) => {
2040
+ onProgress?.({
2041
+ phase: "exporting-data",
2042
+ section: "table-data",
2043
+ schemaName,
2044
+ tableName: table.name,
2045
+ objectName: table.name,
2046
+ rowsExported,
2047
+ bytesWritten: writer.bytesWritten,
2048
+ exportState
2049
+ });
2050
+ };
2051
+ progress("started");
2052
+ try {
2053
+ for await (const row of connection.stream(
2054
+ { sql },
2055
+ {
2056
+ ...signal === void 0 ? {} : { signal },
2057
+ ...options.streamBatchSize === void 0 ? {} : { batchSize: options.streamBatchSize }
2058
+ }
2059
+ )) {
2060
+ throwIfAborted2(signal);
2061
+ const tuple = new SqlChunkBuilder();
2062
+ tuple.append("(");
2063
+ for (let index = 0; index < valueCount; index++) {
2064
+ if (index > 0) {
2065
+ tuple.append(",");
2066
+ }
2067
+ tuple.append(renderColumnLiteral(row, index, textStyle));
2068
+ }
2069
+ tuple.append(")");
2070
+ if (statement && (statementRows >= maxRowsPerStatement || statement.length + tuple.length + 2 > maxStatementBytes)) {
2071
+ await closeStatement();
2072
+ }
2073
+ if (!statement) {
2074
+ statement = new SqlChunkBuilder();
2075
+ statement.append(statementPrefix);
2076
+ } else {
2077
+ statement.append(",");
2078
+ }
2079
+ statement.appendBuilder(tuple);
2080
+ statementRows++;
2081
+ rowsExported++;
2082
+ if (rowsExported % 1e3 === 0) {
2083
+ progress("progress");
2084
+ }
2085
+ }
2086
+ await closeStatement();
2087
+ await flushOutput();
2088
+ progress("finished");
2089
+ return {
2090
+ rowsExported,
2091
+ bytesWritten: writer.bytesWritten,
2092
+ statementsWritten,
2093
+ cancelled: false,
2094
+ warnings
2095
+ };
2096
+ } catch (error) {
2097
+ if (isAbortError(error)) {
2098
+ progress("cancelled");
2099
+ return {
2100
+ rowsExported,
2101
+ bytesWritten: writer.bytesWritten,
2102
+ statementsWritten,
2103
+ cancelled: true,
2104
+ warnings
2105
+ };
2106
+ }
2107
+ progress("failed");
2108
+ throw error;
2109
+ }
2110
+ }
2111
+ function systemRowFilterClause(table, filter) {
2112
+ if (filter === void 0 || table.kind !== "system") {
2113
+ return "";
2114
+ }
2115
+ const column = table.name === "sqlite_sequence" ? "name" : "tbl";
2116
+ const names = [...new Set(filter.map(toAsciiLowerCase))].map(quoteStringLiteral);
2117
+ if (names.length === 0) {
2118
+ return " WHERE 0";
2119
+ }
2120
+ return ` WHERE lower(${column}) IN (${names.join(",")})`;
2121
+ }
2122
+
2123
+ // src/compatibility/check.ts
2124
+ var FEATURE_LABELS = {
2125
+ supportsWithoutRowid: "WITHOUT ROWID tables (SQLite 3.8.2+)",
2126
+ supportsMultiRowValues: "multi-row VALUES (SQLite 3.7.11+)",
2127
+ supportsPragmaFunctions: "table-valued pragma functions (SQLite 3.16.0+)",
2128
+ supportsTableXinfo: "PRAGMA table_xinfo (SQLite 3.26.0+)",
2129
+ supportsGeneratedColumns: "generated columns (SQLite 3.31.0+)",
2130
+ supportsSqliteSchemaAlias: "the sqlite_schema table name (SQLite 3.33.0+)",
2131
+ supportsWritableSchemaReset: "PRAGMA writable_schema=RESET (SQLite 3.35.0+)",
2132
+ supportsStrictTables: "STRICT tables (SQLite 3.37.0+)",
2133
+ supportsTableList: "PRAGMA table_list (SQLite 3.37.0+)"
2134
+ };
2135
+ var BUILT_IN_COLLATIONS = /* @__PURE__ */ new Set(["BINARY", "NOCASE", "RTRIM"]);
2136
+ function checkTargetCompatibility(database, target, options = {}) {
2137
+ const diagnostics = [];
2138
+ const { schemaName } = database;
2139
+ const reported = /* @__PURE__ */ new Set();
2140
+ const require2 = (feature, detail, objectReference) => {
2141
+ if (target[feature] || reported.has(feature)) {
2142
+ return;
2143
+ }
2144
+ reported.add(feature);
2145
+ diagnostics.push({
2146
+ severity: "error",
2147
+ code: "unsupported-target-feature",
2148
+ message: `Restore target does not support ${FEATURE_LABELS[feature]}, which this dump uses: ${detail}`,
2149
+ ...objectReference === void 0 ? {} : { objectReference }
2150
+ });
2151
+ };
2152
+ const missingModules = /* @__PURE__ */ new Set();
2153
+ for (const table of database.tables) {
2154
+ const reference = { kind: "table", schemaName, name: table.name };
2155
+ if (table.strict) {
2156
+ require2("supportsStrictTables", `table "${table.name}"`, reference);
2157
+ }
2158
+ if (table.withoutRowid) {
2159
+ require2("supportsWithoutRowid", `table "${table.name}"`, reference);
2160
+ }
2161
+ for (const column of table.columns) {
2162
+ if (column.generated !== "none") {
2163
+ require2("supportsGeneratedColumns", `column "${table.name}"."${column.name}"`, {
2164
+ kind: "column",
2165
+ schemaName,
2166
+ name: column.name,
2167
+ parentName: table.name
2168
+ });
2169
+ }
2170
+ }
2171
+ if (table.kind === "virtual") {
2172
+ if (!options.legacySchemaTableName) {
2173
+ require2("supportsSqliteSchemaAlias", `virtual table "${table.name}" is recreated through INSERT INTO sqlite_schema`, reference);
2174
+ }
2175
+ const module2 = table.virtualModule === void 0 ? void 0 : toAsciiLowerCase(table.virtualModule);
2176
+ if (options.modules && module2 !== void 0 && !options.modules.has(module2) && !missingModules.has(module2)) {
2177
+ missingModules.add(module2);
2178
+ diagnostics.push({
2179
+ severity: "error",
2180
+ code: "virtual-table-module-unavailable",
2181
+ message: `Restore target has no "${table.virtualModule}" module, which virtual table "${table.name}" needs. The dump still restores \u2014 its schema row and shadow tables are plain SQL \u2014 but the table cannot be queried there until the module is loaded.`,
2182
+ objectReference: { kind: "virtualTable", schemaName, name: table.name }
2183
+ });
2184
+ }
2185
+ }
2186
+ if (table.kind === "system" && /^sqlite_stat/.test(table.name) && !options.legacySchemaTableName) {
2187
+ require2("supportsSqliteSchemaAlias", "the statistics tables are recreated by ANALYZE sqlite_schema", reference);
2188
+ }
2189
+ }
2190
+ if (options.extendedInsert) {
2191
+ require2("supportsMultiRowValues", "dataExport.extendedInsert is enabled");
2192
+ }
2193
+ const customCollations = /* @__PURE__ */ new Map();
2194
+ for (const index of database.indexes) {
2195
+ for (const column of index.columns) {
2196
+ if (column.collation !== null && !BUILT_IN_COLLATIONS.has(toAsciiUpperCase(column.collation))) {
2197
+ customCollations.set(toAsciiUpperCase(column.collation), index.name);
2198
+ }
2199
+ }
2200
+ }
2201
+ for (const [collation, indexName] of customCollations) {
2202
+ diagnostics.push({
2203
+ severity: "warning",
2204
+ code: "custom-collation",
2205
+ message: `Index "${indexName}" uses the collation ${collation}, which is not built into SQLite. The restoring application must register it (sqlite3_create_collation) before the restore, or the index cannot be created.`,
2206
+ objectReference: { kind: "index", schemaName, name: indexName }
2207
+ });
2208
+ }
2209
+ return diagnostics;
2210
+ }
2211
+
2212
+ // src/compatibility/unsupported.ts
2213
+ var UNSUPPORTED_FEATURES = [
2214
+ {
2215
+ code: "file-settings-not-dumped",
2216
+ summary: "file-level settings (page_size, auto_vacuum, journal_mode, encoding)",
2217
+ detail: "These describe how the database file is laid out, not what it contains, and most can only be chosen before the first table is created. The native .dump does not carry them either. Set them on the target database before restoring if they matter; the dump restores correctly under any of them."
2218
+ },
2219
+ {
2220
+ code: "temp-and-attached-schemas-not-dumped",
2221
+ summary: "the temp schema and attached databases",
2222
+ detail: "A dump covers one schema \u2014 main by default. Temporary objects belong to one connection, and each attached database is a separate file; dump an attached database on its own by passing its name as schemaName."
2223
+ },
2224
+ {
2225
+ code: "application-functions-not-dumped",
2226
+ summary: "application-defined functions, collations and loadable extensions",
2227
+ detail: "User-defined SQL functions, collating sequences and virtual table modules are registered by the application (or loaded from a shared library), not stored in the database. The schema that uses them is dumped verbatim; the restoring application must register them first, or objects using them cannot be created or queried."
2228
+ },
2229
+ {
2230
+ code: "encryption-not-dumped",
2231
+ summary: "encryption keys",
2232
+ detail: "An encrypted database (SQLCipher, SEE) is dumped as plain SQL once it is opened with its key. The dump itself is not encrypted, and no key is ever written into it."
2233
+ }
2234
+ ];
2235
+ function unsupportedFeatureDiagnostics() {
2236
+ return UNSUPPORTED_FEATURES.map((feature) => ({
2237
+ severity: "info",
2238
+ code: feature.code,
2239
+ message: `Not dumped: ${feature.summary}. ${feature.detail}`
2240
+ }));
2241
+ }
2242
+
2243
+ // src/preflight/preflightRestore.ts
2244
+ async function queryRows(connection, sql, signal) {
2245
+ try {
2246
+ return (await connection.query({ sql }, signal)).rows;
2247
+ } catch (error) {
2248
+ if (isAbortError(error)) throw error;
2249
+ return void 0;
2250
+ }
2251
+ }
2252
+ function firstValue(rows) {
2253
+ const first = rows?.[0];
2254
+ return first === void 0 ? void 0 : Object.values(first)[0];
2255
+ }
2256
+ async function preflightRestore(request) {
2257
+ const acquired = await acquireSqliteConnection(request.connection, request.signal);
2258
+ const connection = acquired.connection;
2259
+ const { signal } = request;
2260
+ try {
2261
+ const version = await detectSqliteVersion(connection, signal);
2262
+ const capabilities = detectSqliteCapabilities(version);
2263
+ const encoding = toText(firstValue(await queryRows(connection, "PRAGMA encoding", signal))) ?? "UTF-8";
2264
+ const foreignKeysEnabled = toNumber(firstValue(await queryRows(connection, "PRAGMA foreign_keys", signal))) !== 0;
2265
+ const moduleRows = await queryRows(connection, "SELECT name FROM pragma_module_list", signal);
2266
+ const optionRows = await queryRows(connection, "PRAGMA compile_options", signal);
2267
+ const compileOptions = optionRows?.map((row) => toText(Object.values(row)[0]) ?? "");
2268
+ const modules = moduleRows?.map((row) => toText(row.name) ?? "").filter((name) => name !== "");
2269
+ const existingRows = await queryRows(
2270
+ connection,
2271
+ "SELECT type, name FROM main.sqlite_master WHERE sql IS NOT NULL AND name NOT LIKE 'sqlite\\_%' ESCAPE '\\' ORDER BY rowid",
2272
+ signal
2273
+ ) ?? [];
2274
+ const existingObjects = existingRows.map((row) => ({
2275
+ type: toText(row.type) ?? "",
2276
+ name: toText(row.name) ?? ""
2277
+ }));
2278
+ const inTransaction = connection.isInTransaction?.();
2279
+ const diagnostics = [];
2280
+ if (inTransaction) {
2281
+ diagnostics.push({
2282
+ severity: "warning",
2283
+ code: "target-in-transaction",
2284
+ message: `The target handle is already inside a transaction. A full dump's own BEGIN TRANSACTION will fail; commit first, or restore with transaction: "wrap".`
2285
+ });
2286
+ }
2287
+ const database = request.database;
2288
+ if (database) {
2289
+ diagnostics.push(
2290
+ ...checkTargetCompatibility(database, capabilities, {
2291
+ ...request.options,
2292
+ ...modules === void 0 ? {} : { modules: new Set(modules.map(toAsciiLowerCase)) }
2293
+ })
2294
+ );
2295
+ const hasVirtualTables = database.tables.some((table) => table.kind === "virtual");
2296
+ if (hasVirtualTables && !connection.setDefensive) {
2297
+ diagnostics.push({
2298
+ severity: "warning",
2299
+ code: "defensive-mode-not-controllable",
2300
+ message: "This dump recreates virtual tables by writing sqlite_schema directly, which SQLITE_DBCONFIG_DEFENSIVE forbids, and this adapter cannot turn defensive mode off. The restore succeeds only if the connection is not in defensive mode."
2301
+ });
2302
+ }
2303
+ const hasStat4 = database.tables.some((table) => table.name === "sqlite_stat4");
2304
+ if (hasStat4 && compileOptions && !compileOptions.includes("ENABLE_STAT4")) {
2305
+ diagnostics.push({
2306
+ severity: "error",
2307
+ code: "statistics-table-unsupported",
2308
+ message: "The source database has a sqlite_stat4 table, and the target SQLite is not built with SQLITE_ENABLE_STAT4, so ANALYZE there does not create it and the dump's INSERT INTO sqlite_stat4 fails. The native .dump of such a database fails the same way. Dump with objectKinds.includeSystemTables: false, or drop sqlite_stat4 from the source copy first."
2309
+ });
2310
+ }
2311
+ if (database.encoding.toUpperCase() !== encoding.toUpperCase()) {
2312
+ diagnostics.push({
2313
+ severity: "info",
2314
+ code: "encoding-differs",
2315
+ message: `The source database is ${database.encoding} and the target is ${encoding}. Text is converted between the two on restore, which is lossless for valid text.`
2316
+ });
2317
+ }
2318
+ if (!request.options?.addDropStatements) {
2319
+ const existing = new Map(
2320
+ existingObjects.map((object) => [toAsciiLowerCase(object.name), object])
2321
+ );
2322
+ const created = [
2323
+ ...database.tables.filter((table) => table.kind !== "system").map((table) => table.name),
2324
+ ...database.views.map((view) => view.name),
2325
+ ...database.indexes.filter((index) => index.sql !== null).map((index) => index.name),
2326
+ ...database.triggers.map((trigger) => trigger.name)
2327
+ ];
2328
+ for (const name of created) {
2329
+ const conflict = existing.get(toAsciiLowerCase(name));
2330
+ if (conflict) {
2331
+ diagnostics.push({
2332
+ severity: "error",
2333
+ code: "object-already-exists",
2334
+ message: `The target already has a ${conflict.type} named "${conflict.name}", so the dump's CREATE for it will fail. Restore into an empty database, drop it first, or render the dump with addDropStatements.`,
2335
+ objectReference: { kind: "table", schemaName: "main", name: conflict.name }
2336
+ });
2337
+ }
2338
+ }
2339
+ }
2340
+ }
2341
+ return {
2342
+ version,
2343
+ capabilities,
2344
+ encoding,
2345
+ foreignKeysEnabled,
2346
+ ...inTransaction === void 0 ? {} : { inTransaction },
2347
+ canDisableDefensiveMode: typeof connection.setDefensive === "function",
2348
+ ...modules === void 0 ? {} : { modules },
2349
+ ...compileOptions === void 0 ? {} : { compileOptions },
2350
+ existingObjects,
2351
+ diagnostics
2352
+ };
2353
+ } finally {
2354
+ await acquired.release();
2355
+ }
2356
+ }
2357
+
2358
+ // src/restore/errors.ts
2359
+ var RestoreError = class extends SqliteDumperError {
2360
+ };
2361
+ var SqlParseError = class extends RestoreError {
2362
+ line;
2363
+ constructor(code, message, line, options) {
2364
+ super(code, message, options);
2365
+ this.name = "SqlParseError";
2366
+ this.line = line;
2367
+ }
2368
+ };
2369
+ var MalformedSqlDumpError = class extends SqlParseError {
2370
+ openConstruct;
2371
+ constructor(openConstruct, line) {
2372
+ super(
2373
+ "malformed-sql-dump",
2374
+ `Unterminated ${openConstruct} starting at line ${line}: the input ends before it is closed`,
2375
+ line
2376
+ );
2377
+ this.name = "MalformedSqlDumpError";
2378
+ this.openConstruct = openConstruct;
2379
+ }
2380
+ };
2381
+ var StatementTooLargeError = class extends SqlParseError {
2382
+ maxStatementBytes;
2383
+ constructor(maxStatementBytes, line) {
2384
+ super(
2385
+ "statement-too-large",
2386
+ `Statement starting near line ${line} exceeds the configured limit of ${maxStatementBytes} bytes without being complete; increase options.maxStatementBytes if this statement is genuinely intended to be this large, or check for a CREATE TRIGGER missing its END`,
2387
+ line
2388
+ );
2389
+ this.name = "StatementTooLargeError";
2390
+ this.maxStatementBytes = maxStatementBytes;
2391
+ }
2392
+ };
2393
+ var UnsupportedClientCommandError = class extends SqlParseError {
2394
+ command;
2395
+ constructor(command, line) {
2396
+ super(
2397
+ "unsupported-client-command",
2398
+ `Unsupported sqlite3 shell command ".${command}" on line ${line}: dbgate-sqlite-dumper executes SQL statements and does not implement shell dot-commands that change the database. Run this script through the sqlite3 shell, or remove the command.`,
2399
+ line
2400
+ );
2401
+ this.name = "UnsupportedClientCommandError";
2402
+ this.command = command;
2403
+ }
2404
+ };
2405
+ var InvalidTextEncodingError = class extends SqlParseError {
2406
+ constructor(message, line) {
2407
+ super("invalid-text-encoding", `${message} (near line ${line})`, line);
2408
+ this.name = "InvalidTextEncodingError";
2409
+ }
2410
+ };
2411
+ var RestoreExecutionError = class extends RestoreError {
2412
+ statementIndex;
2413
+ location;
2414
+ sqlPreview;
2415
+ sqliteError;
2416
+ constructor(statementIndex, location, sqlPreview, message, sqliteError, options) {
2417
+ super("restore-execution-failed", message, options);
2418
+ this.name = "RestoreExecutionError";
2419
+ this.statementIndex = statementIndex;
2420
+ this.location = location;
2421
+ this.sqlPreview = sqlPreview;
2422
+ if (sqliteError) {
2423
+ this.sqliteError = sqliteError;
2424
+ }
2425
+ }
2426
+ };
2427
+
2428
+ // src/restore/statementInfo.ts
2429
+ function leadingTokens(sql, limit) {
2430
+ const tokens = [];
2431
+ let index = 0;
2432
+ const length = sql.length;
2433
+ while (index < length && tokens.length < limit) {
2434
+ const character = sql[index];
2435
+ const code = sql.charCodeAt(index);
2436
+ if (/\s/.test(character) || character === "\uFEFF") {
2437
+ index++;
2438
+ continue;
2439
+ }
2440
+ if (character === "-" && sql[index + 1] === "-") {
2441
+ const end = sql.indexOf("\n", index);
2442
+ index = end === -1 ? length : end + 1;
2443
+ continue;
2444
+ }
2445
+ if (character === "/" && sql[index + 1] === "*") {
2446
+ const end = sql.indexOf("*/", index + 2);
2447
+ index = end === -1 ? length : end + 2;
2448
+ continue;
2449
+ }
2450
+ if (character === '"' || character === "`" || character === "'" || character === "[") {
2451
+ const close = character === "[" ? "]" : character;
2452
+ let value = "";
2453
+ index++;
2454
+ while (index < length) {
2455
+ if (sql[index] === close) {
2456
+ if (close !== "]" && sql[index + 1] === close) {
2457
+ value += close;
2458
+ index += 2;
2459
+ continue;
2460
+ }
2461
+ index++;
2462
+ break;
2463
+ }
2464
+ value += sql[index];
2465
+ index++;
2466
+ }
2467
+ tokens.push({ kind: character === "'" ? "string" : "quoted", value });
2468
+ continue;
2469
+ }
2470
+ if (code >= 48 && code <= 57) {
2471
+ let end = index + 1;
2472
+ while (end < length && /[0-9A-Za-z_.+-]/.test(sql[end])) {
2473
+ end++;
2474
+ }
2475
+ tokens.push({ kind: "number", value: sql.slice(index, end) });
2476
+ index = end;
2477
+ continue;
2478
+ }
2479
+ if (isIdentifierCharCode(code)) {
2480
+ let end = index + 1;
2481
+ while (end < length && isIdentifierCharCode(sql.charCodeAt(end))) {
2482
+ end++;
2483
+ }
2484
+ tokens.push({ kind: "word", value: sql.slice(index, end) });
2485
+ index = end;
2486
+ continue;
2487
+ }
2488
+ tokens.push({ kind: "punct", value: character });
2489
+ index++;
2490
+ }
2491
+ return tokens;
2492
+ }
2493
+ function nameToken(token) {
2494
+ if (!token) {
2495
+ return void 0;
2496
+ }
2497
+ return token.kind === "word" || token.kind === "quoted" || token.kind === "string" ? token.value : void 0;
2498
+ }
2499
+ function qualifiedName(tokens, position) {
2500
+ const first = nameToken(tokens[position]);
2501
+ if (first === void 0) {
2502
+ return { next: position };
2503
+ }
2504
+ if (tokens[position + 1]?.kind === "punct" && tokens[position + 1]?.value === ".") {
2505
+ const second = nameToken(tokens[position + 2]);
2506
+ return second === void 0 ? { name: first, next: position + 1 } : { name: second, next: position + 3 };
2507
+ }
2508
+ return { name: first, next: position + 1 };
2509
+ }
2510
+ function isWord(token, word) {
2511
+ return token?.kind === "word" && toAsciiUpperCase(token.value) === word;
2512
+ }
2513
+ function describeStatement(sql) {
2514
+ const tokens = leadingTokens(sql, 12);
2515
+ const first = tokens[0];
2516
+ if (!first || first.kind !== "word") {
2517
+ return { verb: "" };
2518
+ }
2519
+ const verb = toAsciiUpperCase(first.value);
2520
+ switch (verb) {
2521
+ case "BEGIN":
2522
+ return { verb, transactionControl: "begin" };
2523
+ case "COMMIT":
2524
+ case "END":
2525
+ return { verb, transactionControl: "commit" };
2526
+ case "ROLLBACK": {
2527
+ const toPosition = isWord(tokens[1], "TRANSACTION") ? 2 : 1;
2528
+ return isWord(tokens[toPosition], "TO") ? { verb, transactionControl: "rollback-to-savepoint" } : { verb, transactionControl: "rollback" };
2529
+ }
2530
+ case "SAVEPOINT":
2531
+ return { verb, transactionControl: "savepoint" };
2532
+ case "RELEASE":
2533
+ return { verb, transactionControl: "release" };
2534
+ case "PRAGMA": {
2535
+ const { name, next } = qualifiedName(tokens, 1);
2536
+ if (name === void 0) {
2537
+ return { verb };
2538
+ }
2539
+ const pragmaName = toAsciiLowerCase(name);
2540
+ const operator = tokens[next];
2541
+ if (operator?.kind === "punct" && (operator.value === "=" || operator.value === "(")) {
2542
+ const valueToken = tokens[next + 1];
2543
+ let value = valueToken?.value;
2544
+ if (valueToken?.kind === "punct" && (valueToken.value === "-" || valueToken.value === "+")) {
2545
+ value = `${valueToken.value}${tokens[next + 2]?.value ?? ""}`;
2546
+ }
2547
+ return value === void 0 ? { verb, pragmaName } : { verb, pragmaName, pragmaValue: value };
2548
+ }
2549
+ return { verb, pragmaName };
2550
+ }
2551
+ case "INSERT":
2552
+ case "REPLACE": {
2553
+ let position = 1;
2554
+ if (verb === "INSERT" && isWord(tokens[1], "OR")) {
2555
+ position = 3;
2556
+ }
2557
+ if (isWord(tokens[position], "INTO")) {
2558
+ position++;
2559
+ }
2560
+ const { name } = qualifiedName(tokens, position);
2561
+ return name === void 0 ? { verb } : { verb, objectName: name };
2562
+ }
2563
+ case "DELETE": {
2564
+ const position = isWord(tokens[1], "FROM") ? 2 : 1;
2565
+ const { name } = qualifiedName(tokens, position);
2566
+ return name === void 0 ? { verb } : { verb, objectName: name };
2567
+ }
2568
+ case "UPDATE":
2569
+ case "ANALYZE":
2570
+ case "DROP": {
2571
+ let position = 1;
2572
+ let objectKind;
2573
+ if (verb === "DROP" && tokens[1]?.kind === "word") {
2574
+ objectKind = toAsciiUpperCase(tokens[1].value);
2575
+ position = 2;
2576
+ if (isWord(tokens[2], "IF") && isWord(tokens[3], "EXISTS")) {
2577
+ position = 4;
2578
+ }
2579
+ }
2580
+ const { name } = qualifiedName(tokens, position);
2581
+ return {
2582
+ verb,
2583
+ ...objectKind === void 0 ? {} : { objectKind },
2584
+ ...name === void 0 ? {} : { objectName: name }
2585
+ };
2586
+ }
2587
+ case "CREATE": {
2588
+ let position = 1;
2589
+ while (isWord(tokens[position], "TEMP") || isWord(tokens[position], "TEMPORARY") || isWord(tokens[position], "UNIQUE")) {
2590
+ position++;
2591
+ }
2592
+ let objectKind = tokens[position]?.kind === "word" ? toAsciiUpperCase(tokens[position].value) : "";
2593
+ position++;
2594
+ if (objectKind === "VIRTUAL" && isWord(tokens[position], "TABLE")) {
2595
+ objectKind = "VIRTUAL TABLE";
2596
+ position++;
2597
+ }
2598
+ if (isWord(tokens[position], "IF") && isWord(tokens[position + 1], "NOT")) {
2599
+ position += 3;
2600
+ }
2601
+ const { name } = qualifiedName(tokens, position);
2602
+ return {
2603
+ verb,
2604
+ ...objectKind === "" ? {} : { objectKind },
2605
+ ...name === void 0 ? {} : { objectName: name }
2606
+ };
2607
+ }
2608
+ default:
2609
+ return { verb };
2610
+ }
2611
+ }
2612
+
2613
+ // src/restore/textEncoding.ts
2614
+ var import_node_buffer2 = require("buffer");
2615
+ function decodeStatementBytes(statement, startLine) {
2616
+ const bytes = Buffer.from(statement, "latin1");
2617
+ if ((0, import_node_buffer2.isUtf8)(bytes)) {
2618
+ return { sql: bytes.toString("utf8"), literalsRewritten: 0 };
2619
+ }
2620
+ let output = "";
2621
+ let literalsRewritten = 0;
2622
+ let line = startLine;
2623
+ let index = 0;
2624
+ const length = statement.length;
2625
+ const appendPlain = (segment) => {
2626
+ const segmentBytes = Buffer.from(segment, "latin1");
2627
+ if (!(0, import_node_buffer2.isUtf8)(segmentBytes)) {
2628
+ throw new InvalidTextEncodingError(
2629
+ "The statement contains bytes that are not valid UTF-8 outside any string literal, so it cannot be executed as text without corrupting them",
2630
+ line
2631
+ );
2632
+ }
2633
+ output += segmentBytes.toString("utf8");
2634
+ };
2635
+ let plainStart = 0;
2636
+ while (index < length) {
2637
+ const character = statement[index];
2638
+ if (character === "\n") {
2639
+ line++;
2640
+ index++;
2641
+ continue;
2642
+ }
2643
+ if (character === "'") {
2644
+ appendPlain(statement.slice(plainStart, index));
2645
+ let end = index + 1;
2646
+ for (; ; ) {
2647
+ const close = statement.indexOf("'", end);
2648
+ if (close === -1) {
2649
+ end = length;
2650
+ break;
2651
+ }
2652
+ if (statement[close + 1] === "'") {
2653
+ end = close + 2;
2654
+ continue;
2655
+ }
2656
+ end = close + 1;
2657
+ break;
2658
+ }
2659
+ const literal = statement.slice(index, end);
2660
+ const literalBytes = Buffer.from(literal, "latin1");
2661
+ if ((0, import_node_buffer2.isUtf8)(literalBytes)) {
2662
+ output += literalBytes.toString("utf8");
2663
+ } else {
2664
+ const value = literal.slice(1, literal.endsWith("'") ? -1 : void 0).replace(/''/g, "'");
2665
+ output += `(CAST(X'${Buffer.from(value, "latin1").toString("hex")}' AS TEXT))`;
2666
+ literalsRewritten++;
2667
+ }
2668
+ for (let scan = index; scan < end; scan++) {
2669
+ if (statement[scan] === "\n") line++;
2670
+ }
2671
+ index = end;
2672
+ plainStart = end;
2673
+ continue;
2674
+ }
2675
+ if (character === '"' || character === "`" || character === "[") {
2676
+ const close = character === "[" ? "]" : character;
2677
+ let end = statement.indexOf(close, index + 1);
2678
+ end = end === -1 ? length : end + 1;
2679
+ index = end;
2680
+ continue;
2681
+ }
2682
+ if (character === "-" && statement[index + 1] === "-") {
2683
+ appendPlain(statement.slice(plainStart, index));
2684
+ const end = statement.indexOf("\n", index);
2685
+ const commentEnd = end === -1 ? length : end;
2686
+ const comment = statement.slice(index, commentEnd);
2687
+ output += (0, import_node_buffer2.isUtf8)(Buffer.from(comment, "latin1")) ? Buffer.from(comment, "latin1").toString("utf8") : "--";
2688
+ index = commentEnd;
2689
+ plainStart = commentEnd;
2690
+ continue;
2691
+ }
2692
+ if (character === "/" && statement[index + 1] === "*") {
2693
+ appendPlain(statement.slice(plainStart, index));
2694
+ const end = statement.indexOf("*/", index + 2);
2695
+ const commentEnd = end === -1 ? length : end + 2;
2696
+ const comment = statement.slice(index, commentEnd);
2697
+ const commentBytes = Buffer.from(comment, "latin1");
2698
+ output += (0, import_node_buffer2.isUtf8)(commentBytes) ? commentBytes.toString("utf8") : " ";
2699
+ for (let scan = index; scan < commentEnd; scan++) {
2700
+ if (statement[scan] === "\n") line++;
2701
+ }
2702
+ index = commentEnd;
2703
+ plainStart = commentEnd;
2704
+ continue;
2705
+ }
2706
+ index++;
2707
+ }
2708
+ appendPlain(statement.slice(plainStart));
2709
+ return { sql: output, literalsRewritten };
2710
+ }
2711
+
2712
+ // src/restore/statementParser.ts
2713
+ var DEFAULT_MAX_STATEMENT_BYTES2 = 256 * 1024 * 1024;
2714
+ var MAX_TERMINATOR_LINE_BYTES = 64 * 1024;
2715
+ var MAX_DOT_COMMAND_BYTES = 64 * 1024;
2716
+ var PRESENTATIONAL_DOT_COMMANDS = /* @__PURE__ */ new Set([
2717
+ "bail",
2718
+ "binary",
2719
+ "changes",
2720
+ "databases",
2721
+ "dbinfo",
2722
+ "echo",
2723
+ "eqp",
2724
+ "explain",
2725
+ "fullschema",
2726
+ "headers",
2727
+ "header",
2728
+ "help",
2729
+ "indexes",
2730
+ "indices",
2731
+ "log",
2732
+ "mode",
2733
+ "nullvalue",
2734
+ "once",
2735
+ "output",
2736
+ "print",
2737
+ "progress",
2738
+ "prompt",
2739
+ "scanstats",
2740
+ "schema",
2741
+ "separator",
2742
+ "show",
2743
+ "stats",
2744
+ "tables",
2745
+ "timeout",
2746
+ "timer",
2747
+ "trace",
2748
+ "width"
2749
+ ]);
2750
+ var EXIT_DOT_COMMANDS = /* @__PURE__ */ new Set(["exit", "quit"]);
2751
+ var OPEN_CONSTRUCT_NAME = {
2752
+ singleQuote: "string literal ('...')",
2753
+ doubleQuote: 'double-quoted identifier ("...")',
2754
+ backtick: "backtick-quoted identifier (`...`)",
2755
+ bracket: "bracket-quoted identifier ([...])"
2756
+ };
2757
+ var CLOSING_CHARACTER = {
2758
+ singleQuote: "'",
2759
+ doubleQuote: '"',
2760
+ backtick: "`",
2761
+ bracket: "]"
2762
+ };
2763
+ function isCompleteWhitespace2(character) {
2764
+ return character === " " || character === "\n" || character === " " || character === "\r" || character === "\f";
2765
+ }
2766
+ function isCSpace(character) {
2767
+ return isCompleteWhitespace2(character) || character === "\v";
2768
+ }
2769
+ function isPlainWhiteLine(text) {
2770
+ let index = 0;
2771
+ while (index < text.length) {
2772
+ const character = text[index];
2773
+ if (isCSpace(character)) {
2774
+ index++;
2775
+ continue;
2776
+ }
2777
+ if (character === "-" && text[index + 1] === "-") {
2778
+ return true;
2779
+ }
2780
+ if (character === "/" && text[index + 1] === "*") {
2781
+ const end = text.indexOf("*/", index + 2);
2782
+ if (end === -1) {
2783
+ return false;
2784
+ }
2785
+ index = end + 2;
2786
+ continue;
2787
+ }
2788
+ return false;
2789
+ }
2790
+ return true;
2791
+ }
2792
+ function isTerminatorLine(line) {
2793
+ let index = 0;
2794
+ while (index < line.length && isCSpace(line[index])) {
2795
+ index++;
2796
+ }
2797
+ if (line[index] === "/") {
2798
+ return isPlainWhiteLine(line.slice(index + 1));
2799
+ }
2800
+ if ((line[index] ?? "").toLowerCase() === "g" && (line[index + 1] ?? "").toLowerCase() === "o") {
2801
+ return isPlainWhiteLine(line.slice(index + 2));
2802
+ }
2803
+ return false;
2804
+ }
2805
+ function couldBeTerminatorLine(partial) {
2806
+ let index = 0;
2807
+ while (index < partial.length && isCSpace(partial[index])) {
2808
+ index++;
2809
+ }
2810
+ if (index >= partial.length) {
2811
+ return true;
2812
+ }
2813
+ const first = partial[index].toLowerCase();
2814
+ if (first === "/") {
2815
+ return true;
2816
+ }
2817
+ return first === "g" && (index + 1 >= partial.length || partial[index + 1].toLowerCase() === "o");
2818
+ }
2819
+ var SqlStatementParser = class {
2820
+ maxStatementBytes;
2821
+ dotCommandPolicy;
2822
+ lex = "normal";
2823
+ completeState = 0;
2824
+ /** Length and (lower-cased, capped) prefix of the identifier being scanned. */
2825
+ wordLength = 0;
2826
+ wordPrefix = "";
2827
+ /** In a block comment: whether the previous byte was `*`. */
2828
+ blockStar = false;
2829
+ openLine = 1;
2830
+ carry = "";
2831
+ parts = [];
2832
+ partsBytes = 0;
2833
+ /** True once the pending statement has content other than whitespace and comments. */
2834
+ hasContent = false;
2835
+ statementStartLine = 1;
2836
+ line = 1;
2837
+ atLineStart = true;
2838
+ firstChunk = true;
2839
+ dotText = "";
2840
+ dotLine = 1;
2841
+ nextStatementIndex = 0;
2842
+ finished = false;
2843
+ bytesConsumedTotal = 0;
2844
+ lastObject;
2845
+ skipped = [];
2846
+ constructor(options) {
2847
+ this.maxStatementBytes = options?.maxStatementBytes ?? DEFAULT_MAX_STATEMENT_BYTES2;
2848
+ this.dotCommandPolicy = options?.dotCommands ?? "skip-presentational";
2849
+ }
2850
+ /** Bytes of source consumed so far. */
2851
+ get bytesConsumed() {
2852
+ return this.bytesConsumedTotal;
2853
+ }
2854
+ /** Dot-commands skipped so far under the `'skip-presentational'` policy. */
2855
+ get skippedDotCommands() {
2856
+ return this.skipped;
2857
+ }
2858
+ /** `true` once a `.quit`/`.exit` command ended the input. */
2859
+ get stopped() {
2860
+ return this.lex === "stopped";
2861
+ }
2862
+ /**
2863
+ * Feeds one chunk of the source, as a **byte string** — one code unit per
2864
+ * byte, as produced by `buffer.toString('latin1')`. Callers holding text
2865
+ * should use {@link parseSqlStatements} or {@link streamSqlStatements},
2866
+ * which convert for them.
2867
+ */
2868
+ push(chunk) {
2869
+ if (this.finished) {
2870
+ throw new Error("SqlStatementParser.push() called after finish()");
2871
+ }
2872
+ this.bytesConsumedTotal += chunk.length;
2873
+ if (chunk.length === 0) {
2874
+ return [];
2875
+ }
2876
+ return this.scan(this.carry + chunk, false);
2877
+ }
2878
+ finish() {
2879
+ if (this.finished) {
2880
+ throw new Error("SqlStatementParser.finish() called more than once");
2881
+ }
2882
+ this.finished = true;
2883
+ const out = this.scan(this.carry, true);
2884
+ this.carry = "";
2885
+ const open = OPEN_CONSTRUCT_NAME[this.lex];
2886
+ if (open !== void 0) {
2887
+ throw new MalformedSqlDumpError(open, this.openLine);
2888
+ }
2889
+ if (this.lex === "dotCommand") {
2890
+ this.handleDotCommand();
2891
+ }
2892
+ if (this.lex !== "stopped") {
2893
+ this.endWord();
2894
+ const statement = this.emit();
2895
+ if (statement) {
2896
+ out.push(statement);
2897
+ }
2898
+ }
2899
+ return out;
2900
+ }
2901
+ scan(text, final) {
2902
+ const out = [];
2903
+ const length = text.length;
2904
+ let index = 0;
2905
+ let keepFrom = this.hasContent && this.lex !== "stopped" ? 0 : -1;
2906
+ const flush = (end) => {
2907
+ if (keepFrom >= 0 && end > keepFrom) {
2908
+ const part = text.slice(keepFrom, end);
2909
+ this.parts.push(part);
2910
+ this.partsBytes += part.length;
2911
+ if (this.partsBytes > this.maxStatementBytes) {
2912
+ throw new StatementTooLargeError(this.maxStatementBytes, this.statementStartLine);
2913
+ }
2914
+ }
2915
+ keepFrom = -1;
2916
+ };
2917
+ const markContent = (at) => {
2918
+ if (!this.hasContent) {
2919
+ this.hasContent = true;
2920
+ this.statementStartLine = this.line;
2921
+ keepFrom = at;
2922
+ } else if (keepFrom < 0) {
2923
+ keepFrom = at;
2924
+ }
2925
+ };
2926
+ const resume = (at) => {
2927
+ if (this.hasContent && keepFrom < 0) {
2928
+ keepFrom = at;
2929
+ }
2930
+ };
2931
+ const carryFrom = (at) => {
2932
+ flush(at);
2933
+ this.carry = text.slice(at);
2934
+ };
2935
+ if (this.firstChunk && length > 0) {
2936
+ if (text.startsWith("\xEF\xBB\xBF")) {
2937
+ index = 3;
2938
+ this.firstChunk = false;
2939
+ } else if (!final && "\xEF\xBB\xBF".startsWith(text)) {
2940
+ this.carry = text;
2941
+ return out;
2942
+ } else {
2943
+ this.firstChunk = false;
2944
+ }
2945
+ }
2946
+ while (index < length) {
2947
+ const character = text[index];
2948
+ if (character === "\r" && this.lex !== "stopped") {
2949
+ if (index + 1 >= length && !final) {
2950
+ carryFrom(index);
2951
+ return out;
2952
+ }
2953
+ if (text[index + 1] === "\n") {
2954
+ flush(index);
2955
+ index++;
2956
+ resume(index);
2957
+ continue;
2958
+ }
2959
+ }
2960
+ switch (this.lex) {
2961
+ case "stopped":
2962
+ index = length;
2963
+ continue;
2964
+ case "hashComment":
2965
+ case "dotCommand": {
2966
+ const newline = text.indexOf("\n", index);
2967
+ const end = newline === -1 ? length : newline;
2968
+ if (this.lex === "dotCommand" && this.dotText.length < MAX_DOT_COMMAND_BYTES) {
2969
+ this.dotText += text.slice(index, end);
2970
+ }
2971
+ if (newline === -1) {
2972
+ index = length;
2973
+ continue;
2974
+ }
2975
+ if (this.lex === "dotCommand") {
2976
+ this.handleDotCommand();
2977
+ if (this.stopped) {
2978
+ index = length;
2979
+ continue;
2980
+ }
2981
+ }
2982
+ this.lex = "normal";
2983
+ index = newline;
2984
+ continue;
2985
+ }
2986
+ case "singleQuote":
2987
+ case "doubleQuote":
2988
+ case "backtick":
2989
+ case "bracket": {
2990
+ const close = CLOSING_CHARACTER[this.lex];
2991
+ if (character === close) {
2992
+ this.lex = "normal";
2993
+ this.atLineStart = false;
2994
+ index++;
2995
+ continue;
2996
+ }
2997
+ if (character === "\r") {
2998
+ index++;
2999
+ continue;
3000
+ }
3001
+ let end = text.indexOf(close, index);
3002
+ if (end === -1) end = length;
3003
+ const crAt = text.indexOf("\r", index);
3004
+ if (crAt !== -1 && crAt < end) end = crAt;
3005
+ this.countNewlines(text, index, end);
3006
+ index = end;
3007
+ continue;
3008
+ }
3009
+ case "blockComment": {
3010
+ if (this.blockStar && character === "/") {
3011
+ this.blockStar = false;
3012
+ this.lex = "normal";
3013
+ this.completeState = completeTransition(this.completeState, CompleteToken.Whitespace);
3014
+ this.atLineStart = false;
3015
+ index++;
3016
+ continue;
3017
+ }
3018
+ const starAt = text.indexOf("*", index);
3019
+ const crAt = text.indexOf("\r", index);
3020
+ let end = starAt === -1 ? length : starAt;
3021
+ if (crAt !== -1 && crAt < end) {
3022
+ end = crAt;
3023
+ }
3024
+ if (end > index) {
3025
+ this.countNewlines(text, index, end);
3026
+ this.blockStar = false;
3027
+ index = end;
3028
+ continue;
3029
+ }
3030
+ if (character === "*") {
3031
+ this.blockStar = true;
3032
+ this.atLineStart = false;
3033
+ if (index + 1 >= length && !final) {
3034
+ index++;
3035
+ continue;
3036
+ }
3037
+ index++;
3038
+ continue;
3039
+ }
3040
+ this.blockStar = false;
3041
+ index++;
3042
+ continue;
3043
+ }
3044
+ case "lineComment": {
3045
+ if (character === "\n") {
3046
+ this.lex = "normal";
3047
+ continue;
3048
+ }
3049
+ if (character === "\r") {
3050
+ index++;
3051
+ continue;
3052
+ }
3053
+ let end = text.indexOf("\n", index);
3054
+ if (end === -1) end = length;
3055
+ const crAt = text.indexOf("\r", index);
3056
+ if (crAt !== -1 && crAt < end) end = crAt;
3057
+ index = end;
3058
+ continue;
3059
+ }
3060
+ case "normal":
3061
+ break;
3062
+ }
3063
+ const code = text.charCodeAt(index);
3064
+ if (this.wordLength > 0) {
3065
+ if (isIdentifierCharCode(code)) {
3066
+ const start = index;
3067
+ while (index < length && isIdentifierCharCode(text.charCodeAt(index))) {
3068
+ index++;
3069
+ }
3070
+ this.extendWord(text.slice(start, index));
3071
+ continue;
3072
+ }
3073
+ this.endWord();
3074
+ }
3075
+ if (this.atLineStart) {
3076
+ this.atLineStart = false;
3077
+ if (!this.hasContent && (character === "." || character === "#")) {
3078
+ this.lex = character === "." ? "dotCommand" : "hashComment";
3079
+ this.dotText = "";
3080
+ this.dotLine = this.line;
3081
+ index++;
3082
+ continue;
3083
+ }
3084
+ if (this.completeState !== 5 && this.completeState !== 6 && this.mayStartTerminatorLine(text, index, final)) {
3085
+ const newline = text.indexOf("\n", index);
3086
+ const lineEnd = newline === -1 ? length : newline;
3087
+ const lineText = text.slice(index, lineEnd);
3088
+ if (newline === -1 && !final) {
3089
+ if (lineText.length < MAX_TERMINATOR_LINE_BYTES && couldBeTerminatorLine(lineText)) {
3090
+ this.atLineStart = true;
3091
+ carryFrom(index);
3092
+ return out;
3093
+ }
3094
+ } else if (isTerminatorLine(lineText)) {
3095
+ flush(index);
3096
+ const statement = this.completeWithSemicolon();
3097
+ if (statement) {
3098
+ out.push(statement);
3099
+ }
3100
+ index = lineEnd;
3101
+ continue;
3102
+ }
3103
+ }
3104
+ }
3105
+ if (character === ";") {
3106
+ const next = completeTransition(this.completeState, CompleteToken.Semi);
3107
+ if (next === 1) {
3108
+ flush(index);
3109
+ this.completeState = next;
3110
+ const statement = this.emit();
3111
+ if (statement) {
3112
+ out.push(statement);
3113
+ }
3114
+ index++;
3115
+ continue;
3116
+ }
3117
+ this.completeState = next;
3118
+ markContent(index);
3119
+ index++;
3120
+ continue;
3121
+ }
3122
+ if (isCompleteWhitespace2(character)) {
3123
+ this.completeState = completeTransition(this.completeState, CompleteToken.Whitespace);
3124
+ if (character === "\n") {
3125
+ this.line++;
3126
+ this.atLineStart = true;
3127
+ }
3128
+ index++;
3129
+ continue;
3130
+ }
3131
+ if (character === "-" || character === "/") {
3132
+ if (index + 1 >= length && !final) {
3133
+ carryFrom(index);
3134
+ return out;
3135
+ }
3136
+ const next = text[index + 1];
3137
+ if (character === "-" && next === "-" || character === "/" && next === "*") {
3138
+ this.lex = character === "-" ? "lineComment" : "blockComment";
3139
+ this.blockStar = false;
3140
+ if (character === "-") {
3141
+ this.completeState = completeTransition(this.completeState, CompleteToken.Whitespace);
3142
+ }
3143
+ index += 2;
3144
+ continue;
3145
+ }
3146
+ this.completeState = completeTransition(this.completeState, CompleteToken.Other);
3147
+ markContent(index);
3148
+ index++;
3149
+ continue;
3150
+ }
3151
+ if (character === "'" || character === '"' || character === "`" || character === "[") {
3152
+ this.lex = character === "'" ? "singleQuote" : character === '"' ? "doubleQuote" : character === "`" ? "backtick" : "bracket";
3153
+ this.openLine = this.line;
3154
+ this.completeState = completeTransition(this.completeState, CompleteToken.Other);
3155
+ markContent(index);
3156
+ index++;
3157
+ continue;
3158
+ }
3159
+ if (code === 239) {
3160
+ if (index + 2 >= length && !final) {
3161
+ carryFrom(index);
3162
+ return out;
3163
+ }
3164
+ if (text.charCodeAt(index + 1) === 187 && text.charCodeAt(index + 2) === 191) {
3165
+ flush(index);
3166
+ index += 3;
3167
+ resume(index);
3168
+ continue;
3169
+ }
3170
+ }
3171
+ if (isIdentifierCharCode(code)) {
3172
+ markContent(index);
3173
+ const start = index;
3174
+ while (index < length && isIdentifierCharCode(text.charCodeAt(index))) {
3175
+ index++;
3176
+ }
3177
+ this.extendWord(text.slice(start, index));
3178
+ continue;
3179
+ }
3180
+ this.completeState = completeTransition(this.completeState, CompleteToken.Other);
3181
+ markContent(index);
3182
+ index++;
3183
+ }
3184
+ flush(length);
3185
+ this.carry = "";
3186
+ return out;
3187
+ }
3188
+ /**
3189
+ * Cheap pre-check before the terminator-line lookahead: only a line whose
3190
+ * first non-blank character is `/` or `g` can be one. Keeps the lookahead —
3191
+ * which has to look at the whole line — off the ordinary `INSERT` lines
3192
+ * that make up almost all of a dump.
3193
+ */
3194
+ mayStartTerminatorLine(text, index, final) {
3195
+ let probe = index;
3196
+ while (probe < text.length && text[probe] !== "\n" && isCSpace(text[probe])) {
3197
+ probe++;
3198
+ }
3199
+ if (probe >= text.length) {
3200
+ return !final;
3201
+ }
3202
+ const first = text[probe];
3203
+ return first === "/" || first === "g" || first === "G";
3204
+ }
3205
+ countNewlines(text, start, end) {
3206
+ let position = text.indexOf("\n", start);
3207
+ while (position !== -1 && position < end) {
3208
+ this.line++;
3209
+ position = text.indexOf("\n", position + 1);
3210
+ }
3211
+ if (end > start) {
3212
+ this.atLineStart = text[end - 1] === "\n";
3213
+ }
3214
+ }
3215
+ extendWord(segment) {
3216
+ if (this.wordPrefix.length < 10) {
3217
+ this.wordPrefix += segment.slice(0, 10 - this.wordPrefix.length);
3218
+ }
3219
+ this.wordLength += segment.length;
3220
+ }
3221
+ endWord() {
3222
+ if (this.wordLength === 0) {
3223
+ return;
3224
+ }
3225
+ const token = this.wordLength > 9 ? CompleteToken.Other : classifyWord(this.wordPrefix);
3226
+ this.completeState = completeTransition(this.completeState, token);
3227
+ this.wordLength = 0;
3228
+ this.wordPrefix = "";
3229
+ }
3230
+ /** A terminator line: behave as if the line were `;`. */
3231
+ completeWithSemicolon() {
3232
+ this.completeState = completeTransition(this.completeState, CompleteToken.Semi);
3233
+ return this.emit();
3234
+ }
3235
+ emit() {
3236
+ const hadContent = this.hasContent;
3237
+ const byteText = this.parts.join("");
3238
+ this.parts = [];
3239
+ this.partsBytes = 0;
3240
+ this.hasContent = false;
3241
+ if (!hadContent) {
3242
+ return null;
3243
+ }
3244
+ const trimmed = byteText.replace(/[ \t\n\r\f\v]+$/, "");
3245
+ if (trimmed === "") {
3246
+ return null;
3247
+ }
3248
+ const { sql, literalsRewritten } = decodeStatementBytes(trimmed, this.statementStartLine);
3249
+ const info = describeStatement(sql);
3250
+ if (info.objectName !== void 0) {
3251
+ this.lastObject = info.objectName;
3252
+ }
3253
+ return {
3254
+ statementIndex: this.nextStatementIndex++,
3255
+ sql,
3256
+ location: { startLine: this.statementStartLine, endLine: this.line },
3257
+ info,
3258
+ ...this.lastObject === void 0 ? {} : { currentObject: this.lastObject },
3259
+ bytesConsumed: this.bytesConsumedTotal,
3260
+ textLiteralsRewritten: literalsRewritten
3261
+ };
3262
+ }
3263
+ handleDotCommand() {
3264
+ const text = this.dotText;
3265
+ this.dotText = "";
3266
+ this.lex = "normal";
3267
+ const command = (/^\S*/.exec(text)?.[0] ?? "").toLowerCase();
3268
+ if (EXIT_DOT_COMMANDS.has(command)) {
3269
+ this.lex = "stopped";
3270
+ return;
3271
+ }
3272
+ if (this.dotCommandPolicy === "skip-presentational" && PRESENTATIONAL_DOT_COMMANDS.has(command)) {
3273
+ this.skipped.push({ command, line: this.dotLine });
3274
+ return;
3275
+ }
3276
+ throw new UnsupportedClientCommandError(command, this.dotLine);
3277
+ }
3278
+ };
3279
+ function parseSqlStatements(sql, options) {
3280
+ const parser = new SqlStatementParser(options);
3281
+ const byteString = (typeof sql === "string" ? Buffer.from(sql, "utf8") : sql).toString("latin1");
3282
+ return [...parser.push(byteString), ...parser.finish()];
3283
+ }
3284
+ async function* toByteStringChunks(source) {
3285
+ if (typeof source === "string") {
3286
+ yield Buffer.from(source, "utf8").toString("latin1");
3287
+ return;
3288
+ }
3289
+ if (source instanceof Uint8Array) {
3290
+ yield (Buffer.isBuffer(source) ? source : Buffer.from(source)).toString("latin1");
3291
+ return;
3292
+ }
3293
+ for await (const chunk of source) {
3294
+ if (typeof chunk === "string") {
3295
+ yield Buffer.from(chunk, "utf8").toString("latin1");
3296
+ } else {
3297
+ yield (Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)).toString("latin1");
3298
+ }
3299
+ }
3300
+ }
3301
+ async function* streamSqlStatements(source, options, signal) {
3302
+ const parser = new SqlStatementParser(options);
3303
+ yield* streamWithParser(parser, source, signal);
3304
+ }
3305
+ async function* streamWithParser(parser, source, signal) {
3306
+ for await (const chunk of toByteStringChunks(source)) {
3307
+ throwIfAborted2(signal);
3308
+ for (const statement of parser.push(chunk)) {
3309
+ yield statement;
3310
+ }
3311
+ if (parser.stopped) {
3312
+ break;
3313
+ }
3314
+ }
3315
+ throwIfAborted2(signal);
3316
+ for (const statement of parser.finish()) {
3317
+ yield statement;
3318
+ }
3319
+ }
3320
+
3321
+ // src/restore/sessionState.ts
3322
+ var TRUTHY_PRAGMA_VALUES = /* @__PURE__ */ new Set(["1", "on", "true", "yes"]);
3323
+ function isTruthyPragmaValue(value) {
3324
+ return value !== void 0 && TRUTHY_PRAGMA_VALUES.has(value.trim().toLowerCase());
3325
+ }
3326
+ var RestoreSessionState = class {
3327
+ initialForeignKeys;
3328
+ foreignKeysChanged = false;
3329
+ writableSchemaOn = false;
3330
+ schemaRowsWritten = false;
3331
+ /** Tracked when the adapter cannot report `isInTransaction()`. */
3332
+ trackedTransaction = false;
3333
+ callerTransaction = false;
3334
+ /** Records the state to restore to. Call once, before the first statement. */
3335
+ async begin(connection, signal) {
3336
+ this.callerTransaction = connection.isInTransaction?.() ?? false;
3337
+ try {
3338
+ const result = await connection.query({ sql: "PRAGMA foreign_keys" }, signal);
3339
+ const first = result.rows[0];
3340
+ if (first !== void 0) {
3341
+ this.initialForeignKeys = toNumber(Object.values(first)[0]) !== 0;
3342
+ }
3343
+ } catch (error) {
3344
+ if (isAbortError(error)) throw error;
3345
+ }
3346
+ }
3347
+ /** Whether the handle was already inside a transaction the caller opened. */
3348
+ get joinedCallerTransaction() {
3349
+ return this.callerTransaction;
3350
+ }
3351
+ /** Whether any statement wrote virtual-table rows into the schema table. */
3352
+ get wroteSchemaRows() {
3353
+ return this.schemaRowsWritten;
3354
+ }
3355
+ /** Call after every statement that executed successfully. */
3356
+ observe(info) {
3357
+ if (info.transactionControl === "begin") {
3358
+ this.trackedTransaction = true;
3359
+ } else if (info.transactionControl === "commit" || info.transactionControl === "rollback") {
3360
+ this.trackedTransaction = false;
3361
+ } else if (info.transactionControl === "savepoint" && !this.trackedTransaction) {
3362
+ this.trackedTransaction = true;
3363
+ }
3364
+ if (info.verb === "PRAGMA" && info.pragmaValue !== void 0) {
3365
+ if (info.pragmaName === "foreign_keys") {
3366
+ this.foreignKeysChanged = true;
3367
+ } else if (info.pragmaName === "writable_schema") {
3368
+ this.writableSchemaOn = isTruthyPragmaValue(info.pragmaValue);
3369
+ }
3370
+ }
3371
+ if (info.verb === "INSERT" && isSchemaTableName(info.objectName)) {
3372
+ this.schemaRowsWritten = true;
3373
+ }
3374
+ }
3375
+ /** Whether a transaction the script (not the caller) opened is still open. */
3376
+ scriptTransactionOpen(connection) {
3377
+ if (this.callerTransaction) {
3378
+ return false;
3379
+ }
3380
+ return connection.isInTransaction?.() ?? this.trackedTransaction;
3381
+ }
3382
+ /**
3383
+ * Puts back what the script changed. Runs without the caller's signal on
3384
+ * purpose: on the cancellation path that signal is already aborted, and
3385
+ * the cleanup must still happen. Returns a description of each change it
3386
+ * undid, for the `session-state-restored` warning.
3387
+ */
3388
+ async restore(connection, options) {
3389
+ const restored = [];
3390
+ let rolledBack = false;
3391
+ if (options.rollbackOpenTransaction && this.scriptTransactionOpen(connection)) {
3392
+ await executeStatement(connection, "ROLLBACK").catch(() => {
3393
+ });
3394
+ this.trackedTransaction = false;
3395
+ rolledBack = true;
3396
+ }
3397
+ if (this.writableSchemaOn) {
3398
+ await executeStatement(connection, "PRAGMA writable_schema=OFF").catch(() => {
3399
+ });
3400
+ this.writableSchemaOn = false;
3401
+ restored.push("writable_schema");
3402
+ }
3403
+ if (this.foreignKeysChanged && this.initialForeignKeys !== void 0) {
3404
+ await executeStatement(
3405
+ connection,
3406
+ `PRAGMA foreign_keys=${this.initialForeignKeys ? "ON" : "OFF"}`
3407
+ ).catch(() => {
3408
+ });
3409
+ this.foreignKeysChanged = false;
3410
+ }
3411
+ return { rolledBack, restored };
3412
+ }
3413
+ };
3414
+ function isSchemaTableName(name) {
3415
+ if (name === void 0) {
3416
+ return false;
3417
+ }
3418
+ const lower = name.toLowerCase();
3419
+ return lower === "sqlite_schema" || lower === "sqlite_master" || lower === "sqlite_temp_schema" || lower === "sqlite_temp_master";
3420
+ }
3421
+
3422
+ // src/restore/restoreSqlDump.ts
3423
+ var WRAP_SAVEPOINT = "dbgate_sqlite_restore";
3424
+ var MAX_REPORTED_FOREIGN_KEY_VIOLATIONS = 20;
3425
+ async function restoreSqlDump(request) {
3426
+ const options = request.options ?? {};
3427
+ const stopOnError = options.stopOnError ?? true;
3428
+ const restoreSessionStateOnExit = options.restoreSessionState ?? true;
3429
+ const schemaWrites = options.schemaWrites ?? "allow";
3430
+ const wrap = options.transaction === "wrap";
3431
+ const signal = request.signal;
3432
+ request.progress?.({ phase: "connecting" });
3433
+ const acquired = await acquireSqliteConnection(request.connection, signal);
3434
+ const connection = acquired.connection;
3435
+ let statementsExecuted = 0;
3436
+ let statementsFailed = 0;
3437
+ let rowsRestored = 0;
3438
+ let bytesConsumed = 0;
3439
+ const errors = [];
3440
+ const warnings = [];
3441
+ const sessionState = new RestoreSessionState();
3442
+ const parser = new SqlStatementParser(options);
3443
+ let defensiveDisabled = false;
3444
+ let wrapOpen = false;
3445
+ let skippedTransactionControl = 0;
3446
+ let textLiteralsRewritten = 0;
3447
+ const result = (cancelled) => ({
3448
+ statementsExecuted,
3449
+ statementsFailed,
3450
+ rowsRestored,
3451
+ bytesConsumed,
3452
+ errors,
3453
+ warnings,
3454
+ cancelled
3455
+ });
3456
+ const report = (phase, statement, executionState, error) => {
3457
+ request.progress?.({
3458
+ phase,
3459
+ statementsProcessed: statementsExecuted + statementsFailed,
3460
+ rowsRestored,
3461
+ bytesConsumed,
3462
+ ...statement === void 0 ? {} : {
3463
+ statementIndex: statement.statementIndex,
3464
+ ...statement.currentObject === void 0 ? {} : { currentObject: statement.currentObject }
3465
+ },
3466
+ ...executionState === void 0 ? {} : { executionState },
3467
+ ...error === void 0 ? {} : {
3468
+ error: {
3469
+ statementIndex: error.statementIndex,
3470
+ location: error.location,
3471
+ sqlPreview: error.sqlPreview,
3472
+ message: error.message
3473
+ }
3474
+ }
3475
+ });
3476
+ };
3477
+ const closeWrap = async (commit) => {
3478
+ if (!wrapOpen) {
3479
+ return;
3480
+ }
3481
+ wrapOpen = false;
3482
+ if (!commit) {
3483
+ await executeStatement(connection, `ROLLBACK TO ${WRAP_SAVEPOINT}`).catch(() => {
3484
+ });
3485
+ warnings.push({
3486
+ code: "transaction-rolled-back",
3487
+ message: 'The restore did not complete, so its transaction (transaction: "wrap") was rolled back and the database is unchanged.'
3488
+ });
3489
+ }
3490
+ await executeStatement(connection, `RELEASE ${WRAP_SAVEPOINT}`).catch(() => {
3491
+ });
3492
+ };
3493
+ const finalize = async (completed) => {
3494
+ await closeWrap(completed);
3495
+ if (restoreSessionStateOnExit) {
3496
+ const { rolledBack, restored } = await sessionState.restore(connection, {
3497
+ rollbackOpenTransaction: true
3498
+ });
3499
+ if (rolledBack) {
3500
+ warnings.push({
3501
+ code: "transaction-rolled-back",
3502
+ message: completed ? "The script opened a transaction and never committed it (a truncated dump ends this way), so it was rolled back \u2014 as the sqlite3 shell's exit would roll it back." : "The restore stopped inside the transaction the script opened, so that transaction was rolled back: nothing it had written so far was kept."
3503
+ });
3504
+ }
3505
+ if (restored.length > 0) {
3506
+ warnings.push({
3507
+ code: "session-state-restored",
3508
+ message: `The script left ${restored.join(", ")} changed when the restore ended, so it was reset before the connection was released.`
3509
+ });
3510
+ }
3511
+ }
3512
+ if (sessionState.wroteSchemaRows) {
3513
+ await executeStatement(connection, "PRAGMA writable_schema=RESET").catch(() => {
3514
+ });
3515
+ }
3516
+ if (defensiveDisabled && connection.setDefensive) {
3517
+ await connection.setDefensive(true).catch(() => {
3518
+ });
3519
+ defensiveDisabled = false;
3520
+ }
3521
+ await acquired.release();
3522
+ };
3523
+ try {
3524
+ await sessionState.begin(connection, signal);
3525
+ if (options.disableForeignKeys) {
3526
+ await executeStatement(connection, "PRAGMA foreign_keys=OFF", signal);
3527
+ sessionState.observe({ verb: "PRAGMA", pragmaName: "foreign_keys", pragmaValue: "OFF" });
3528
+ }
3529
+ if (sessionState.joinedCallerTransaction && !wrap) {
3530
+ warnings.push({
3531
+ code: "caller-transaction-open",
3532
+ message: `The connection was already inside a transaction when the restore started. A full dump's own BEGIN TRANSACTION will fail in that state; commit first, or restore with transaction: "wrap", which nests.`
3533
+ });
3534
+ }
3535
+ for await (const statement of streamWithParser(parser, request.source, signal)) {
3536
+ throwIfAborted2(signal);
3537
+ bytesConsumed = statement.bytesConsumed;
3538
+ textLiteralsRewritten += statement.textLiteralsRewritten;
3539
+ report("parsing", statement);
3540
+ const info = statement.info;
3541
+ if (wrap) {
3542
+ if (info.transactionControl === "begin" || info.transactionControl === "commit" || info.transactionControl === "rollback") {
3543
+ skippedTransactionControl++;
3544
+ continue;
3545
+ }
3546
+ if (!wrapOpen && info.verb !== "PRAGMA") {
3547
+ await executeStatement(connection, `SAVEPOINT ${WRAP_SAVEPOINT}`, signal);
3548
+ wrapOpen = true;
3549
+ }
3550
+ }
3551
+ const schemaWriteRefused = schemaWrites === "refuse" && (info.verb === "INSERT" && isSchemaTableName(info.objectName) || info.pragmaName === "writable_schema" && isTruthyPragmaValue(info.pragmaValue));
3552
+ if (!schemaWriteRefused && schemaWrites === "allow" && !defensiveDisabled && connection.setDefensive && info.pragmaName === "writable_schema" && isTruthyPragmaValue(info.pragmaValue)) {
3553
+ await connection.setDefensive(false);
3554
+ defensiveDisabled = true;
3555
+ warnings.push({
3556
+ code: "defensive-mode-disabled",
3557
+ message: "The dump recreates virtual tables by writing sqlite_schema directly (as every native .dump of such a database does), so SQLITE_DBCONFIG_DEFENSIVE was disabled for the rest of the restore and re-enabled afterwards.",
3558
+ statementIndex: statement.statementIndex
3559
+ });
3560
+ }
3561
+ report("executing", statement, "started");
3562
+ try {
3563
+ if (schemaWriteRefused) {
3564
+ throw new Error(
3565
+ 'Statement writes the schema table directly, which schemaWrites: "refuse" does not allow'
3566
+ );
3567
+ }
3568
+ const executed = await executeStatement(connection, statement.sql, signal);
3569
+ rowsRestored += executed.changes;
3570
+ statementsExecuted++;
3571
+ sessionState.observe(info);
3572
+ report("executing", statement, "finished");
3573
+ } catch (error) {
3574
+ if (isAbortError(error)) {
3575
+ throw error;
3576
+ }
3577
+ statementsFailed++;
3578
+ const statementError = toStatementError(connection, statement, error);
3579
+ errors.push(statementError);
3580
+ report("executing", statement, "failed", statementError);
3581
+ if (stopOnError) {
3582
+ collectParserWarnings(parser, warnings, textLiteralsRewritten, skippedTransactionControl);
3583
+ await finalize(false);
3584
+ return result(false);
3585
+ }
3586
+ }
3587
+ }
3588
+ report("finalizing");
3589
+ if (options.verifyForeignKeys) {
3590
+ await closeWrap(true);
3591
+ warnings.push(...await checkForeignKeys(connection, signal));
3592
+ }
3593
+ collectParserWarnings(parser, warnings, textLiteralsRewritten, skippedTransactionControl);
3594
+ await finalize(true);
3595
+ return result(false);
3596
+ } catch (error) {
3597
+ collectParserWarnings(parser, warnings, textLiteralsRewritten, skippedTransactionControl);
3598
+ await finalize(false);
3599
+ if (isAbortError(error)) {
3600
+ return result(true);
3601
+ }
3602
+ throw error;
3603
+ }
3604
+ }
3605
+ function collectParserWarnings(parser, warnings, textLiteralsRewritten, skippedTransactionControl) {
3606
+ for (const skipped of parser.skippedDotCommands) {
3607
+ warnings.push({
3608
+ code: "dot-command-skipped",
3609
+ message: `The sqlite3 shell command ".${skipped.command}" on line ${skipped.line} only affects the shell's own output, so it was skipped.`
3610
+ });
3611
+ }
3612
+ if (textLiteralsRewritten > 0) {
3613
+ warnings.push({
3614
+ code: "text-literal-rewritten",
3615
+ message: `${textLiteralsRewritten} string literal(s) held bytes that are not valid UTF-8 and were executed as CAST(X'...' AS TEXT), which stores the identical bytes.`
3616
+ });
3617
+ }
3618
+ if (skippedTransactionControl > 0) {
3619
+ warnings.push({
3620
+ code: "script-transaction-control-skipped",
3621
+ message: `${skippedTransactionControl} BEGIN/COMMIT/ROLLBACK statement(s) in the script were skipped, because transaction: "wrap" runs the whole restore in its own transaction.`
3622
+ });
3623
+ }
3624
+ }
3625
+ async function checkForeignKeys(connection, signal) {
3626
+ const found = [];
3627
+ let total = 0;
3628
+ const byTable = /* @__PURE__ */ new Map();
3629
+ for await (const row of connection.stream(
3630
+ { sql: "PRAGMA foreign_key_check" },
3631
+ signal === void 0 ? {} : { signal }
3632
+ )) {
3633
+ total++;
3634
+ const table = toText(row.table) ?? "?";
3635
+ byTable.set(table, (byTable.get(table) ?? 0) + 1);
3636
+ if (found.length < MAX_REPORTED_FOREIGN_KEY_VIOLATIONS) {
3637
+ found.push({
3638
+ code: "foreign-key-violation",
3639
+ message: `Row ${toText(row.rowid) ?? "(no rowid)"} of table "${table}" references a missing row in "${toText(row.parent) ?? "?"}" (foreign key #${toText(row.fkid) ?? "?"}).`
3640
+ });
3641
+ }
3642
+ }
3643
+ if (total > found.length) {
3644
+ found.push({
3645
+ code: "foreign-key-violation",
3646
+ message: `${total} foreign-key violations in total: ${[...byTable].map(([table, count]) => `${table} (${count})`).join(", ")}.`
3647
+ });
3648
+ }
3649
+ return found;
3650
+ }
3651
+ function toStatementError(connection, statement, error) {
3652
+ const described = connection.describeError?.(error);
3653
+ const message = redactSecrets(
3654
+ described?.message ?? (error instanceof Error ? error.message : String(error))
3655
+ );
3656
+ const sqliteError = described ? { ...described, message: redactSecrets(described.message) } : void 0;
3657
+ const executionError = new RestoreExecutionError(
3658
+ statement.statementIndex,
3659
+ statement.location,
3660
+ safeSqlPreview(statement.sql),
3661
+ message,
3662
+ sqliteError,
3663
+ { cause: error }
3664
+ );
3665
+ return {
3666
+ statementIndex: executionError.statementIndex,
3667
+ location: executionError.location,
3668
+ sqlPreview: executionError.sqlPreview,
3669
+ message: executionError.message,
3670
+ ...executionError.sqliteError === void 0 ? {} : { sqliteError: executionError.sqliteError }
3671
+ };
3672
+ }
3673
+
3674
+ // src/api/dump.ts
3675
+ async function dumpSqlite(connectionInput, options, output, onProgress, signal) {
3676
+ onProgress?.({ phase: "connecting" });
3677
+ const acquired = await acquireSqliteConnection(connectionInput, signal);
3678
+ const session = await (async () => {
3679
+ onProgress?.({ phase: "starting-snapshot" });
3680
+ try {
3681
+ return await beginSqliteDumpSession(
3682
+ acquired.connection,
3683
+ options.consistency === void 0 ? {} : { consistency: options.consistency },
3684
+ signal
3685
+ );
3686
+ } catch (error) {
3687
+ await acquired.release();
3688
+ throw error;
3689
+ }
3690
+ })();
3691
+ try {
3692
+ onProgress?.({ phase: "introspecting" });
3693
+ const introspection = await introspectSqlite(
3694
+ acquired.connection,
3695
+ options.schemaName === void 0 ? {} : { schemaName: options.schemaName },
3696
+ signal
3697
+ );
3698
+ onProgress?.({
3699
+ phase: "detecting-version",
3700
+ message: introspection.version.versionString,
3701
+ schemaName: introspection.database.schemaName
3702
+ });
3703
+ const mode = options.mode ?? "full";
3704
+ const selection = normalizeDumpSelection(options.selection);
3705
+ const archive = inspectDumpArchive(introspection.database, {
3706
+ mode,
3707
+ selection,
3708
+ ...options.objectKinds === void 0 ? {} : { objectKinds: options.objectKinds }
3709
+ });
3710
+ onProgress?.({ phase: "planning-archive", objectsTotal: archive.entries.length });
3711
+ if (!archive.valid) {
3712
+ throw new SqliteDumperError(
3713
+ "invalid-archive",
3714
+ "Archive planning failed; inspect the diagnostics, cycles and unsatisfiedDependencies returned by inspectDumpArchive for details"
3715
+ );
3716
+ }
3717
+ const writer = new StreamDumpWriter(output);
3718
+ const tablesByName = new Map(
3719
+ introspection.database.tables.map((table) => [foldSqliteName(table.name), table])
3720
+ );
3721
+ let rowsExported = 0;
3722
+ let statementsWritten = 0;
3723
+ const dataWarnings = [];
3724
+ const onTableData = async (entry) => {
3725
+ const table = tablesByName.get(foldSqliteName(entry.name));
3726
+ if (!table) {
3727
+ return false;
3728
+ }
3729
+ const result = await exportTableDataAsInserts({
3730
+ connection: acquired.connection,
3731
+ schemaName: introspection.database.schemaName,
3732
+ table,
3733
+ writer,
3734
+ encoding: introspection.database.encoding,
3735
+ ...entry.systemRowFilter === void 0 ? {} : { systemRowFilter: entry.systemRowFilter },
3736
+ ...options.dataExport === void 0 ? {} : { options: options.dataExport },
3737
+ ...signal === void 0 ? {} : { signal },
3738
+ ...onProgress === void 0 ? {} : { onProgress }
3739
+ });
3740
+ rowsExported += result.rowsExported;
3741
+ statementsWritten += result.statementsWritten;
3742
+ dataWarnings.push(...result.warnings);
3743
+ if (result.cancelled) {
3744
+ throw new DOMException("The operation was aborted.", "AbortError");
3745
+ }
3746
+ return true;
3747
+ };
3748
+ const renderResult = await renderPlainSql({
3749
+ database: introspection.database,
3750
+ archive,
3751
+ writer,
3752
+ mode,
3753
+ sourceVersion: introspection.version,
3754
+ ...options.render === void 0 ? {} : { options: options.render },
3755
+ ...signal === void 0 ? {} : { signal },
3756
+ ...onProgress === void 0 ? {} : { onProgress },
3757
+ onTableData
3758
+ });
3759
+ onProgress?.({ phase: "finalizing", bytesWritten: renderResult.bytesWritten });
3760
+ const sessionWarnings = session.joinedExistingTransaction ? [
3761
+ {
3762
+ severity: "info",
3763
+ code: "dump-joined-caller-transaction",
3764
+ message: "The connection was already inside a transaction, so the dump was read within it and includes that transaction's uncommitted changes."
3765
+ }
3766
+ ] : [];
3767
+ return {
3768
+ bytesWritten: renderResult.bytesWritten,
3769
+ renderedDumpIds: renderResult.renderedDumpIds,
3770
+ skippedDumpIds: renderResult.skippedDumpIds,
3771
+ warnings: [
3772
+ ...introspection.diagnostics,
3773
+ ...archive.diagnostics,
3774
+ ...sessionWarnings,
3775
+ ...renderResult.warnings,
3776
+ ...dedupeDiagnostics(dataWarnings)
3777
+ ],
3778
+ cancelled: renderResult.cancelled,
3779
+ rowsExported,
3780
+ statementsWritten
3781
+ };
3782
+ } finally {
3783
+ await session.finish();
3784
+ await acquired.release();
3785
+ }
3786
+ }
3787
+ function dedupeDiagnostics(diagnostics) {
3788
+ const seen = /* @__PURE__ */ new Set();
3789
+ return diagnostics.filter((diagnostic) => {
3790
+ const key = `${diagnostic.code}\0${diagnostic.message}`;
3791
+ if (seen.has(key)) {
3792
+ return false;
3793
+ }
3794
+ seen.add(key);
3795
+ return true;
3796
+ });
3797
+ }
3798
+ // Annotate the CommonJS export names for ESM import in node:
3799
+ 0 && (module.exports = {
3800
+ BufferDumpWriter,
3801
+ COMPLETE_TRANSITIONS,
3802
+ CompleteToken,
3803
+ DEFENSIVE_WARNING_COMMENT,
3804
+ InvalidTextEncodingError,
3805
+ MalformedSqlDumpError,
3806
+ OperationCancelledError,
3807
+ RestoreError,
3808
+ RestoreExecutionError,
3809
+ RestoreSessionState,
3810
+ SEQUENCE_TABLE_NAME,
3811
+ SESSION_GUARD_FOOTER,
3812
+ SESSION_GUARD_HEADER,
3813
+ SQLITE_KEYWORD_COUNT,
3814
+ SqlChunkBuilder,
3815
+ SqlParseError,
3816
+ SqlStatementParser,
3817
+ SqliteDumperError,
3818
+ StatementTooLargeError,
3819
+ StreamDumpWriter,
3820
+ UNSUPPORTED_FEATURES,
3821
+ UnsupportedClientCommandError,
3822
+ WRITABLE_SCHEMA_OFF,
3823
+ WRITABLE_SCHEMA_ON,
3824
+ acquireSqliteConnection,
3825
+ assignDumpSection,
3826
+ beginSqliteDumpSession,
3827
+ checkTargetCompatibility,
3828
+ classifyWord,
3829
+ columnValueSelect,
3830
+ completeTransition,
3831
+ createArchiveIdentity,
3832
+ createCanonicalIdentity,
3833
+ createDumpId,
3834
+ declaresAutoincrement,
3835
+ decodeStatementBytes,
3836
+ describeStatement,
3837
+ detectSqliteCapabilities,
3838
+ detectSqliteVersion,
3839
+ detectTargetCapabilities,
3840
+ dumpSectionPriority,
3841
+ dumpSqlite,
3842
+ executeStatement,
3843
+ exportTableDataAsInserts,
3844
+ foldSqliteName,
3845
+ insertableColumns,
3846
+ inspectDumpArchive,
3847
+ introspectSqlite,
3848
+ isAbortError,
3849
+ isCompleteStatement,
3850
+ isIdentifierCharCode,
3851
+ isIndexSelected,
3852
+ isSchemaTableName,
3853
+ isSqliteConnectionSource,
3854
+ isSqliteDump,
3855
+ isSqliteKeyword,
3856
+ isStatisticsTableName,
3857
+ isTableDataExcluded,
3858
+ isTableSelected,
3859
+ isTriggerSelected,
3860
+ isTruthyPragmaValue,
3861
+ isViewSelected,
3862
+ maskSqlLiterals,
3863
+ needsIdentifierQuoting,
3864
+ normalizeDumpSelection,
3865
+ parseSqlStatements,
3866
+ parseSqliteVersion,
3867
+ parseTableOptions,
3868
+ parseVirtualTableModule,
3869
+ preflightRestore,
3870
+ preservableRowidName,
3871
+ quoteIdentifier,
3872
+ quoteIdentifierIfNeeded,
3873
+ quoteQualifiedIdentifier,
3874
+ quoteStringLiteral,
3875
+ redactSecrets,
3876
+ renderBlobLiteral,
3877
+ renderColumnLiteral,
3878
+ renderDatabaseSettings,
3879
+ renderDrop,
3880
+ renderEscapedStringLiteral,
3881
+ renderPlainSql,
3882
+ renderQuotedStringLiteral,
3883
+ renderSchemaLine,
3884
+ renderSchemaObject,
3885
+ renderSystemTablePrelude,
3886
+ renderTextLiteral,
3887
+ renderVirtualTable,
3888
+ resolvePlainSqlRenderOptions,
3889
+ restoreSqlDump,
3890
+ safeSqlPreview,
3891
+ streamSqlStatements,
3892
+ streamWithParser,
3893
+ tableGroupPriority,
3894
+ throwIfAborted,
3895
+ toAsciiLowerCase,
3896
+ toAsciiUpperCase,
3897
+ toByteStringChunks,
3898
+ toNumber,
3899
+ toText,
3900
+ unsupportedFeatureDiagnostics
3901
+ });
3902
+ //# sourceMappingURL=index.cjs.map