@crvouga/mockingbird-service-postgres 3.11.0 → 3.12.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.js CHANGED
@@ -1,3 +1,1015 @@
1
+ // ../../core/dist/durability.js
2
+ function withDurability(api, durable) {
3
+ let queue = Promise.resolve();
4
+ return {
5
+ fetch(request) {
6
+ const next = queue.then(async () => {
7
+ const response = await api.fetch(request);
8
+ await durable.flush();
9
+ return response;
10
+ });
11
+ queue = next.catch(() => {
12
+ });
13
+ return next;
14
+ }
15
+ };
16
+ }
17
+ var DurabilityConflictError = class extends Error {
18
+ constructor() {
19
+ super("Durable image changed in another writer; reopen before saving");
20
+ this.name = "DurabilityConflictError";
21
+ }
22
+ };
23
+ async function openDurable(options) {
24
+ const { backend, key: key2, codec: codec3 } = options;
25
+ const pageSize = options.pageSize ?? 16384;
26
+ if (!Number.isSafeInteger(pageSize) || pageSize < 1)
27
+ throw new RangeError("Invalid page size");
28
+ const image = await backend.load(key2);
29
+ let previous = image ? new Uint8Array(image.bytes) : new Uint8Array();
30
+ const value = image ? codec3.decode(image.bytes) : codec3.create();
31
+ let revision = image?.revision ?? 0;
32
+ let storedPageSize = image?.pageSize ?? pageSize;
33
+ let queue = Promise.resolve();
34
+ let closing = false;
35
+ let closed = false;
36
+ function enqueue(run) {
37
+ if (closed || closing)
38
+ return Promise.reject(new Error("Durable handle is closed"));
39
+ const next = queue.then(run);
40
+ queue = next.catch(() => {
41
+ });
42
+ return next;
43
+ }
44
+ async function persist() {
45
+ const bytes = codec3.encode(value);
46
+ const byteLength = bytes.length;
47
+ const changedPages = [];
48
+ let changedBytes = 0;
49
+ const words = bytes.byteOffset % 4 === 0 ? new Uint32Array(bytes.buffer, bytes.byteOffset, Math.floor(byteLength / 4)) : null;
50
+ const previousWords = new Uint32Array(previous.buffer, previous.byteOffset, Math.floor(previous.length / 4));
51
+ for (let offset = 0; offset < byteLength; offset += pageSize) {
52
+ const end = Math.min(offset + pageSize, byteLength);
53
+ let changed = storedPageSize !== pageSize || Math.min(pageSize, previous.length - offset) !== end - offset;
54
+ if (!changed)
55
+ changed = !equalPage(bytes, previous, words, previousWords, offset, end);
56
+ if (changed) {
57
+ changedPages.push(offset / pageSize);
58
+ changedBytes += end - offset;
59
+ }
60
+ }
61
+ if (revision !== 0 && changedPages.length === 0 && byteLength === previous.length && storedPageSize === pageSize)
62
+ return;
63
+ const replacement = previous.length !== byteLength || changedBytes >= byteLength / 2 ? new Uint8Array(bytes) : void 0;
64
+ const pages = changedPages.map((index) => {
65
+ const offset = index * pageSize;
66
+ const end = Math.min(offset + pageSize, byteLength);
67
+ return {
68
+ index,
69
+ // Buffer.slice returns a borrowed view; the TypedArray operation owns its result.
70
+ bytes: replacement ? replacement.subarray(offset, end) : Uint8Array.prototype.slice.call(bytes, offset, end)
71
+ };
72
+ });
73
+ revision = await backend.commit(key2, revision, { byteLength, pageSize, pages });
74
+ if (replacement)
75
+ previous = replacement;
76
+ else
77
+ for (const page of pages)
78
+ previous.set(page.bytes, page.index * pageSize);
79
+ storedPageSize = pageSize;
80
+ }
81
+ return {
82
+ value,
83
+ flush: () => enqueue(persist),
84
+ write: (run) => enqueue(async () => {
85
+ const result = run(value);
86
+ if (result && typeof result.then === "function") {
87
+ throw new TypeError("Durable write callbacks must be synchronous");
88
+ }
89
+ await persist();
90
+ return result;
91
+ }),
92
+ close() {
93
+ if (closed)
94
+ return Promise.resolve();
95
+ if (closing)
96
+ return queue;
97
+ const next = enqueue(async () => {
98
+ await persist();
99
+ await codec3.close?.(value);
100
+ closed = true;
101
+ });
102
+ closing = true;
103
+ const completion = next.catch((error) => {
104
+ closing = false;
105
+ queue = Promise.resolve();
106
+ throw error;
107
+ });
108
+ queue = completion;
109
+ return completion;
110
+ }
111
+ };
112
+ }
113
+ function equalPage(left, right, leftWords, rightWords, start, end) {
114
+ let offset = start;
115
+ if (!leftWords) {
116
+ for (; offset < end; offset++)
117
+ if (left[offset] !== right[offset])
118
+ return false;
119
+ return true;
120
+ }
121
+ while (offset < end && offset % 4 !== 0) {
122
+ if (left[offset] !== right[offset])
123
+ return false;
124
+ offset++;
125
+ }
126
+ const wordEnd = Math.floor(end / 4);
127
+ let word2 = offset / 4;
128
+ for (; word2 + 4 <= wordEnd; word2 += 4) {
129
+ if (leftWords[word2] !== rightWords[word2] || leftWords[word2 + 1] !== rightWords[word2 + 1] || leftWords[word2 + 2] !== rightWords[word2 + 2] || leftWords[word2 + 3] !== rightWords[word2 + 3])
130
+ return false;
131
+ }
132
+ for (; word2 < wordEnd; word2++) {
133
+ if (leftWords[word2] !== rightWords[word2])
134
+ return false;
135
+ }
136
+ offset = word2 * 4;
137
+ while (offset < end) {
138
+ if (left[offset] !== right[offset])
139
+ return false;
140
+ offset++;
141
+ }
142
+ return true;
143
+ }
144
+ function applyDurablePatch(previous, patch) {
145
+ validateDurablePatch(patch);
146
+ const bytes = new Uint8Array(patch.byteLength);
147
+ bytes.set(previous.subarray(0, bytes.length));
148
+ for (const page of patch.pages)
149
+ bytes.set(page.bytes, page.index * patch.pageSize);
150
+ return bytes;
151
+ }
152
+ function validateDurablePatch(patch) {
153
+ if (!Number.isSafeInteger(patch.byteLength) || patch.byteLength < 0 || !Number.isSafeInteger(patch.pageSize) || patch.pageSize < 1) {
154
+ throw new RangeError("Invalid durable patch dimensions");
155
+ }
156
+ const seen = /* @__PURE__ */ new Set();
157
+ for (const page of patch.pages) {
158
+ const offset = page.index * patch.pageSize;
159
+ if (!Number.isSafeInteger(page.index) || page.index < 0 || offset >= patch.byteLength || page.bytes.length !== Math.min(patch.pageSize, patch.byteLength - offset) || seen.has(page.index)) {
160
+ throw new RangeError("Invalid durable page");
161
+ }
162
+ seen.add(page.index);
163
+ }
164
+ }
165
+ function validateDurableCommit(patch, previous) {
166
+ validateDurablePatch(patch);
167
+ const supplied = new Set(patch.pages.map((page) => page.index));
168
+ const count = Math.ceil(patch.byteLength / patch.pageSize);
169
+ let start = count;
170
+ if (!previous || previous.pageSize !== patch.pageSize)
171
+ start = 0;
172
+ else if (patch.byteLength > previous.byteLength)
173
+ start = Math.floor(previous.byteLength / patch.pageSize);
174
+ else if (patch.byteLength < previous.byteLength && patch.byteLength % patch.pageSize !== 0)
175
+ start = count - 1;
176
+ for (let index = start; index < count; index++) {
177
+ if (!supplied.has(index))
178
+ throw new RangeError("Missing durable page");
179
+ }
180
+ }
181
+ var MemoryDurabilityBackend = class {
182
+ images = /* @__PURE__ */ new Map();
183
+ async load(key2) {
184
+ const image = this.images.get(key2);
185
+ return image && { ...image, bytes: image.bytes.slice() };
186
+ }
187
+ async commit(key2, expectedRevision, patch) {
188
+ const previous = this.images.get(key2);
189
+ if ((previous?.revision ?? 0) !== expectedRevision)
190
+ throw new DurabilityConflictError();
191
+ validateDurableCommit(patch, previous && { byteLength: previous.bytes.length, pageSize: previous.pageSize });
192
+ const revision = expectedRevision + 1;
193
+ this.images.set(key2, {
194
+ revision,
195
+ pageSize: patch.pageSize,
196
+ bytes: applyDurablePatch(previous?.bytes ?? new Uint8Array(), patch)
197
+ });
198
+ return revision;
199
+ }
200
+ };
201
+
202
+ // ../../core/dist/durability-browser.js
203
+ var browserDurabilityLifecycle = {
204
+ subscribe(onSuspend) {
205
+ if (typeof globalThis.addEventListener !== "function")
206
+ return () => {
207
+ };
208
+ globalThis.addEventListener("pagehide", onSuspend);
209
+ return () => globalThis.removeEventListener("pagehide", onSuspend);
210
+ }
211
+ };
212
+ var IndexedDBDurabilityBackend = class {
213
+ database;
214
+ factory;
215
+ name;
216
+ durability;
217
+ constructor(options = {}) {
218
+ this.factory = options.indexedDB ?? globalThis.indexedDB;
219
+ if (!this.factory)
220
+ throw new Error("IndexedDB is unavailable; inject a durability backend");
221
+ this.name = options.name ?? "mockingbird";
222
+ this.durability = options.durability ?? "strict";
223
+ }
224
+ open() {
225
+ this.database ??= new Promise((resolve, reject) => {
226
+ const request = this.factory.open(this.name, 1);
227
+ request.onupgradeneeded = () => {
228
+ const db = request.result;
229
+ db.createObjectStore("images");
230
+ const pages = db.createObjectStore("pages", { keyPath: ["key", "index"] });
231
+ pages.createIndex("image", "key");
232
+ };
233
+ request.onerror = () => {
234
+ this.database = void 0;
235
+ reject(request.error);
236
+ };
237
+ request.onblocked = () => {
238
+ };
239
+ request.onsuccess = () => {
240
+ const db = request.result;
241
+ db.onversionchange = () => {
242
+ db.close();
243
+ this.database = void 0;
244
+ };
245
+ resolve(db);
246
+ };
247
+ });
248
+ return this.database;
249
+ }
250
+ async load(key2) {
251
+ const db = await this.open();
252
+ return new Promise((resolve, reject) => {
253
+ const tx = db.transaction(["images", "pages"], "readonly");
254
+ let image;
255
+ let failure;
256
+ tx.onabort = () => reject(failure ?? tx.error);
257
+ tx.oncomplete = () => resolve(image);
258
+ const meta = tx.objectStore("images").get(key2);
259
+ meta.onsuccess = () => {
260
+ const info = meta.result;
261
+ if (!info)
262
+ return;
263
+ const request = tx.objectStore("pages").index("image").getAll(key2);
264
+ request.onsuccess = () => {
265
+ try {
266
+ const bytes = new Uint8Array(info.byteLength);
267
+ const pages = request.result;
268
+ if (pages.length !== Math.ceil(info.byteLength / info.pageSize)) {
269
+ throw new Error("Incomplete durable image");
270
+ }
271
+ const patch = {
272
+ ...info,
273
+ pages: pages.map((page) => ({ index: page.index, bytes: page.bytes }))
274
+ };
275
+ validateDurablePatch(patch);
276
+ for (const page of pages)
277
+ bytes.set(page.bytes, page.index * info.pageSize);
278
+ image = { revision: info.revision, pageSize: info.pageSize, bytes };
279
+ } catch (error) {
280
+ failure = error;
281
+ tx.abort();
282
+ }
283
+ };
284
+ };
285
+ });
286
+ }
287
+ async commit(key2, expectedRevision, patch) {
288
+ validateDurablePatch(patch);
289
+ const db = await this.open();
290
+ return new Promise((resolve, reject) => {
291
+ const tx = db.transaction(["images", "pages"], "readwrite", { durability: this.durability });
292
+ let failure;
293
+ tx.onabort = () => reject(failure ?? tx.error);
294
+ tx.oncomplete = () => resolve(expectedRevision + 1);
295
+ const images = tx.objectStore("images");
296
+ const pages = tx.objectStore("pages");
297
+ const request = images.get(key2);
298
+ request.onsuccess = () => {
299
+ try {
300
+ const previous = request.result;
301
+ if ((previous?.revision ?? 0) !== expectedRevision) {
302
+ failure = new DurabilityConflictError();
303
+ tx.abort();
304
+ return;
305
+ }
306
+ validateDurableCommit(patch, previous);
307
+ const oldCount = previous ? Math.ceil(previous.byteLength / previous.pageSize) : 0;
308
+ const newCount = Math.ceil(patch.byteLength / patch.pageSize);
309
+ for (let index = newCount; index < oldCount; index++)
310
+ pages.delete([key2, index]);
311
+ for (const page of patch.pages) {
312
+ const bytes = page.bytes.byteOffset === 0 && page.bytes.byteLength === page.bytes.buffer.byteLength ? page.bytes : new Uint8Array(page.bytes);
313
+ pages.put({ key: key2, index: page.index, bytes });
314
+ }
315
+ images.put({
316
+ revision: expectedRevision + 1,
317
+ byteLength: patch.byteLength,
318
+ pageSize: patch.pageSize
319
+ }, key2);
320
+ } catch (error) {
321
+ failure = error;
322
+ tx.abort();
323
+ }
324
+ };
325
+ });
326
+ }
327
+ /** Release this adapter's connection; does not delete any saved images. */
328
+ async close() {
329
+ const opening = this.database;
330
+ this.database = void 0;
331
+ if (opening)
332
+ (await opening).close();
333
+ }
334
+ };
335
+ var LocalStorageDurabilityBackend = class {
336
+ storage;
337
+ prefix;
338
+ locks;
339
+ constructor(options = {}) {
340
+ this.storage = options.storage ?? globalThis.localStorage;
341
+ if (!this.storage)
342
+ throw new Error("localStorage is unavailable; inject a durability backend");
343
+ this.prefix = options.prefix ?? "mockingbird:";
344
+ this.locks = options.locks ?? globalThis.navigator?.locks;
345
+ }
346
+ async load(key2) {
347
+ return this.read(key2);
348
+ }
349
+ read(key2) {
350
+ const text = this.storage.getItem(this.prefix + key2);
351
+ if (text === null)
352
+ return void 0;
353
+ const image = JSON.parse(text);
354
+ const binary = atob(image.data);
355
+ const bytes = new Uint8Array(binary.length);
356
+ for (let i = 0; i < binary.length; i++)
357
+ bytes[i] = binary.charCodeAt(i);
358
+ return { revision: image.revision, pageSize: image.pageSize, bytes };
359
+ }
360
+ async commit(key2, expectedRevision, patch) {
361
+ const save = () => {
362
+ const previous = this.read(key2);
363
+ if ((previous?.revision ?? 0) !== expectedRevision)
364
+ throw new DurabilityConflictError();
365
+ validateDurableCommit(patch, previous && { byteLength: previous.bytes.length, pageSize: previous.pageSize });
366
+ const bytes = applyDurablePatch(previous?.bytes ?? new Uint8Array(), patch);
367
+ let binary = "";
368
+ for (let offset = 0; offset < bytes.length; offset += 8192) {
369
+ binary += String.fromCharCode(...bytes.subarray(offset, offset + 8192));
370
+ }
371
+ const revision = expectedRevision + 1;
372
+ this.storage.setItem(this.prefix + key2, JSON.stringify({ revision, pageSize: patch.pageSize, data: btoa(binary) }));
373
+ return revision;
374
+ };
375
+ return this.locks ? this.locks.request(this.prefix + key2, save) : save();
376
+ }
377
+ };
378
+
379
+ // ../../core/dist/durability-buffered.js
380
+ var HEADER = 32;
381
+ var MAGIC = [77, 66, 68, 74];
382
+ function isDurableJournal(bytes) {
383
+ return MAGIC.every((byte, index) => bytes[index] === byte);
384
+ }
385
+ function checksum(bytes) {
386
+ let hash = 2166136261;
387
+ for (const byte of bytes)
388
+ hash = Math.imul(hash ^ byte, 16777619);
389
+ return hash >>> 0;
390
+ }
391
+ function header(checkpointBytes, hash) {
392
+ if (checkpointBytes > 4294967295)
393
+ throw new RangeError("Buffered checkpoint exceeds 4 GiB");
394
+ const bytes = new Uint8Array(HEADER);
395
+ bytes.set(MAGIC);
396
+ const view = new DataView(bytes.buffer);
397
+ view.setUint32(4, 1, true);
398
+ view.setUint32(8, checkpointBytes, true);
399
+ view.setUint32(20, hash, true);
400
+ view.setUint32(24, checksum(bytes.subarray(0, 24)), true);
401
+ return bytes;
402
+ }
403
+ function encodeDurableCheckpoint(record) {
404
+ const bytes = new Uint8Array(HEADER + record.length);
405
+ bytes.set(header(record.length, checksum(record)));
406
+ bytes.set(record, HEADER);
407
+ return bytes;
408
+ }
409
+ function readDurableJournal(bytes) {
410
+ if (!isDurableJournal(bytes))
411
+ return void 0;
412
+ const bad2 = () => {
413
+ throw new Error("Invalid buffered durability image");
414
+ };
415
+ if (bytes.length < HEADER)
416
+ return bad2();
417
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
418
+ const checkpointBytes = view.getUint32(8, true);
419
+ if (view.getUint32(4, true) !== 1 || view.getUint32(12, true) !== 0 || view.getUint32(16, true) !== 0 || view.getUint32(24, true) !== checksum(bytes.subarray(0, 24)) || HEADER + checkpointBytes > bytes.length)
420
+ return bad2();
421
+ const checkpoint = bytes.subarray(HEADER, HEADER + checkpointBytes);
422
+ if (checksum(checkpoint) !== view.getUint32(20, true))
423
+ return bad2();
424
+ const records = [checkpoint];
425
+ let offset = HEADER + checkpointBytes;
426
+ while (offset < bytes.length) {
427
+ if (offset + 8 > bytes.length)
428
+ return bad2();
429
+ const length = view.getUint32(offset, true);
430
+ const hash = view.getUint32(offset + 4, true);
431
+ offset += 8;
432
+ if (offset + length > bytes.length)
433
+ return bad2();
434
+ const record = bytes.subarray(offset, offset + length);
435
+ if (checksum(record) !== hash)
436
+ return bad2();
437
+ records.push(record);
438
+ offset += length;
439
+ }
440
+ if (offset !== bytes.length)
441
+ return bad2();
442
+ return records;
443
+ }
444
+ var timers = {
445
+ schedule(run, delay) {
446
+ const timer = setTimeout(run, delay);
447
+ timer.unref?.();
448
+ return timer;
449
+ },
450
+ cancel(timer) {
451
+ clearTimeout(timer);
452
+ }
453
+ };
454
+ async function openBufferedDurable(options) {
455
+ const { backend, key: key2, codec: codec3 } = options;
456
+ const pageSize = options.pageSize ?? 16384;
457
+ const interval = options.flushIntervalMs ?? 1e3;
458
+ const maxBatches = options.compactAfterBatches ?? 256;
459
+ if (!Number.isSafeInteger(pageSize) || pageSize < 1 || !Number.isSafeInteger(interval) || interval < 1 || !Number.isSafeInteger(maxBatches) || maxBatches < 1 || options.compactAfterBytes !== void 0 && (!Number.isSafeInteger(options.compactAfterBytes) || options.compactAfterBytes < 1))
460
+ throw new RangeError("Invalid buffered durability options");
461
+ const scheduler = options.scheduler ?? timers;
462
+ const image = await backend.load(key2);
463
+ const records = image && readDurableJournal(image.bytes);
464
+ const value = image ? records ? codec3.decodeJournal(records) : codec3.decode(image.bytes) : codec3.create();
465
+ let revision = image?.revision ?? 0;
466
+ let length = records && image ? image.bytes.length : 0;
467
+ let baseLength = records?.[0]?.length ?? 0;
468
+ let baseHash = records?.[0] ? checksum(records[0]) : 0;
469
+ let batches = records ? records.length - 1 : 0;
470
+ let tail = records && image ? new Uint8Array(image.bytes.subarray(Math.floor((length - 1) / pageSize) * pageSize)) : new Uint8Array();
471
+ let checkpointRequired = !records || image?.pageSize !== pageSize;
472
+ let previous;
473
+ if (records)
474
+ previous = codec3.baseline ? codec3.baseline(value) : codec3.capture(value, void 0, true).token;
475
+ let generation = 0;
476
+ let saved = 0;
477
+ let queued = 0;
478
+ let inWrite = false;
479
+ let closing = false;
480
+ let closed = false;
481
+ let conflict;
482
+ let lastError;
483
+ let exposed = false;
484
+ let timer;
485
+ let timerActive = false;
486
+ let retryDelay = interval;
487
+ let queue = Promise.resolve();
488
+ function cancel() {
489
+ if (timerActive)
490
+ scheduler.cancel(timer);
491
+ timerActive = false;
492
+ }
493
+ function schedule(delay = interval) {
494
+ if (timerActive || closing || closed || conflict)
495
+ return;
496
+ timerActive = true;
497
+ timer = scheduler.schedule(() => {
498
+ timerActive = false;
499
+ if (!codec3.canCapture(value)) {
500
+ schedule();
501
+ return;
502
+ }
503
+ void enqueue(() => persist()).catch(() => {
504
+ });
505
+ }, delay);
506
+ }
507
+ function failure(error) {
508
+ lastError = error;
509
+ if (error instanceof DurabilityConflictError || typeof error === "object" && error !== null && "name" in error && error.name === "DurabilityConflictError") {
510
+ conflict = error;
511
+ cancel();
512
+ stopLifecycle?.();
513
+ } else {
514
+ schedule(retryDelay);
515
+ retryDelay = Math.min(1e4, Math.max(1e3, retryDelay * 2));
516
+ }
517
+ try {
518
+ options.onError?.(error);
519
+ } catch {
520
+ }
521
+ }
522
+ function enqueue(run) {
523
+ if (closed || closing)
524
+ return Promise.reject(new Error("Durable handle is closed"));
525
+ if (conflict)
526
+ return Promise.reject(conflict);
527
+ queued++;
528
+ const next = queue.then(run).finally(() => {
529
+ queued--;
530
+ });
531
+ queue = next.catch(() => {
532
+ });
533
+ return next;
534
+ }
535
+ async function persist(force = false) {
536
+ if (conflict)
537
+ throw conflict;
538
+ cancel();
539
+ if (!checkpointRequired && generation === saved && !exposed && !force)
540
+ return;
541
+ const at = generation;
542
+ try {
543
+ const checkpoint = checkpointRequired || batches >= maxBatches || length - HEADER - baseLength >= (options.compactAfterBytes ?? Math.max(4 * 1024 * 1024, baseLength));
544
+ const capture = codec3.capture(value, previous, checkpoint || exposed);
545
+ if (!capture.bytes) {
546
+ previous = capture.token;
547
+ saved = at;
548
+ codec3.acknowledge(value, capture.token);
549
+ lastError = void 0;
550
+ retryDelay = interval;
551
+ return;
552
+ }
553
+ const payload = capture.bytes;
554
+ let patch;
555
+ let nextLength;
556
+ let nextBase = baseLength;
557
+ let nextHash = baseHash;
558
+ let nextBatches = batches;
559
+ if (capture.checkpoint) {
560
+ nextBase = payload.length;
561
+ nextHash = checksum(payload);
562
+ nextBatches = 0;
563
+ nextLength = HEADER + payload.length;
564
+ const bytes = new Uint8Array(nextLength);
565
+ bytes.set(header(nextBase, nextHash));
566
+ bytes.set(payload, HEADER);
567
+ const pages = [];
568
+ for (let offset = 0; offset < bytes.length; offset += pageSize)
569
+ pages.push({ index: offset / pageSize, bytes: bytes.subarray(offset, offset + pageSize) });
570
+ patch = { byteLength: nextLength, pageSize, pages };
571
+ } else {
572
+ const frame = new Uint8Array(8 + payload.length);
573
+ const view = new DataView(frame.buffer);
574
+ view.setUint32(0, payload.length, true);
575
+ view.setUint32(4, checksum(payload), true);
576
+ frame.set(payload, 8);
577
+ nextLength = length + frame.length;
578
+ nextBatches++;
579
+ const pages = /* @__PURE__ */ new Map();
580
+ let offset = length;
581
+ while (offset < nextLength) {
582
+ const index = Math.floor(offset / pageSize);
583
+ const start = index * pageSize;
584
+ let page = pages.get(index);
585
+ if (!page) {
586
+ page = new Uint8Array(Math.min(pageSize, nextLength - start));
587
+ if (index === Math.floor((length - 1) / pageSize))
588
+ page.set(tail);
589
+ pages.set(index, page);
590
+ }
591
+ const count = Math.min(page.length - (offset - start), nextLength - offset);
592
+ page.set(frame.subarray(offset - length, offset - length + count), offset - start);
593
+ offset += count;
594
+ }
595
+ patch = {
596
+ byteLength: nextLength,
597
+ pageSize,
598
+ pages: [...pages].map(([index, bytes]) => ({ index, bytes }))
599
+ };
600
+ }
601
+ const lastPage = patch.pages.find((page) => page.index === Math.floor((nextLength - 1) / pageSize));
602
+ if (!lastPage)
603
+ throw new Error("Missing buffered tail page");
604
+ const nextTail = lastPage.bytes.byteOffset === 0 && lastPage.bytes.byteLength === lastPage.bytes.buffer.byteLength ? lastPage.bytes : new Uint8Array(lastPage.bytes);
605
+ revision = await backend.commit(key2, revision, patch);
606
+ tail = nextTail;
607
+ length = nextLength;
608
+ baseLength = nextBase;
609
+ baseHash = nextHash;
610
+ batches = nextBatches;
611
+ previous = capture.token;
612
+ checkpointRequired = false;
613
+ codec3.acknowledge(value, capture.token);
614
+ saved = at;
615
+ lastError = void 0;
616
+ retryDelay = interval;
617
+ } catch (error) {
618
+ failure(error);
619
+ throw error;
620
+ } finally {
621
+ if (generation !== saved || exposed)
622
+ schedule();
623
+ }
624
+ }
625
+ let unsubscribe = () => {
626
+ };
627
+ let stopLifecycle;
628
+ unsubscribe = codec3.subscribe(value, {
629
+ changed() {
630
+ generation++;
631
+ schedule();
632
+ },
633
+ exposed() {
634
+ exposed = true;
635
+ generation++;
636
+ schedule();
637
+ },
638
+ assertWritable() {
639
+ if (closed || closing && !inWrite)
640
+ throw new Error("Durable handle is closed");
641
+ },
642
+ closed() {
643
+ if (closing || closed)
644
+ return;
645
+ closed = true;
646
+ cancel();
647
+ unsubscribe();
648
+ stopLifecycle?.();
649
+ if (checkpointRequired || generation !== saved)
650
+ failure(new Error("Database closed directly; pending buffered changes were not acknowledged"));
651
+ void Promise.resolve().then(() => codec3.close?.(value)).catch(failure);
652
+ }
653
+ });
654
+ stopLifecycle = !closed ? options.lifecycle?.subscribe(() => {
655
+ if (!closed && !closing && !conflict && codec3.canCapture(value))
656
+ void enqueue(persist).catch(() => {
657
+ });
658
+ }) : void 0;
659
+ if (checkpointRequired)
660
+ schedule();
661
+ return {
662
+ value,
663
+ get pending() {
664
+ return checkpointRequired || generation !== saved || queued > 0;
665
+ },
666
+ get lastError() {
667
+ return lastError;
668
+ },
669
+ flush: () => enqueue(() => persist(true)),
670
+ write: (run) => enqueue(async () => {
671
+ let result;
672
+ inWrite = true;
673
+ try {
674
+ result = run(value);
675
+ } finally {
676
+ inWrite = false;
677
+ }
678
+ if (result && typeof result.then === "function")
679
+ throw new TypeError("Durable write callbacks must be synchronous");
680
+ generation++;
681
+ await persist();
682
+ return result;
683
+ }),
684
+ close() {
685
+ if (closed)
686
+ return lastError ? Promise.reject(lastError) : Promise.resolve();
687
+ if (closing)
688
+ return queue;
689
+ const next = enqueue(async () => {
690
+ await persist(true);
691
+ await codec3.close?.(value);
692
+ cancel();
693
+ unsubscribe();
694
+ stopLifecycle?.();
695
+ closed = true;
696
+ });
697
+ closing = true;
698
+ const completion = next.catch((error) => {
699
+ closing = false;
700
+ queue = Promise.resolve();
701
+ if (!conflict)
702
+ schedule();
703
+ throw error;
704
+ });
705
+ queue = completion;
706
+ return completion;
707
+ }
708
+ };
709
+ }
710
+ function packDurableRecord(metadata, snapshot) {
711
+ const meta = new TextEncoder().encode(JSON.stringify(packValue(metadata)));
712
+ const bytes = new Uint8Array(4 + meta.length + snapshot.length);
713
+ new DataView(bytes.buffer).setUint32(0, meta.length, true);
714
+ bytes.set(meta, 4);
715
+ bytes.set(snapshot, 4 + meta.length);
716
+ return bytes;
717
+ }
718
+ function unpackDurableRecord(bytes) {
719
+ if (bytes.length < 4)
720
+ throw new Error("Invalid buffered record");
721
+ const length = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0, true);
722
+ if (length > bytes.length - 4)
723
+ throw new Error("Invalid buffered record");
724
+ return {
725
+ metadata: unpackValue(JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(4, 4 + length)))),
726
+ snapshot: bytes.subarray(4 + length)
727
+ };
728
+ }
729
+ function packValue(value) {
730
+ if (typeof value === "bigint")
731
+ return [2, String(value)];
732
+ if (typeof value === "number" && !Number.isFinite(value))
733
+ return [3, String(value)];
734
+ if (value instanceof Uint8Array)
735
+ return [1, Array.from(value)];
736
+ if (Array.isArray(value))
737
+ return [0, value.map(packValue)];
738
+ if (value !== null && typeof value === "object")
739
+ return [
740
+ 4,
741
+ Object.entries(value).filter(([, value2]) => value2 !== void 0).map(([key2, value2]) => [key2, packValue(value2)])
742
+ ];
743
+ if (value === void 0)
744
+ throw new TypeError("Undefined durable metadata");
745
+ return value;
746
+ }
747
+ function unpackValue(value) {
748
+ if (!Array.isArray(value))
749
+ return value;
750
+ const [tag, payload] = value;
751
+ switch (tag) {
752
+ case 0:
753
+ return payload.map(unpackValue);
754
+ case 1:
755
+ return new Uint8Array(payload);
756
+ case 2:
757
+ return BigInt(payload);
758
+ case 3:
759
+ return Number(payload);
760
+ case 4:
761
+ return Object.fromEntries(payload.map(([key2, value2]) => [key2, unpackValue(value2)]));
762
+ default:
763
+ throw new Error("Invalid durable metadata tag");
764
+ }
765
+ }
766
+
767
+ // ../../core/dist/fork-map.js
768
+ var ForkMap = class _ForkMap {
769
+ owner = {};
770
+ index = { owner: this.owner, groups: [] };
771
+ order = { owner: this.owner, cells: [] };
772
+ shift = 0;
773
+ length = 0;
774
+ count = 0;
775
+ nextSequence = 0;
776
+ layout = 0;
777
+ cleared = 0;
778
+ version = 0;
779
+ constructor(entries) {
780
+ if (entries)
781
+ for (const [key2, value] of entries)
782
+ this.set(key2, value);
783
+ }
784
+ get size() {
785
+ return this.count;
786
+ }
787
+ get [Symbol.toStringTag]() {
788
+ return "Map";
789
+ }
790
+ fork() {
791
+ const copy = new _ForkMap();
792
+ copy.index = this.index;
793
+ copy.order = this.order;
794
+ copy.shift = this.shift;
795
+ copy.length = this.length;
796
+ copy.count = this.count;
797
+ copy.nextSequence = this.nextSequence;
798
+ this.owner = {};
799
+ return copy;
800
+ }
801
+ /** Visit changed hash buckets only. Values must be replaced, rather than mutated in place. */
802
+ *changes(previous) {
803
+ if (previous?.index === this.index)
804
+ return;
805
+ for (let group = 0; group < 32; group++) {
806
+ const currentGroup = this.index.groups[group];
807
+ const oldGroup = previous?.index.groups[group];
808
+ if (currentGroup === oldGroup)
809
+ continue;
810
+ for (let bucket = 0; bucket < 32; bucket++) {
811
+ const current = currentGroup?.buckets[bucket]?.data;
812
+ const old = oldGroup?.buckets[bucket]?.data;
813
+ if (current === old)
814
+ continue;
815
+ if (current)
816
+ for (const [key2, entry] of current) {
817
+ const before = old?.get(key2);
818
+ if (!before || !Object.is(before.value, entry.value) || before.sequence !== entry.sequence)
819
+ yield { key: key2, value: entry.value, deleted: false };
820
+ }
821
+ if (old) {
822
+ for (const key2 of old.keys())
823
+ if (!current?.has(key2))
824
+ yield { key: key2, deleted: true };
825
+ }
826
+ }
827
+ }
828
+ }
829
+ get(key2) {
830
+ return this.find(key2)?.value;
831
+ }
832
+ has(key2) {
833
+ return this.find(key2) !== void 0;
834
+ }
835
+ set(key2, value) {
836
+ if (typeof key2 === "number" && key2 === 0)
837
+ key2 = 0;
838
+ const hash = hashKey(key2);
839
+ const existing = this.bucket(hash)?.get(key2);
840
+ if (existing && Object.is(existing.value, value))
841
+ return this;
842
+ const entry = existing ? { ...existing, value } : { key: key2, value, position: this.length++, sequence: this.nextSequence++ };
843
+ this.writableBucket(hash).set(key2, entry);
844
+ this.writeOrder(entry.position, entry);
845
+ if (!existing)
846
+ this.count++;
847
+ this.version++;
848
+ return this;
849
+ }
850
+ delete(key2) {
851
+ const hash = hashKey(key2);
852
+ const entry = this.bucket(hash)?.get(key2);
853
+ if (!entry)
854
+ return false;
855
+ this.writableBucket(hash).delete(key2);
856
+ this.writeOrder(entry.position, void 0);
857
+ this.count--;
858
+ this.version++;
859
+ if (this.length > 1024 && this.length > this.count * 2)
860
+ this.compact();
861
+ return true;
862
+ }
863
+ clear() {
864
+ this.index = { owner: this.owner, groups: [] };
865
+ this.order = { owner: this.owner, cells: [] };
866
+ this.shift = this.length = this.count = this.nextSequence = 0;
867
+ this.layout++;
868
+ this.cleared++;
869
+ this.version++;
870
+ }
871
+ entries() {
872
+ return this.iterate(0);
873
+ }
874
+ keys() {
875
+ return this.iterate(1);
876
+ }
877
+ values() {
878
+ return this.iterate(2);
879
+ }
880
+ [Symbol.iterator]() {
881
+ return this.entries();
882
+ }
883
+ forEach(callback, thisArg) {
884
+ for (const [key2, value] of this)
885
+ callback.call(thisArg, value, key2, this);
886
+ }
887
+ find(key2) {
888
+ return this.bucket(hashKey(key2))?.get(key2);
889
+ }
890
+ bucket(hash) {
891
+ return this.index.groups[hash >>> 5 & 31]?.buckets[hash & 31]?.data;
892
+ }
893
+ writableBucket(hash) {
894
+ if (this.index.owner !== this.owner)
895
+ this.index = { owner: this.owner, groups: this.index.groups.slice() };
896
+ const groupIndex = hash >>> 5 & 31;
897
+ let group = this.index.groups[groupIndex];
898
+ if (!group || group.owner !== this.owner) {
899
+ group = { owner: this.owner, buckets: group?.buckets.slice() ?? [] };
900
+ this.index.groups[groupIndex] = group;
901
+ }
902
+ const at = hash & 31;
903
+ let bucket = group.buckets[at];
904
+ if (!bucket || bucket.owner !== this.owner) {
905
+ bucket = { owner: this.owner, data: bucket ? this.copyBucket(bucket.data) : /* @__PURE__ */ new Map() };
906
+ group.buckets[at] = bucket;
907
+ }
908
+ return bucket.data;
909
+ }
910
+ copyBucket(bucket) {
911
+ return new Map(bucket);
912
+ }
913
+ leaf(position) {
914
+ let node = this.order;
915
+ for (let shift = this.shift; shift > 0; shift -= 5)
916
+ node = node.cells[Math.floor(position / 2 ** shift) & 31];
917
+ return node;
918
+ }
919
+ writeOrder(position, entry) {
920
+ while (position >= 2 ** (this.shift + 5)) {
921
+ this.order = { owner: this.owner, cells: [this.order] };
922
+ this.shift += 5;
923
+ }
924
+ if (this.order.owner !== this.owner)
925
+ this.order = { owner: this.owner, cells: this.order.cells.slice() };
926
+ let node = this.order;
927
+ for (let shift = this.shift; shift > 0; shift -= 5) {
928
+ const at = Math.floor(position / 2 ** shift) & 31;
929
+ let child = node.cells[at];
930
+ if (!child || child.owner !== this.owner) {
931
+ child = { owner: this.owner, cells: child?.cells.slice() ?? [] };
932
+ node.cells[at] = child;
933
+ }
934
+ node = child;
935
+ }
936
+ node.cells[position & 31] = entry;
937
+ }
938
+ compact() {
939
+ const entries = [];
940
+ for (let position = 0; position < this.length; position++) {
941
+ const entry = this.leaf(position).cells[position & 31];
942
+ if (entry)
943
+ entries.push(entry);
944
+ }
945
+ this.index = { owner: this.owner, groups: [] };
946
+ this.order = { owner: this.owner, cells: [] };
947
+ this.shift = this.length = this.count = 0;
948
+ for (const original of entries) {
949
+ const entry = { ...original, position: this.length++ };
950
+ this.writableBucket(hashKey(entry.key)).set(entry.key, entry);
951
+ this.writeOrder(entry.position, entry);
952
+ this.count++;
953
+ }
954
+ this.layout++;
955
+ }
956
+ *iterate(kind) {
957
+ let position = 0;
958
+ let layout = this.layout;
959
+ let cleared = this.cleared;
960
+ let lastSequence = -1;
961
+ let version = -1;
962
+ let leaf;
963
+ let page = -1;
964
+ for (; ; ) {
965
+ if (cleared !== this.cleared) {
966
+ position = 0;
967
+ lastSequence = -1;
968
+ cleared = this.cleared;
969
+ }
970
+ if (layout !== this.layout) {
971
+ position = 0;
972
+ while (position < this.length) {
973
+ const entry2 = this.leaf(position).cells[position & 31];
974
+ if (entry2 && entry2.sequence > lastSequence)
975
+ break;
976
+ position++;
977
+ }
978
+ layout = this.layout;
979
+ }
980
+ if (position >= this.length)
981
+ return;
982
+ const nextPage = Math.floor(position / 32);
983
+ if (page !== nextPage || version !== this.version) {
984
+ leaf = this.leaf(position);
985
+ page = nextPage;
986
+ version = this.version;
987
+ }
988
+ const entry = leaf?.cells[position++ & 31];
989
+ if (!entry)
990
+ continue;
991
+ lastSequence = entry.sequence;
992
+ yield kind === 0 ? [entry.key, entry.value] : kind === 1 ? entry.key : entry.value;
993
+ }
994
+ }
995
+ };
996
+ function hashKey(key2) {
997
+ if (typeof key2 === "number" && Number.isInteger(key2))
998
+ return mix((key2 | 0) ^ (key2 / 4294967296 | 0));
999
+ if (typeof key2 === "bigint")
1000
+ return mix(Number(BigInt.asIntN(32, key2 ^ key2 >> 32n)));
1001
+ const text = String(key2);
1002
+ let hash = 2166136261;
1003
+ for (let i = 0; i < text.length; i++)
1004
+ hash = Math.imul(hash ^ text.charCodeAt(i), 16777619);
1005
+ return hash;
1006
+ }
1007
+ function mix(value) {
1008
+ value = Math.imul(value ^ value >>> 16, 73244475);
1009
+ value = Math.imul(value ^ value >>> 16, 73244475);
1010
+ return value ^ value >>> 16;
1011
+ }
1012
+
1
1013
  // ../../core/dist/timeline.js
2
1014
  var BRANCH_PATTERN = /^[A-Za-z0-9_.-]{1,64}$/;
3
1015
  var Timeline = class {
@@ -921,11 +1933,11 @@ function tsHeadline(config, document, query, options) {
921
1933
  for (const part of options.split(",")) {
922
1934
  const eq = part.indexOf("=");
923
1935
  if (eq === -1) continue;
924
- const key = part.slice(0, eq).trim().toLowerCase();
1936
+ const key2 = part.slice(0, eq).trim().toLowerCase();
925
1937
  let val = part.slice(eq + 1).trim();
926
1938
  if (val.startsWith('"') && val.endsWith('"')) val = val.slice(1, -1);
927
- if (key === "startsel") startSel = val;
928
- else if (key === "stopsel") stopSel = val;
1939
+ if (key2 === "startsel") startSel = val;
1940
+ else if (key2 === "stopsel") stopSel = val;
929
1941
  }
930
1942
  }
931
1943
  const node = parseTsqueryText(query);
@@ -1028,8 +2040,8 @@ function weightIndex(w) {
1028
2040
  function collectQueryOperands(node, out) {
1029
2041
  switch (node.kind) {
1030
2042
  case "lexeme": {
1031
- const key = `${node.word}\0${node.prefix ? "*" : ""}`;
1032
- if (!out.has(key)) out.set(key, node);
2043
+ const key2 = `${node.word}\0${node.prefix ? "*" : ""}`;
2044
+ if (!out.has(key2)) out.set(key2, node);
1033
2045
  break;
1034
2046
  }
1035
2047
  case "not":
@@ -2256,13 +3268,13 @@ var JsonParser = class {
2256
3268
  for (; ; ) {
2257
3269
  this.skipWs();
2258
3270
  if (this.text[this.pos] !== '"') this.fail("expected string key");
2259
- const key = this.parseString();
3271
+ const key2 = this.parseString();
2260
3272
  this.skipWs();
2261
3273
  if (this.text[this.pos] !== ":") this.fail("expected :");
2262
3274
  this.pos++;
2263
3275
  this.skipWs();
2264
3276
  const value = this.parseValue(depth);
2265
- m.set(key, value);
3277
+ m.set(key2, value);
2266
3278
  this.skipWs();
2267
3279
  const c = this.text[this.pos];
2268
3280
  if (c === ",") {
@@ -4790,10 +5802,81 @@ function parseArrayText(t, text, ctx) {
4790
5802
 
4791
5803
  // src/storage/database-state.ts
4792
5804
  var TableData = class _TableData {
5805
+ /** @internal Optional physical row journal; IDs remain stable across heap splices. */
5806
+ durableChanges = null;
5807
+ durableNextId = 0;
5808
+ durableEpoch;
5809
+ durableUnsafe = false;
5810
+ durableIds;
5811
+ enableDurabilityTracking(ids, nextId) {
5812
+ if (this.durableChanges && !this.durableUnsafe && !ids) return;
5813
+ this.materializeSlab();
5814
+ this.durableIds = /* @__PURE__ */ new WeakMap();
5815
+ this.durableChanges = new ForkMap();
5816
+ this.durableNextId = nextId ?? this.#rows.length;
5817
+ for (let i = 0; i < this.#rows.length; i++) this.durableIds.set(this.#rows[i], ids?.[i] ?? i);
5818
+ this.durableEpoch = {};
5819
+ this.durableUnsafe = false;
5820
+ }
5821
+ durableRowId(row) {
5822
+ const id = this.durableIds?.get(row);
5823
+ if (id === void 0) throw new Error("Untracked durable row");
5824
+ return id;
5825
+ }
5826
+ disableDurabilityTracking() {
5827
+ this.durableChanges = null;
5828
+ this.durableIds = void 0;
5829
+ this.durableEpoch = void 0;
5830
+ this.durableUnsafe = false;
5831
+ }
5832
+ recordDurableRow(row, previous) {
5833
+ if (!this.durableChanges) return;
5834
+ const id = (previous && this.durableIds?.get(previous)) ?? this.durableIds?.get(row) ?? this.durableNextId++;
5835
+ this.durableIds.set(row, id);
5836
+ this.durableChanges.set(id, { row, xmin: this.rowXmins.get(row) ?? 2 });
5837
+ }
5838
+ recordDurableDelete(row) {
5839
+ if (this.durableChanges) this.durableChanges.set(this.durableRowId(row), { row: null, xmin: 0 });
5840
+ }
5841
+ /** @internal Metadata twin with no visits/copies of existing rows or index entries. */
5842
+ emptyForDurability() {
5843
+ const copy = new _TableData(this.schema, this.name, this.columns, this.oid, this.temp);
5844
+ copy.constraints = this.constraints;
5845
+ copy.triggers = this.triggers;
5846
+ copy.unlogged = this.unlogged;
5847
+ return copy;
5848
+ }
5849
+ /** @internal Serialization/SQL scans must not count as public native-array exposure. */
5850
+ serializationRows() {
5851
+ this.materializeSlab();
5852
+ return this.materializedRows();
5853
+ }
5854
+ /** @internal Internal mutable array access, with ordinary public mutableRows kept intact. */
5855
+ writeRows() {
5856
+ return this.serializationRows();
5857
+ }
5858
+ /** @internal Ordinary snapshot branches must not inherit a persistence journal. */
5859
+ untrackedFork() {
5860
+ const copy = this.emptyForDurability();
5861
+ copy.rowXmins = this.rowXmins;
5862
+ copy.slabXmins = this.slabXmins;
5863
+ if (this.slab) copy.slab = this.slab;
5864
+ else {
5865
+ copy.#rows = this.#rows;
5866
+ copy.#rowPatches = this.#rowPatches?.fork() ?? null;
5867
+ copy.#rowsShared = this.#rowsShared = true;
5868
+ copy.tuplesShared = this.tuplesShared = true;
5869
+ }
5870
+ copy.indexStores = this.indexStores ? new Map([...this.indexStores].map(([name, store]) => [name, store.clone()])) : null;
5871
+ return copy;
5872
+ }
4793
5873
  name;
4794
5874
  schema;
4795
5875
  columns;
4796
- rows;
5876
+ #rows = [];
5877
+ #rowPatches = null;
5878
+ #rowsShared = false;
5879
+ #rowsExposed = false;
4797
5880
  rowXmins = /* @__PURE__ */ new WeakMap();
4798
5881
  slabXmins = null;
4799
5882
  /** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
@@ -4809,22 +5892,54 @@ var TableData = class _TableData {
4809
5892
  shareCount = 0;
4810
5893
  /** Derived unique/btree index maps; null until built or invalidated. */
4811
5894
  indexStores = null;
5895
+ /** DML replaces tuples; DDL must detach them before changing cells in place. */
5896
+ tuplesShared = false;
4812
5897
  constructor(schema, name, columns, oid, temp = false) {
4813
5898
  this.schema = schema;
4814
5899
  this.name = name;
4815
5900
  this.columns = columns;
4816
- this.rows = [];
5901
+ Object.defineProperty(this, "rows", {
5902
+ enumerable: true,
5903
+ configurable: true,
5904
+ get: this.nativeRows,
5905
+ set: this.setNativeRows
5906
+ });
4817
5907
  this.constraints = [];
4818
5908
  this.triggers = [];
4819
5909
  this.temp = temp;
4820
5910
  this.oid = oid;
4821
5911
  }
4822
5912
  rowCount() {
4823
- return this.slab ? this.slab.rowCount : this.rows.length;
5913
+ return this.slab ? this.slab.rowCount : this.#rows.length;
4824
5914
  }
4825
5915
  rowAt(index) {
4826
5916
  if (this.slab) return this.slab.rowAt(index);
4827
- return this.rows[index] ?? [];
5917
+ return this.#rowPatches?.get(index) ?? this.#rows[index] ?? [];
5918
+ }
5919
+ /** Replace an existing tuple without copying the array of unchanged row references. */
5920
+ replaceRow(index, row) {
5921
+ if (this.durableChanges) this.recordDurableRow(row, this.rowAt(index));
5922
+ if (this.#rowPatches) this.#rowPatches.set(index, row);
5923
+ else this.#rows[index] = row;
5924
+ }
5925
+ materializedRows() {
5926
+ if (this.#rowsShared) this.#rows = this.#rows.slice();
5927
+ if (this.#rowPatches) for (const [index, row] of this.#rowPatches) this.#rows[index] = row;
5928
+ this.#rowPatches = null;
5929
+ this.#rowsShared = false;
5930
+ return this.#rows;
5931
+ }
5932
+ nativeRows() {
5933
+ if (this.durableChanges) this.durableUnsafe = true;
5934
+ this.#rowsExposed = true;
5935
+ return this.materializedRows();
5936
+ }
5937
+ setNativeRows(rows) {
5938
+ if (this.durableChanges) this.durableUnsafe = true;
5939
+ this.#rows = rows;
5940
+ this.#rowPatches = null;
5941
+ this.#rowsShared = false;
5942
+ this.#rowsExposed = true;
4828
5943
  }
4829
5944
  /** All rows for scans; materializes slab once into `rows` when needed. */
4830
5945
  allRows() {
@@ -4833,13 +5948,15 @@ var TableData = class _TableData {
4833
5948
  }
4834
5949
  attachSlab(slab) {
4835
5950
  this.slab = slab;
4836
- this.rows = [];
5951
+ this.#rows = [];
5952
+ this.#rowPatches = null;
5953
+ this.#rowsShared = false;
4837
5954
  }
4838
5955
  materializeSlab() {
4839
5956
  if (!this.slab) return;
4840
- this.rows = this.slab.materialize();
5957
+ this.#rows = this.slab.materialize();
4841
5958
  if (this.slabXmins)
4842
- this.rows.forEach((row, index) => {
5959
+ this.#rows.forEach((row, index) => {
4843
5960
  this.rowXmins.set(row, this.slabXmins[index] ?? 2);
4844
5961
  });
4845
5962
  this.slabXmins = null;
@@ -4863,7 +5980,7 @@ var TableData = class _TableData {
4863
5980
  columnIndex(name) {
4864
5981
  return this.columns.findIndex((c) => c.name === name);
4865
5982
  }
4866
- clone() {
5983
+ cloneMetadata() {
4867
5984
  const t = new _TableData(
4868
5985
  this.schema,
4869
5986
  this.name,
@@ -4871,21 +5988,68 @@ var TableData = class _TableData {
4871
5988
  this.oid,
4872
5989
  this.temp
4873
5990
  );
5991
+ t.unlogged = this.unlogged;
5992
+ t.durableChanges = this.durableChanges?.fork() ?? null;
5993
+ t.durableIds = this.durableIds;
5994
+ t.durableNextId = this.durableNextId;
5995
+ t.durableEpoch = this.durableEpoch;
5996
+ t.durableUnsafe = this.durableUnsafe;
5997
+ t.constraints = this.constraints.map((c) => ({ ...c }));
5998
+ t.triggers = this.triggers.map((tr) => ({ ...tr }));
5999
+ t.indexStores = this.indexStores ? new Map([...this.indexStores].map(([k, v]) => [k, v.clone()])) : null;
6000
+ return t;
6001
+ }
6002
+ clone() {
6003
+ const t = this.cloneMetadata();
6004
+ if (t.durableChanges) t.durableUnsafe = true;
4874
6005
  if (this.slab) {
4875
- t.rows = this.slab.materialize().map((r) => r.slice());
6006
+ t.#rows = this.slab.materialize().map((r) => r.slice());
4876
6007
  } else {
4877
- t.rows = this.rows.map((r) => r.slice());
6008
+ t.#rows = this.materializedRows().map((r) => r.slice());
4878
6009
  }
4879
- t.rows.forEach((row, index) => {
4880
- const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.rows[index]);
6010
+ t.#rows.forEach((row, index) => {
6011
+ const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.#rows[index]);
4881
6012
  if (xmin !== void 0) t.rowXmins.set(row, xmin);
4882
6013
  });
4883
- t.unlogged = this.unlogged;
4884
- t.constraints = this.constraints.map((c) => ({ ...c }));
4885
- t.triggers = this.triggers.map((tr) => ({ ...tr }));
4886
- t.indexStores = this.indexStores ? new Map([...this.indexStores].map(([k, v]) => [k, v.clone()])) : null;
4887
6014
  return t;
4888
6015
  }
6016
+ /** DML creates new tuple arrays; retain existing tuples and xmin bindings until DDL. */
6017
+ cloneForDml() {
6018
+ if (this.triggers.length > 0) return this.cloneForWrite();
6019
+ const t = this.cloneMetadata();
6020
+ t.rowXmins = this.rowXmins;
6021
+ if (this.slab) {
6022
+ t.#rows = this.slab.materialize();
6023
+ if (this.slabXmins) {
6024
+ for (let index = 0; index < t.#rows.length; index++)
6025
+ t.rowXmins.set(t.#rows[index], this.slabXmins[index] ?? 2);
6026
+ }
6027
+ } else {
6028
+ if (this.#rows.length >= 4096 && !this.#rowsExposed) {
6029
+ this.#rowPatches ??= new ForkMap();
6030
+ t.#rowPatches = this.#rowPatches.fork();
6031
+ t.#rows = this.#rows;
6032
+ t.#rowsShared = this.#rowsShared = true;
6033
+ } else t.#rows = this.materializedRows().slice();
6034
+ this.tuplesShared = true;
6035
+ }
6036
+ t.tuplesShared = true;
6037
+ return t;
6038
+ }
6039
+ /** A live DML fork can be unfrozen while its unchanged tuples still belong to history. */
6040
+ ownTuples() {
6041
+ if (this.durableChanges) this.durableUnsafe = true;
6042
+ if (!this.tuplesShared) return;
6043
+ const xmins = /* @__PURE__ */ new WeakMap();
6044
+ this.rows = this.rows.map((row) => {
6045
+ const copy = row.slice();
6046
+ const xmin = this.rowXmins.get(row);
6047
+ if (xmin !== void 0) xmins.set(copy, xmin);
6048
+ return copy;
6049
+ });
6050
+ this.rowXmins = xmins;
6051
+ this.tuplesShared = false;
6052
+ }
4889
6053
  /** Independent writable copy (row tuples copied so ALTER COLUMN is isolated). */
4890
6054
  cloneForWrite() {
4891
6055
  const t = this.clone();
@@ -5153,10 +6317,10 @@ var DatabaseState = class _DatabaseState {
5153
6317
  }
5154
6318
  return out;
5155
6319
  }
5156
- findEnumByKey(key) {
5157
- const dot = key.indexOf(".");
5158
- if (dot === -1) return this.findEnum([key]);
5159
- return this.schemas.get(key.slice(0, dot))?.enums.get(key.slice(dot + 1)) ?? null;
6320
+ findEnumByKey(key2) {
6321
+ const dot = key2.indexOf(".");
6322
+ if (dot === -1) return this.findEnum([key2]);
6323
+ return this.schemas.get(key2.slice(0, dot))?.enums.get(key2.slice(dot + 1)) ?? null;
5160
6324
  }
5161
6325
  /** format_type()-style display name for a type OID (builtin or enum). */
5162
6326
  typeNameForOid(oid) {
@@ -5239,12 +6403,21 @@ var DatabaseState = class _DatabaseState {
5239
6403
  }
5240
6404
  }
5241
6405
  ensureWritableTable(table) {
5242
- if (!table.frozen) return table;
6406
+ if (!table.frozen) {
6407
+ table.ownTuples();
6408
+ return table;
6409
+ }
5243
6410
  const schema = this.schemas.get(table.schema);
5244
6411
  const copy = table.cloneForWrite();
5245
6412
  schema?.tables.set(table.name, copy);
5246
6413
  return copy;
5247
6414
  }
6415
+ ensureWritableTableForDml(table) {
6416
+ if (!table.frozen) return table;
6417
+ const copy = table.cloneForDml();
6418
+ this.schemas.get(table.schema)?.tables.set(table.name, copy);
6419
+ return copy;
6420
+ }
5248
6421
  ensureWritableSequence(seq) {
5249
6422
  if ((seq.shareCount ?? 0) === 0) return seq;
5250
6423
  const schema = this.schemas.get(seq.schema);
@@ -5634,8 +6807,8 @@ function canImplicitCast(from, to) {
5634
6807
  if (from === to) return true;
5635
6808
  if (from === "unknown") return true;
5636
6809
  if (isArrayType(from) && isArrayType(to)) return canImplicitCast(arrayElemType(from), arrayElemType(to));
5637
- const key = `${from}->${to}`;
5638
- return IMPLICIT_CASTS.has(key);
6810
+ const key2 = `${from}->${to}`;
6811
+ return IMPLICIT_CASTS.has(key2);
5639
6812
  }
5640
6813
  var IMPLICIT_CASTS = /* @__PURE__ */ new Set([
5641
6814
  "int2->int4",
@@ -5946,8 +7119,8 @@ function numericFamilyCast(from, to, v) {
5946
7119
  }
5947
7120
  }
5948
7121
  function datetimeCast(env, from, to, v) {
5949
- const key = `${from}->${to}`;
5950
- switch (key) {
7122
+ const key2 = `${from}->${to}`;
7123
+ switch (key2) {
5951
7124
  case "date->timestamp": {
5952
7125
  const d = v;
5953
7126
  if (d === DATE_POS_INF) return TS_POS_INF;
@@ -8354,7 +9527,7 @@ function evalPgcryptoFunction(ctx, fn, args) {
8354
9527
  // src/functions/hash-fns.ts
8355
9528
  var utf83 = new TextEncoder();
8356
9529
  var rot = (x, k) => (x << k | x >>> 32 - k) >>> 0;
8357
- function mix(s) {
9530
+ function mix2(s) {
8358
9531
  s[0] = s[0] - s[2] >>> 0;
8359
9532
  s[0] = (s[0] ^ rot(s[2], 4)) >>> 0;
8360
9533
  s[2] = s[2] + s[1] >>> 0;
@@ -8398,7 +9571,7 @@ function hashAny(k, seed) {
8398
9571
  const bits = BigInt.asUintN(64, seed);
8399
9572
  s[0] = s[0] + Number(bits >> 32n) >>> 0;
8400
9573
  s[1] = s[1] + Number(bits & 0xffffffffn) >>> 0;
8401
- mix(s);
9574
+ mix2(s);
8402
9575
  }
8403
9576
  let at = 0;
8404
9577
  let len = k.length;
@@ -8406,7 +9579,7 @@ function hashAny(k, seed) {
8406
9579
  s[0] = s[0] + word(k, at) >>> 0;
8407
9580
  s[1] = s[1] + word(k, at + 4) >>> 0;
8408
9581
  s[2] = s[2] + word(k, at + 8) >>> 0;
8409
- mix(s);
9582
+ mix2(s);
8410
9583
  }
8411
9584
  for (let i = len - 1; i >= 0; i--) {
8412
9585
  const byte = k[at + i];
@@ -8596,7 +9769,7 @@ function getJsonFunctions() {
8596
9769
  m.set("json_typeof", typeofFn);
8597
9770
  m.set("jsonb_typeof", typeofFn);
8598
9771
  for (const name of ["jsonb_path_query_first", "jsonb_path_exists", "jsonb_path_match", "jsonb_path_query_array"]) {
8599
- for (const key of [name, `${name}_tz`]) m.set(key, jsonpathFunction(name));
9772
+ for (const key2 of [name, `${name}_tz`]) m.set(key2, jsonpathFunction(name));
8600
9773
  }
8601
9774
  m.set(
8602
9775
  "json_array_length",
@@ -8620,11 +9793,11 @@ function getJsonFunctions() {
8620
9793
  let current = jsonArg(ctx, args[0]);
8621
9794
  for (const pathArg of args.slice(1)) {
8622
9795
  if (current === null) break;
8623
- const key = argText(ctx, pathArg);
9796
+ const key2 = argText(ctx, pathArg);
8624
9797
  if (current.j === "obj") {
8625
- current = current.v.get(key) ?? null;
9798
+ current = current.v.get(key2) ?? null;
8626
9799
  } else if (current.j === "arr") {
8627
- const idx = Number.parseInt(key, 10);
9800
+ const idx = Number.parseInt(key2, 10);
8628
9801
  if (Number.isNaN(idx)) {
8629
9802
  current = null;
8630
9803
  } else {
@@ -8733,8 +9906,8 @@ function buildObject(ctx, args) {
8733
9906
  if (k.v === null) {
8734
9907
  throw pgError("invalid_parameter_value", "argument 1: key must not be null", "22004");
8735
9908
  }
8736
- const key = castTo(ctx, k, "text", { explicit: true }).v;
8737
- entries.push([key, datumToJsonb(ctx, args[i + 1].t, args[i + 1].v)]);
9909
+ const key2 = castTo(ctx, k, "text", { explicit: true }).v;
9910
+ entries.push([key2, datumToJsonb(ctx, args[i + 1].t, args[i + 1].v)]);
8738
9911
  }
8739
9912
  return jsonbObj(entries);
8740
9913
  }
@@ -9430,14 +10603,14 @@ function nameTaken(schema, name, self) {
9430
10603
  return other !== void 0 && other !== self;
9431
10604
  }
9432
10605
  function syncIndexCatalog(state) {
9433
- const tables = /* @__PURE__ */ new Map();
10606
+ const tables2 = /* @__PURE__ */ new Map();
9434
10607
  for (const schema of state.schemas.values()) {
9435
- for (const table of schema.tables.values()) tables.set(table.oid, { schema, table });
10608
+ for (const table of schema.tables.values()) tables2.set(table.oid, { schema, table });
9436
10609
  for (const view of schema.views.values())
9437
- if (view.materialized) tables.set(view.oid, { schema, table: materializedTable(view) });
10610
+ if (view.materialized) tables2.set(view.oid, { schema, table: materializedTable(view) });
9438
10611
  }
9439
10612
  const backing = /* @__PURE__ */ new Map();
9440
- for (const { table } of tables.values()) {
10613
+ for (const { table } of tables2.values()) {
9441
10614
  for (const constraint of table.constraints) {
9442
10615
  if (isKeyConstraint(constraint) && constraint.indexOid !== void 0) {
9443
10616
  backing.set(constraint.indexOid, { table, constraint });
@@ -9446,20 +10619,20 @@ function syncIndexCatalog(state) {
9446
10619
  }
9447
10620
  const linked = /* @__PURE__ */ new Set();
9448
10621
  for (const schema of state.schemas.values()) {
9449
- for (const [key, index] of [...schema.indexes]) {
9450
- const home = index.tableOid !== void 0 ? tables.get(index.tableOid) : schema.tables.has(index.table) ? { schema, table: schema.tables.get(index.table) } : void 0;
10622
+ for (const [key2, index] of [...schema.indexes]) {
10623
+ const home = index.tableOid !== void 0 ? tables2.get(index.tableOid) : schema.tables.has(index.table) ? { schema, table: schema.tables.get(index.table) } : void 0;
9451
10624
  const owner = index.isConstraint && index.oid !== void 0 ? backing.get(index.oid) : void 0;
9452
10625
  if (!home || index.isConstraint && (!owner || owner.table !== home.table)) {
9453
- schema.indexes.delete(key);
10626
+ schema.indexes.delete(key2);
9454
10627
  continue;
9455
10628
  }
9456
10629
  const name = owner ? owner.constraint.name : index.name;
9457
- const stale = index.oid === void 0 || index.tableOid !== home.table.oid || index.schema !== home.schema.name || index.table !== home.table.name || index.name !== name || key !== name || owner !== void 0 && !sameKeyColumns(index, owner.constraint);
10630
+ const stale = index.oid === void 0 || index.tableOid !== home.table.oid || index.schema !== home.schema.name || index.table !== home.table.name || index.name !== name || key2 !== name || owner !== void 0 && !sameKeyColumns(index, owner.constraint);
9458
10631
  if (!stale) {
9459
10632
  if (owner) linked.add(index.oid);
9460
10633
  continue;
9461
10634
  }
9462
- schema.indexes.delete(key);
10635
+ schema.indexes.delete(key2);
9463
10636
  if (nameTaken(home.schema, name)) continue;
9464
10637
  const next = {
9465
10638
  ...index,
@@ -9477,7 +10650,7 @@ function syncIndexCatalog(state) {
9477
10650
  home.schema.indexes.set(name, next);
9478
10651
  }
9479
10652
  }
9480
- for (const { schema, table } of [...tables.values()]) {
10653
+ for (const { schema, table } of [...tables2.values()]) {
9481
10654
  if (!table.constraints.some((c) => isKeyConstraint(c) && (c.indexOid === void 0 || !linked.has(c.indexOid)))) {
9482
10655
  continue;
9483
10656
  }
@@ -10264,8 +11437,8 @@ function splitCollation(column) {
10264
11437
  return { column: null, expr: inner, collation };
10265
11438
  }
10266
11439
  function keyText(scope, column, pretty) {
10267
- const key = splitCollation(column);
10268
- return key.column !== null ? quoteIdentifier(key.column) : deparseIndexExpr(scope, key.expr, pretty);
11440
+ const key2 = splitCollation(column);
11441
+ return key2.column !== null ? quoteIdentifier(key2.column) : deparseIndexExpr(scope, key2.expr, pretty);
10269
11442
  }
10270
11443
  function defaultOpclass(type) {
10271
11444
  if (type === null) return null;
@@ -10274,15 +11447,15 @@ function defaultOpclass(type) {
10274
11447
  return type === "varchar" ? "text_ops" : `${type}_ops`;
10275
11448
  }
10276
11449
  function columnType(table, column) {
10277
- const key = splitCollation(column);
10278
- return key.column === null ? null : table?.columns.find((c) => c.name === key.column)?.type.id ?? null;
11450
+ const key2 = splitCollation(column);
11451
+ return key2.column === null ? null : table?.columns.find((c) => c.name === key2.column)?.type.id ?? null;
10279
11452
  }
10280
11453
  function keyDefinition(scope, index, column, pretty) {
10281
11454
  let out = keyText(scope, column, pretty);
10282
- const key = splitCollation(column);
10283
- const declared = key.column === null ? null : scope.table?.columns.find((c) => c.name === key.column)?.collate;
10284
- if (key.collation !== null && key.collation !== (declared ?? null)) {
10285
- out += ` COLLATE ${quoteIdentifier(key.collation)}`;
11455
+ const key2 = splitCollation(column);
11456
+ const declared = key2.column === null ? null : scope.table?.columns.find((c) => c.name === key2.column)?.collate;
11457
+ if (key2.collation !== null && key2.collation !== (declared ?? null)) {
11458
+ out += ` COLLATE ${quoteIdentifier(key2.collation)}`;
10286
11459
  }
10287
11460
  const opclass = column.opclass;
10288
11461
  if (opclass && opclass[opclass.length - 1] !== defaultOpclass(columnType(scope.table, column))) {
@@ -10309,7 +11482,7 @@ function deparseIndexPredicate(ctx, index, pretty = false) {
10309
11482
  }
10310
11483
  function deparseIndexExpressions(ctx, index) {
10311
11484
  const scope = scopeOf(ctx, index);
10312
- const expressions = index.columns.map(splitCollation).filter((key) => key.expr !== null).map((key) => deparseRuleExpr(scope, key.expr));
11485
+ const expressions = index.columns.map(splitCollation).filter((key2) => key2.expr !== null).map((key2) => deparseRuleExpr(scope, key2.expr));
10313
11486
  return expressions.length > 0 ? expressions.join(", ") : null;
10314
11487
  }
10315
11488
  function deparseIndex(ctx, index, pretty = false) {
@@ -10324,8 +11497,8 @@ function deparseIndex(ctx, index, pretty = false) {
10324
11497
  return predicate === null ? out : `${out} WHERE ${predicate}`;
10325
11498
  }
10326
11499
  function deparseIndexColumn(ctx, index, position, pretty = false) {
10327
- const key = index.columns[position - 1];
10328
- if (key) return keyText(scopeOf(ctx, index), key, pretty);
11500
+ const key2 = index.columns[position - 1];
11501
+ if (key2) return keyText(scopeOf(ctx, index), key2, pretty);
10329
11502
  const included = index.include?.[position - 1 - index.columns.length];
10330
11503
  return included === void 0 ? "" : quoteIdentifier(included);
10331
11504
  }
@@ -12380,9 +13553,9 @@ function tryDatetimeArith(ctx, op, l, r) {
12380
13553
  const rt = r.t;
12381
13554
  const isDT = (t) => ["date", "time", "timestamp", "timestamptz", "interval"].includes(t);
12382
13555
  if (!isDT(lt) && !isDT(rt)) return null;
12383
- const key = `${lt}${op}${rt}`;
13556
+ const key2 = `${lt}${op}${rt}`;
12384
13557
  const nullOf = (t) => tv(t, null);
12385
- switch (key) {
13558
+ switch (key2) {
12386
13559
  case "date+int4":
12387
13560
  case "date+int2": {
12388
13561
  if (l.v === null || r.v === null) return nullOf("date");
@@ -12849,11 +14022,11 @@ function evalJsonExtract(_ctx, op, l, r) {
12849
14022
  result = null;
12850
14023
  break;
12851
14024
  }
12852
- const key = String(p);
12853
- if (result.j === "arr" && /^-?\d+$/.test(key)) {
12854
- result = jsonGetIndex(result, Number(key));
14025
+ const key2 = String(p);
14026
+ if (result.j === "arr" && /^-?\d+$/.test(key2)) {
14027
+ result = jsonGetIndex(result, Number(key2));
12855
14028
  } else {
12856
- result = jsonGetKey(result, key);
14029
+ result = jsonGetKey(result, key2);
12857
14030
  }
12858
14031
  }
12859
14032
  }
@@ -12871,18 +14044,18 @@ function jsonGetIndex(v, idx) {
12871
14044
  const i = idx < 0 ? v.v.length + idx : idx;
12872
14045
  return v.v[i] ?? null;
12873
14046
  }
12874
- function jsonGetKey(v, key) {
14047
+ function jsonGetKey(v, key2) {
12875
14048
  if (v.j !== "obj") return null;
12876
- return v.v.get(key) ?? null;
14049
+ return v.v.get(key2) ?? null;
12877
14050
  }
12878
14051
  function evalJsonbExists(_ctx, op, l, r) {
12879
14052
  if (l.t !== "jsonb") opNotExist(op, l.t, r.t);
12880
14053
  if (l.v === null || r.v === null) return tv("bool", null);
12881
14054
  const value = l.v.value;
12882
- const has = (key) => {
12883
- if (value.j === "obj") return value.v.has(key);
12884
- if (value.j === "arr") return value.v.some((x) => x.j === "str" && x.v === key);
12885
- if (value.j === "str") return value.v === key;
14055
+ const has = (key2) => {
14056
+ if (value.j === "obj") return value.v.has(key2);
14057
+ if (value.j === "arr") return value.v.some((x) => x.j === "str" && x.v === key2);
14058
+ if (value.j === "str") return value.v === key2;
12886
14059
  return false;
12887
14060
  };
12888
14061
  if (op === "?") {
@@ -12896,14 +14069,14 @@ function evalJsonbDelete(_ctx, l, r) {
12896
14069
  if (l.v === null || r.v === null) return tv("jsonb", null);
12897
14070
  const value = l.v.value;
12898
14071
  if (isTextType(r.t) || r.t === "unknown") {
12899
- const key = r.v;
14072
+ const key2 = r.v;
12900
14073
  if (value.j === "obj") {
12901
14074
  const m = new Map(value.v);
12902
- m.delete(key);
14075
+ m.delete(key2);
12903
14076
  return tv("jsonb", wrapJsonb({ j: "obj", v: m }));
12904
14077
  }
12905
14078
  if (value.j === "arr") {
12906
- return tv("jsonb", wrapJsonb(jsonbArr(value.v.filter((x) => !(x.j === "str" && x.v === key)))));
14079
+ return tv("jsonb", wrapJsonb(jsonbArr(value.v.filter((x) => !(x.j === "str" && x.v === key2)))));
12907
14080
  }
12908
14081
  throw pgError("invalid_parameter_value", "cannot delete from scalar", "22023");
12909
14082
  }
@@ -12940,22 +14113,22 @@ function evalJsonbDeletePath(ctx, l, r0) {
12940
14113
  throw pgError("invalid_parameter_value", "path element cannot be null", "22004");
12941
14114
  }
12942
14115
  const del = (v, depth) => {
12943
- const key = path[depth];
14116
+ const key2 = path[depth];
12944
14117
  if (v.j === "obj") {
12945
- if (!v.v.has(key)) return v;
14118
+ if (!v.v.has(key2)) return v;
12946
14119
  const m = new Map(v.v);
12947
14120
  if (depth === path.length - 1) {
12948
- m.delete(key);
14121
+ m.delete(key2);
12949
14122
  } else {
12950
- m.set(key, del(m.get(key), depth + 1));
14123
+ m.set(key2, del(m.get(key2), depth + 1));
12951
14124
  }
12952
14125
  return { j: "obj", v: m };
12953
14126
  }
12954
14127
  if (v.j === "arr") {
12955
- if (!/^-?\d+$/.test(key)) {
14128
+ if (!/^-?\d+$/.test(key2)) {
12956
14129
  return v;
12957
14130
  }
12958
- let idx = Number(key);
14131
+ let idx = Number(key2);
12959
14132
  if (idx < 0) idx = v.v.length + idx;
12960
14133
  if (idx < 0 || idx >= v.v.length) return v;
12961
14134
  if (depth === path.length - 1) {
@@ -13728,8 +14901,8 @@ function evalJsonbSubscript(ctx, scope, base, e) {
13728
14901
  const k = evalExpr(ctx, scope, sub.lower ?? sub.upper);
13729
14902
  if (k.v === null) return tv("jsonb", null);
13730
14903
  if (current.j === "obj") {
13731
- const key = String(castTo(ctx, k, "text", { explicit: true }).v);
13732
- current = current.v.get(key) ?? null;
14904
+ const key2 = String(castTo(ctx, k, "text", { explicit: true }).v);
14905
+ current = current.v.get(key2) ?? null;
13733
14906
  } else if (current.j === "arr") {
13734
14907
  const cast = castTo(ctx, k, "int4", { explicit: true });
13735
14908
  let i = cast.v;
@@ -14182,8 +15355,8 @@ var JsonObjectAggAcc = class {
14182
15355
  if (k.v === null) {
14183
15356
  throw pgError("null_value_not_allowed", "field name must not be null", "22004");
14184
15357
  }
14185
- const key = castTo(this.ctx, k, "text", { explicit: true }).v;
14186
- this.entries.push([key, v.v === null ? JSONB_NULL : datumToJsonb(this.ctx, v.t, v.v)]);
15358
+ const key2 = castTo(this.ctx, k, "text", { explicit: true }).v;
15359
+ this.entries.push([key2, v.v === null ? JSONB_NULL : datumToJsonb(this.ctx, v.t, v.v)]);
14187
15360
  }
14188
15361
  result() {
14189
15362
  if (!this.any) return tv(this.jsonb ? "jsonb" : "json", null);
@@ -14978,6 +16151,21 @@ var IndexStore = class _IndexStore {
14978
16151
  name;
14979
16152
  unique;
14980
16153
  entries = /* @__PURE__ */ new Map();
16154
+ integerKeys = null;
16155
+ shared = false;
16156
+ ownedBuckets = /* @__PURE__ */ new WeakSet();
16157
+ writableBucket(key2, bucket) {
16158
+ if (this.ownedBuckets.has(bucket)) return bucket;
16159
+ const copy = bucket.slice();
16160
+ this.entries.set(key2, copy);
16161
+ this.ownedBuckets.add(copy);
16162
+ return copy;
16163
+ }
16164
+ detach() {
16165
+ if (!this.shared) return;
16166
+ if (!(this.entries instanceof ForkMap)) this.entries = new Map(this.entries);
16167
+ this.shared = false;
16168
+ }
14981
16169
  constructor(name, unique = false) {
14982
16170
  this.name = name;
14983
16171
  this.unique = unique;
@@ -14985,8 +16173,8 @@ var IndexStore = class _IndexStore {
14985
16173
  get size() {
14986
16174
  return this.entries.size;
14987
16175
  }
14988
- checkUnique(key, rowIdx) {
14989
- const existing = this.entries.get(key);
16176
+ checkUnique(key2, rowIdx) {
16177
+ const existing = this.entries.get(key2);
14990
16178
  if (!existing) return;
14991
16179
  for (const i of existing) {
14992
16180
  if (rowIdx === void 0 || i !== rowIdx) {
@@ -14994,46 +16182,88 @@ var IndexStore = class _IndexStore {
14994
16182
  }
14995
16183
  }
14996
16184
  }
14997
- insert(key, rowIdx) {
14998
- if (this.unique) this.checkUnique(key, rowIdx);
14999
- const existing = this.entries.get(key);
16185
+ insert(key2, rowIdx) {
16186
+ if (this.unique) this.checkUnique(key2, rowIdx);
16187
+ this.detach();
16188
+ this.integerKeys = null;
16189
+ const existing = this.entries.get(key2);
15000
16190
  if (!existing) {
15001
- this.entries.set(key, [rowIdx]);
16191
+ const bucket = [rowIdx];
16192
+ this.ownedBuckets.add(bucket);
16193
+ this.entries.set(key2, bucket);
15002
16194
  return;
15003
16195
  }
15004
16196
  if (existing.includes(rowIdx)) return;
15005
- existing.push(rowIdx);
16197
+ this.writableBucket(key2, existing).push(rowIdx);
15006
16198
  }
15007
- remove(key, rowIdx) {
15008
- const existing = this.entries.get(key);
16199
+ remove(key2, rowIdx) {
16200
+ const existing = this.entries.get(key2);
15009
16201
  if (!existing) return;
15010
16202
  const at = existing.indexOf(rowIdx);
15011
16203
  if (at < 0) return;
15012
- existing.splice(at, 1);
15013
- if (existing.length === 0) this.entries.delete(key);
16204
+ this.detach();
16205
+ this.integerKeys = null;
16206
+ if (existing.length === 1) this.entries.delete(key2);
16207
+ else {
16208
+ const remaining = this.writableBucket(key2, existing);
16209
+ remaining.splice(at, 1);
16210
+ this.entries.set(key2, remaining);
16211
+ }
16212
+ }
16213
+ lookup(key2) {
16214
+ return this.entries.get(key2) ?? [];
15014
16215
  }
15015
- lookup(key) {
15016
- return this.entries.get(key) ?? [];
16216
+ /** Ordered access for a single int2/int4 key (the planner validates the key type). */
16217
+ integerRange(lower, upper, includeLower, includeUpper) {
16218
+ const keys = this.integerKeys ??= [...this.entries].map(([key2, rows]) => ({ value: Number(key2.slice(1)), rows })).sort((a, b) => a.value - b.value);
16219
+ let lo = 0;
16220
+ let hi = keys.length;
16221
+ while (lo < hi) {
16222
+ const mid = lo + hi >>> 1;
16223
+ const value = keys[mid].value;
16224
+ if (value < lower || !includeLower && value === lower) lo = mid + 1;
16225
+ else hi = mid;
16226
+ }
16227
+ const result = [];
16228
+ for (let i = lo; i < keys.length; i++) {
16229
+ const key2 = keys[i];
16230
+ if (key2.value > upper || !includeUpper && key2.value === upper) break;
16231
+ result.push(...key2.rows);
16232
+ }
16233
+ return result.sort((a, b) => a - b);
15017
16234
  }
15018
16235
  clear() {
15019
- this.entries.clear();
16236
+ this.entries = /* @__PURE__ */ new Map();
16237
+ this.shared = false;
16238
+ this.integerKeys = null;
15020
16239
  }
15021
16240
  clone() {
15022
16241
  const copy = new _IndexStore(this.name, this.unique);
15023
- for (const [key, rowids] of this.entries) copy.entries.set(key, [...rowids]);
16242
+ if (this.entries.size >= 4096 && !(this.entries instanceof ForkMap)) this.entries = new ForkMap(this.entries);
16243
+ copy.entries = this.entries instanceof ForkMap ? this.entries.fork() : this.entries;
16244
+ copy.integerKeys = this.integerKeys;
16245
+ copy.shared = true;
16246
+ this.shared = true;
16247
+ this.ownedBuckets = /* @__PURE__ */ new WeakSet();
15024
16248
  return copy;
15025
16249
  }
15026
16250
  };
15027
16251
 
15028
16252
  // src/indexes/maintain.ts
16253
+ function prepareDmlIndexStores(env, table) {
16254
+ if (table.indexStores || !table.frozen || table.triggers.length > 0) return;
16255
+ const specs = uniqueSpecsFor(env, table);
16256
+ if (specs.some((spec) => spec.where || spec.keys.some((key2) => key2.expr))) return;
16257
+ ensureIndexStores(env, table);
16258
+ }
15029
16259
  function ensureIndexStores(env, table) {
15030
16260
  if (table.indexStores) return table.indexStores;
15031
16261
  const stores = /* @__PURE__ */ new Map();
15032
16262
  for (const spec of uniqueSpecsFor(env, table)) {
15033
16263
  const store = new IndexStore(spec.name, true);
15034
16264
  for (let i = 0; i < table.rowCount(); i++) {
15035
- const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
15036
- if (key !== null) store.insert(key, i);
16265
+ const key2 = uniqueKeyOf(env, table, spec, table.rowAt(i));
16266
+ if (key2 !== null) store.insert(key2, i);
15037
16267
  }
15038
16268
  stores.set(spec.name, store);
15039
16269
  }
@@ -15053,8 +16283,8 @@ function indexStoreFor(env, table, spec) {
15053
16283
  if (!store) {
15054
16284
  store = new IndexStore(spec.name, true);
15055
16285
  for (let i = 0; i < table.rowCount(); i++) {
15056
- const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
15057
- if (key !== null) store.insert(key, i);
16286
+ const key2 = uniqueKeyOf(env, table, spec, table.rowAt(i));
16287
+ if (key2 !== null) store.insert(key2, i);
15058
16288
  }
15059
16289
  stores.set(spec.name, store);
15060
16290
  }
@@ -15062,22 +16292,33 @@ function indexStoreFor(env, table, spec) {
15062
16292
  }
15063
16293
  function indexInsertRow(env, table, rowIdx, row) {
15064
16294
  for (const spec of uniqueSpecsFor(env, table)) {
15065
- const key = uniqueKeyOf(env, table, spec, row);
15066
- if (key === null) continue;
15067
- indexStoreFor(env, table, spec).insert(key, rowIdx);
16295
+ const key2 = uniqueKeyOf(env, table, spec, row);
16296
+ if (key2 === null) continue;
16297
+ indexStoreFor(env, table, spec).insert(key2, rowIdx);
15068
16298
  }
15069
16299
  }
15070
16300
  function indexRemoveRow(env, table, rowIdx, row) {
15071
16301
  if (!table.indexStores) return;
15072
16302
  for (const spec of uniqueSpecsFor(env, table)) {
15073
- const key = uniqueKeyOf(env, table, spec, row);
15074
- if (key === null) continue;
15075
- table.indexStores.get(spec.name)?.remove(key, rowIdx);
16303
+ const key2 = uniqueKeyOf(env, table, spec, row);
16304
+ if (key2 === null) continue;
16305
+ table.indexStores.get(spec.name)?.remove(key2, rowIdx);
15076
16306
  }
15077
16307
  }
15078
16308
  function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
15079
- indexRemoveRow(env, table, rowIdx, oldRow);
15080
- indexInsertRow(env, table, rowIdx, newRow);
16309
+ const specs = uniqueSpecsFor(env, table);
16310
+ if (specs.some((spec) => spec.where || spec.keys.some((key2) => key2.expr))) {
16311
+ indexRemoveRow(env, table, rowIdx, oldRow);
16312
+ indexInsertRow(env, table, rowIdx, newRow);
16313
+ return;
16314
+ }
16315
+ for (const spec of specs) {
16316
+ const before = uniqueKeyOf(env, table, spec, oldRow);
16317
+ const after = uniqueKeyOf(env, table, spec, newRow);
16318
+ if (before === after) continue;
16319
+ if (before !== null) table.indexStores?.get(spec.name)?.remove(before, rowIdx);
16320
+ if (after !== null) indexStoreFor(env, table, spec).insert(after, rowIdx);
16321
+ }
15081
16322
  }
15082
16323
  function rebuildTableIndexes(env, table) {
15083
16324
  table.indexStores = null;
@@ -15196,15 +16437,15 @@ function uniqueKeyOf(env, table, spec, row) {
15196
16437
  }
15197
16438
  function checkUnique(env, table, row, selfIdx) {
15198
16439
  for (const spec of uniqueSpecsFor(env, table)) {
15199
- const key = uniqueKeyOf(env, table, spec, row);
15200
- if (key === null) continue;
15201
- indexStoreFor(env, table, spec).checkUnique(key, selfIdx);
16440
+ const key2 = uniqueKeyOf(env, table, spec, row);
16441
+ if (key2 === null) continue;
16442
+ indexStoreFor(env, table, spec).checkUnique(key2, selfIdx);
15202
16443
  }
15203
16444
  }
15204
16445
  function findConflict(env, table, spec, row) {
15205
- const key = uniqueKeyOf(env, table, spec, row);
15206
- if (key === null) return null;
15207
- const hits = indexStoreFor(env, table, spec).lookup(key);
16446
+ const key2 = uniqueKeyOf(env, table, spec, row);
16447
+ if (key2 === null) return null;
16448
+ const hits = indexStoreFor(env, table, spec).lookup(key2);
15208
16449
  return hits.length > 0 ? hits[0] : null;
15209
16450
  }
15210
16451
  function checkForeignKeys(env, table, row) {
@@ -15238,11 +16479,11 @@ function checkForeignKeys(env, table, row) {
15238
16479
  let found = false;
15239
16480
  for (let i = 0; i < refTable.rowCount(); i++) {
15240
16481
  const r = refTable.rowAt(i);
15241
- const key = refIdxs.map((ri, j) => {
16482
+ const key2 = refIdxs.map((ri, j) => {
15242
16483
  const v = r[ri] ?? null;
15243
16484
  return v === null ? "\0N" : datumKey(keyTypes[j], v);
15244
16485
  }).join("");
15245
- if (key === wanted) {
16486
+ if (key2 === wanted) {
15246
16487
  found = true;
15247
16488
  break;
15248
16489
  }
@@ -15294,6 +16535,82 @@ function conjunctions(expr) {
15294
16535
  }
15295
16536
  return [expr];
15296
16537
  }
16538
+ function tryPointRowIndices(env, table, alias, where) {
16539
+ const eqs = [];
16540
+ for (const part of conjunctions(where)) {
16541
+ const eq = equalityAgainstConst(part);
16542
+ if (!eq || !["param", "number_lit", "string_lit", "bool_lit", "null_lit"].includes(eq.valueExpr.type)) return null;
16543
+ if (part.type !== "binop") return null;
16544
+ const column = part.left.type === "colref" ? part.left : part.right;
16545
+ if (column.type !== "colref") return null;
16546
+ if (column.parts.length > 1 && column.parts[column.parts.length - 2] !== alias) return null;
16547
+ eqs.push(eq);
16548
+ }
16549
+ for (const spec of uniqueSpecsFor(env, table)) {
16550
+ if (spec.where || spec.keys.length !== eqs.length || spec.keys.some((key3) => key3.expr) || !eqs.every((eq, index) => eq.column === spec.columnNames[index]))
16551
+ continue;
16552
+ const values = table.columns.map(() => null);
16553
+ let matches2 = true;
16554
+ for (let index = 0; index < spec.keys.length; index++) {
16555
+ const key3 = spec.keys[index];
16556
+ const column = table.columns[key3.colIdx];
16557
+ const eq = eqs[index];
16558
+ if (!column || !eq || column.domain) {
16559
+ matches2 = false;
16560
+ break;
16561
+ }
16562
+ const value = evalExpr(env.ctx, makeEvalScope(env, null), eq.valueExpr);
16563
+ if (value.t !== column.type.id && !(column.type.id === "text" && value.t === "unknown" && typeof value.v === "string")) {
16564
+ matches2 = false;
16565
+ break;
16566
+ }
16567
+ values[key3.colIdx] = value.v;
16568
+ }
16569
+ if (!matches2) continue;
16570
+ const key2 = uniqueKeyOf(env, table, spec, values);
16571
+ return { indices: key2 === null ? [] : indexStoreFor(env, table, spec).lookup(key2), indexName: spec.name };
16572
+ }
16573
+ return null;
16574
+ }
16575
+ function recordIndexScan(env, table, name) {
16576
+ const schema = env.ctx.state.schemas.get(table.schema);
16577
+ const index = schema?.indexes.get(name);
16578
+ if (schema && index) {
16579
+ const lastScan = env.ctx.state.clock().getTime();
16580
+ schema.indexes.set(name, { ...index, scans: (index.scans ?? 0n) + 1n, lastScan });
16581
+ }
16582
+ }
16583
+ function tryRangeRowIndices(env, table, alias, where) {
16584
+ const parts = conjunctions(where);
16585
+ if (parts.length !== 2) return null;
16586
+ const bounds = [];
16587
+ for (const part of parts) {
16588
+ if (part.type !== "binop" || ![">", ">=", "<", "<="].includes(part.op)) return null;
16589
+ const column2 = part.left.type === "colref" ? part.left : part.right;
16590
+ const value = part.left.type === "colref" ? part.right : part.left;
16591
+ if (column2.type !== "colref" || column2.parts.length > 2 || column2.parts.length === 2 && column2.parts[0] !== alias || !["param", "number_lit"].includes(value.type))
16592
+ return null;
16593
+ const op = part.left === column2 ? part.op : { ">": "<", ">=": "<=", "<": ">", "<=": ">=" }[part.op];
16594
+ bounds.push({ column: column2.parts.at(-1), op, value });
16595
+ }
16596
+ const lower = bounds.find((bound) => bound.op === ">" || bound.op === ">=");
16597
+ const upper = bounds.find((bound) => bound.op === "<" || bound.op === "<=");
16598
+ if (!lower || !upper || lower.column !== upper.column) return null;
16599
+ const column = table.columns.find((column2) => column2.name === lower.column);
16600
+ if (!column || column.domain || !["int2", "int4"].includes(column.type.id)) return null;
16601
+ for (const spec of uniqueSpecsFor(env, table)) {
16602
+ if (spec.where || spec.keys.length !== 1 || spec.keys[0].expr || spec.columnNames[0] !== lower.column) continue;
16603
+ const low = evalExpr(env.ctx, makeEvalScope(env, null), lower.value);
16604
+ const high = evalExpr(env.ctx, makeEvalScope(env, null), upper.value);
16605
+ if (low.t !== column.type.id || high.t !== column.type.id || typeof low.v !== "number" || typeof high.v !== "number")
16606
+ return null;
16607
+ return {
16608
+ indices: indexStoreFor(env, table, spec).integerRange(low.v, high.v, lower.op === ">=", upper.op === "<="),
16609
+ indexName: spec.name
16610
+ };
16611
+ }
16612
+ return null;
16613
+ }
15297
16614
  function tryIndexedTableRows(env, table, alias, where) {
15298
16615
  const parts = conjunctions(where);
15299
16616
  const eqs = [];
@@ -15327,15 +16644,10 @@ function tryIndexedTableRows(env, table, alias, where) {
15327
16644
  const v = evalExpr(env.ctx, makeEvalScope(env, scope), eqs[i].valueExpr);
15328
16645
  probeRow[colIdx] = castTo(env.ctx, v, table.columns[colIdx].type.id, {}).v;
15329
16646
  }
15330
- const key = uniqueKeyOf(env, table, spec, probeRow);
15331
- if (key === null) return [];
15332
- const hits = indexStoreFor(env, table, spec).lookup(key);
15333
- const schema = env.ctx.state.schemas.get(table.schema);
15334
- const index = schema?.indexes.get(spec.name);
15335
- if (schema && index) {
15336
- const lastScan = env.ctx.state.clock().getTime();
15337
- schema.indexes.set(spec.name, { ...index, scans: (index.scans ?? 0n) + 1n, lastScan });
15338
- }
16647
+ const key2 = uniqueKeyOf(env, table, spec, probeRow);
16648
+ if (key2 === null) return [];
16649
+ const hits = indexStoreFor(env, table, spec).lookup(key2);
16650
+ recordIndexScan(env, table, spec.name);
15339
16651
  return hits.map((i) => table.rowAt(i));
15340
16652
  }
15341
16653
  function tryIndexedFromItem(env, item, where) {
@@ -16155,17 +17467,17 @@ var Parser = class {
16155
17467
  else this.expectKw("null");
16156
17468
  return { type: "comment", objectKind: kind, objectName: objectName2, comment: comment2 };
16157
17469
  }
16158
- let extra = "";
17470
+ let extra2 = "";
16159
17471
  if (kind === "materialized") {
16160
17472
  this.expectKw("view");
16161
- extra = " view";
17473
+ extra2 = " view";
16162
17474
  }
16163
17475
  const objectName = this.qualifiedName();
16164
17476
  this.expectKw("is");
16165
17477
  let comment = null;
16166
17478
  if (this.peek().type === "string") comment = this.next().value;
16167
17479
  else this.expectKw("null");
16168
- return { type: "comment", objectKind: kind + extra, objectName, comment };
17480
+ return { type: "comment", objectKind: kind + extra2, objectName, comment };
16169
17481
  }
16170
17482
  case "grant":
16171
17483
  case "revoke": {
@@ -17925,10 +19237,10 @@ var Parser = class {
17925
19237
  continue;
17926
19238
  }
17927
19239
  if (this.eatKw("set")) {
17928
- const key = this.ident(true).toLowerCase();
19240
+ const key2 = this.ident(true).toLowerCase();
17929
19241
  if (this.eatKw("from")) {
17930
19242
  this.expectKw("current");
17931
- settings[key] = "__from_current__";
19243
+ settings[key2] = "__from_current__";
17932
19244
  } else {
17933
19245
  if (!this.eatOp("=")) this.expectKw("to");
17934
19246
  const values = [];
@@ -17937,10 +19249,10 @@ var Parser = class {
17937
19249
  if (!["string", "ident", "quoted_ident", "number"].includes(value.type))
17938
19250
  this.errorAt(value, "expected setting value");
17939
19251
  values.push(
17940
- key === "search_path" && /[^a-z0-9_]/.test(value.value) ? `"${value.value.replaceAll('"', '""')}"` : value.value
19252
+ key2 === "search_path" && /[^a-z0-9_]/.test(value.value) ? `"${value.value.replaceAll('"', '""')}"` : value.value
17941
19253
  );
17942
19254
  } while (this.eatPunct(","));
17943
- settings[key] = values.join(", ");
19255
+ settings[key2] = values.join(", ");
17944
19256
  }
17945
19257
  continue;
17946
19258
  }
@@ -18442,10 +19754,10 @@ var Parser = class {
18442
19754
  parseTruncate() {
18443
19755
  this.expectKw("truncate");
18444
19756
  this.eatKw("table");
18445
- const tables = [];
19757
+ const tables2 = [];
18446
19758
  do {
18447
19759
  this.eatKw("only");
18448
- tables.push(this.qualifiedName());
19760
+ tables2.push(this.qualifiedName());
18449
19761
  this.eatOp("*");
18450
19762
  } while (this.eatPunct(","));
18451
19763
  let restartIdentity = false;
@@ -18458,7 +19770,7 @@ var Parser = class {
18458
19770
  let cascade = false;
18459
19771
  if (this.eatKw("cascade")) cascade = true;
18460
19772
  else this.eatKw("restrict");
18461
- return { type: "truncate", tables, restartIdentity, cascade };
19773
+ return { type: "truncate", tables: tables2, restartIdentity, cascade };
18462
19774
  }
18463
19775
  // --- SET / EXPLAIN / COPY -----------------------------------------------------
18464
19776
  parseSet() {
@@ -18581,12 +19893,12 @@ var Parser = class {
18581
19893
  this.pos++;
18582
19894
  if (!this.atPunct(")")) {
18583
19895
  do {
18584
- const key = this.ident(true);
19896
+ const key2 = this.ident(true);
18585
19897
  if (this.atPunct(",") || this.atPunct(")")) {
18586
- options[key] = true;
19898
+ options[key2] = true;
18587
19899
  } else {
18588
19900
  const v = this.next();
18589
- options[key] = v.value;
19901
+ options[key2] = v.value;
18590
19902
  }
18591
19903
  } while (this.eatPunct(","));
18592
19904
  }
@@ -20588,11 +21900,11 @@ function computeOneWindow(ctx, call, spec, rowCount, evalAt) {
20588
21900
  const v = evalAt(i, p);
20589
21901
  keyParts.push(v.v === null ? "\0N" : datumKey(v.t === UNKNOWN ? "text" : v.t, v.v));
20590
21902
  }
20591
- const key = keyParts.join("");
20592
- partitionOf.push(key);
20593
- const list = partitions.get(key) ?? [];
21903
+ const key2 = keyParts.join("");
21904
+ partitionOf.push(key2);
21905
+ const list = partitions.get(key2) ?? [];
20594
21906
  list.push(i);
20595
- partitions.set(key, list);
21907
+ partitions.set(key2, list);
20596
21908
  }
20597
21909
  const results = new Array(rowCount);
20598
21910
  for (const rowIdxs of partitions.values()) {
@@ -20613,8 +21925,8 @@ function computePartition(ctx, call, spec, rowIdxs, evalAt, results) {
20613
21925
  let group = 0;
20614
21926
  for (let pos = 0; pos < n; pos++) {
20615
21927
  if (pos > 0) {
20616
- const same = spec.orderBy.length === 0 || compareKeys(ctx, keys.get(rowIdxs[pos - 1]), keys.get(rowIdxs[pos])) === 0;
20617
- if (!same) group++;
21928
+ const same2 = spec.orderBy.length === 0 || compareKeys(ctx, keys.get(rowIdxs[pos - 1]), keys.get(rowIdxs[pos])) === 0;
21929
+ if (!same2) group++;
20618
21930
  }
20619
21931
  peerGroup[pos] = group;
20620
21932
  }
@@ -20869,10 +22181,10 @@ function computeRankingFunction(ctx, name, call, rowIdxs, peerGroup, _groupCount
20869
22181
  if (buckets <= 0)
20870
22182
  throw pgError("invalid_parameter_value", "argument of ntile must be greater than zero", "22014");
20871
22183
  const base = Math.floor(n / buckets);
20872
- const extra = n % buckets;
22184
+ const extra2 = n % buckets;
20873
22185
  let pos = 0;
20874
22186
  for (let b = 1; b <= buckets && pos < n; b++) {
20875
- const size = base + (b <= extra ? 1 : 0);
22187
+ const size = base + (b <= extra2 ? 1 : 0);
20876
22188
  for (let k = 0; k < size && pos < n; k++, pos++) {
20877
22189
  results[rowIdxs[pos]] = tv("int4", b);
20878
22190
  }
@@ -21311,7 +22623,7 @@ function renameWithAliases(rel4, label, colAliases, what) {
21311
22623
  }));
21312
22624
  return { columns, rows: rel4.rows };
21313
22625
  }
21314
- function materializeItem(env, item, scope) {
22626
+ function materializeItem(env, item, scope, shapeOnly = false) {
21315
22627
  switch (item.type) {
21316
22628
  case "from_table": {
21317
22629
  const label = item.alias ?? item.name[item.name.length - 1];
@@ -21330,7 +22642,7 @@ function materializeItem(env, item, scope) {
21330
22642
  ...table.columns.map((c) => ({ name: c.name, type: c.type.id, mod: c.type.mod, table: label })),
21331
22643
  { name: "xmin", type: "xid", table: label, hidden: true, system: true }
21332
22644
  ],
21333
- rows: table.rows.map((row) => [...row, table.rowXmins.get(row) ?? 2])
22645
+ rows: shapeOnly ? [] : table.serializationRows().map((row) => [...row, table.rowXmins.get(row) ?? 2])
21334
22646
  };
21335
22647
  return { rel: renameWithAliases(rel4, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
21336
22648
  }
@@ -21742,16 +23054,16 @@ function combineJoin(env, kind, left, right, on, using, usingAlias, rangeVars, e
21742
23054
  const rightTypes = hashRightIdxs.map((i) => right.columns[i].type);
21743
23055
  const buckets = /* @__PURE__ */ new Map();
21744
23056
  for (let ri = 0; ri < right.rows.length; ri++) {
21745
- const key = joinKeyFromRow(right.rows[ri], hashRightIdxs, rightTypes, hashKeyTypes, ctx);
21746
- if (key === null) continue;
21747
- const bucket = buckets.get(key);
23057
+ const key2 = joinKeyFromRow(right.rows[ri], hashRightIdxs, rightTypes, hashKeyTypes, ctx);
23058
+ if (key2 === null) continue;
23059
+ const bucket = buckets.get(key2);
21748
23060
  if (bucket) bucket.push(ri);
21749
- else buckets.set(key, [ri]);
23061
+ else buckets.set(key2, [ri]);
21750
23062
  }
21751
23063
  for (const lrow of left.rows) {
21752
23064
  let matched = false;
21753
- const key = joinKeyFromRow(lrow, hashLeftIdxs, leftTypes, hashKeyTypes, ctx);
21754
- const candidates = key === null ? [] : buckets.get(key) ?? [];
23065
+ const key2 = joinKeyFromRow(lrow, hashLeftIdxs, leftTypes, hashKeyTypes, ctx);
23066
+ const candidates = key2 === null ? [] : buckets.get(key2) ?? [];
21755
23067
  for (const ri of candidates) {
21756
23068
  const rrow = right.rows[ri];
21757
23069
  if (!matchRows(lrow, rrow)) continue;
@@ -22252,9 +23564,9 @@ function computeAggregate(env, call, rows, probeScope) {
22252
23564
  const seen = /* @__PURE__ */ new Set();
22253
23565
  effective = [];
22254
23566
  for (const t of tuples) {
22255
- const key = t.args.map((a) => a.v === null ? "\0N" : datumKey(a.t === UNKNOWN ? "text" : a.t, a.v)).join("");
22256
- if (seen.has(key)) continue;
22257
- seen.add(key);
23567
+ const key2 = t.args.map((a) => a.v === null ? "\0N" : datumKey(a.t === UNKNOWN ? "text" : a.t, a.v)).join("");
23568
+ if (seen.has(key2)) continue;
23569
+ seen.add(key2);
22258
23570
  effective.push(t);
22259
23571
  }
22260
23572
  }
@@ -22603,14 +23915,30 @@ function checkPredicateType(env, columns, rangeVars, e, kind, extras) {
22603
23915
  function executeCore(env0, core, orderBy, opts) {
22604
23916
  const env = env0;
22605
23917
  const ctx = env.ctx;
22606
- const source = buildFrom(env, core.from, core.where);
23918
+ const item = core.from.length === 1 ? core.from[0] : null;
23919
+ const pointTable = item?.type === "from_table" && !item.colAliases?.length && !(item.name.length === 1 && env.ctes.has(item.name[0])) ? env.ctx.state.findTable(item.name) : null;
23920
+ const point = pointTable && core.where && item?.type === "from_table" ? tryPointRowIndices(env, pointTable, item.alias ?? item.name[item.name.length - 1], core.where) : null;
23921
+ const range = !point && pointTable && core.where && item?.type === "from_table" ? tryRangeRowIndices(env, pointTable, item.alias ?? item.name[item.name.length - 1], core.where) : null;
23922
+ const access = point ?? range;
23923
+ const source = access && item ? materializeItem(env, item, env.outer, true) : buildFrom(env, core.from, core.where);
22607
23924
  const srcCols = source.rel.columns;
22608
23925
  const rangeVars = source.rangeVars;
22609
23926
  const rowScope = (row) => new RowScope(srcCols, row, env.outer, rangeVars);
22610
23927
  let srcRows = source.rel.rows;
22611
23928
  if (core.where) {
22612
23929
  checkPredicateType(env, srcCols, rangeVars, core.where, "WHERE");
22613
- if (core.from.length === 1) {
23930
+ if (access && pointTable) {
23931
+ pointTable.materializeSlab();
23932
+ srcRows = access.indices.map((index) => {
23933
+ const row = pointTable.rowAt(index);
23934
+ return [...row, pointTable.rowXmins.get(row) ?? 2];
23935
+ });
23936
+ if (range) {
23937
+ const where = core.where;
23938
+ srcRows = srcRows.filter((row) => evalPredicate2(env, rowScope(row), where));
23939
+ }
23940
+ recordIndexScan(env, pointTable, access.indexName);
23941
+ } else if (core.from.length === 1) {
22614
23942
  const indexed = tryIndexedFromItem(env, core.from[0], core.where);
22615
23943
  if (indexed !== null) {
22616
23944
  srcRows = indexed;
@@ -22673,13 +24001,13 @@ function executeCore(env0, core, orderBy, opts) {
22673
24001
  } else {
22674
24002
  for (const row of srcRows) {
22675
24003
  const scope = rowScope(row);
22676
- const key = set.map((e) => {
24004
+ const key2 = set.map((e) => {
22677
24005
  const v = evalScalar(env, scope, e);
22678
24006
  return v.v === null ? "\0N" : datumKey(v.t === UNKNOWN ? "text" : v.t, v.v);
22679
24007
  }).join("");
22680
- const list = groups.get(key);
24008
+ const list = groups.get(key2);
22681
24009
  if (list) list.push(row);
22682
- else groups.set(key, [row]);
24010
+ else groups.set(key2, [row]);
22683
24011
  }
22684
24012
  }
22685
24013
  for (const rows of groups.values()) {
@@ -22791,11 +24119,11 @@ function executeCore(env0, core, orderBy, opts) {
22791
24119
  }
22792
24120
  }
22793
24121
  }
22794
- const item = { name: `__ord${orderExprs.length}`, kind: "expr", colIdx: -1, expr: ob.expr, hidden: true };
24122
+ const item2 = { name: `__ord${orderExprs.length}`, kind: "expr", colIdx: -1, expr: ob.expr, hidden: true };
22795
24123
  const spec = { colIdx: projItems.length, dir, nullsFirst };
22796
- projItems.push(item);
24124
+ projItems.push(item2);
22797
24125
  sortSpecs.push(spec);
22798
- orderExprs.push({ item, spec });
24126
+ orderExprs.push({ item: item2, spec });
22799
24127
  }
22800
24128
  if (core.distinct && !core.distinct.on && sortSpecs.length > 0 && !opts?.hasLimit) {
22801
24129
  const used = new Set(sortSpecs.map((s) => s.colIdx));
@@ -23169,7 +24497,7 @@ var TransactionManager = class {
23169
24497
  return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
23170
24498
  }
23171
24499
  restore(snap) {
23172
- this.state.restoreFrom(snap.state);
24500
+ this.state.restoreFrom(snap.state.cloneShallow());
23173
24501
  this.state.prng.setState(snap.prngState);
23174
24502
  }
23175
24503
  thawOnce() {
@@ -23269,7 +24597,10 @@ function withStatementRollback(env, fn) {
23269
24597
  function requireTargetTable(env, parts, verb) {
23270
24598
  const state = env.ctx.state;
23271
24599
  const table = state.findTable(parts);
23272
- if (table) return state.ensureWritableTable(table);
24600
+ if (table) {
24601
+ prepareDmlIndexStores(env, table);
24602
+ return state.ensureWritableTableForDml(table);
24603
+ }
23273
24604
  const view = state.findView(parts);
23274
24605
  if (view) {
23275
24606
  throw pgError("wrong_object_type", `cannot ${verb} view "${view.name}"`, "42809");
@@ -23437,7 +24768,7 @@ function resolveArbiters(env, table, clause) {
23437
24768
  return matches2.map((spec) => ({ spec }));
23438
24769
  }
23439
24770
  function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, where) {
23440
- const rows = table.mutableRows();
24771
+ const rows = table.writeRows();
23441
24772
  const existing = rows[existingIdx];
23442
24773
  const cols = [
23443
24774
  ...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
@@ -23449,7 +24780,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
23449
24780
  applyUpdateSets(env, table, sets, scope, updated);
23450
24781
  computeGeneratedColumns(env, table, updated);
23451
24782
  table.rowXmins.set(updated, env.ctx.rowVersionXid());
23452
- rows[existingIdx] = updated;
24783
+ table.replaceRow(existingIdx, updated);
23453
24784
  indexUpdateRow(env, table, existingIdx, existing, updated);
23454
24785
  checkNotNull(env, table, updated);
23455
24786
  checkChecks(env, table, updated);
@@ -23461,7 +24792,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
23461
24792
  function executeInsert(env0, stmt) {
23462
24793
  const env = applyWith(env0, stmt.with);
23463
24794
  const table = requireTargetTable(env, stmt.table, "insert into");
23464
- const rows = table.mutableRows();
24795
+ const rows = table.writeRows();
23465
24796
  const label = stmt.alias ?? table.name;
23466
24797
  const colIdxs = insertTargetColumns(env, table, stmt);
23467
24798
  const sourceRows = insertSourceRows(env, stmt, colIdxs);
@@ -23545,6 +24876,7 @@ function executeInsert(env0, stmt) {
23545
24876
  checkForeignKeys(env, table, newRow);
23546
24877
  table.rowXmins.set(newRow, env.ctx.rowVersionXid());
23547
24878
  rows.push(newRow);
24879
+ table.recordDurableRow(newRow);
23548
24880
  indexInsertRow(env, table, rows.length - 1, newRow);
23549
24881
  insertedCount++;
23550
24882
  insertedRows.push(newRow);
@@ -23637,13 +24969,17 @@ function executeUpdate(env0, stmt) {
23637
24969
  const label = stmt.alias ?? table.name;
23638
24970
  fireStatementTriggers(env, table, "before", "update");
23639
24971
  const fromSource = stmt.from.length > 0 ? buildFrom(env, stmt.from) : null;
23640
- const rows = table.mutableRows();
23641
24972
  const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
23642
24973
  const updatedRows = [];
23643
24974
  const replacedRows = [];
23644
24975
  let updateCount = 0;
23645
- for (let ri = 0; ri < rows.length; ri++) {
23646
- const oldRow = rows[ri];
24976
+ const point = !fromSource && stmt.where && table.triggers.length === 0 && !table.columns.some((column) => column.generated || column.domain) && !table.constraints.some((constraint) => constraint.kind === "check") && stmt.sets.every(
24977
+ (set) => set.columns.every((column) => column.subscripts === null && column.fields.length === 0) && "type" in set.value && isPureUpdateValue(set.value)
24978
+ ) && referencingConstraints(env, table).length === 0 ? tryPointRowIndices(env, table, label, stmt.where) : null;
24979
+ const rows = point ? null : table.writeRows();
24980
+ for (let candidate = 0; candidate < (point ? point.indices.length : rows.length); candidate++) {
24981
+ const ri = point ? point.indices[candidate] : candidate;
24982
+ const oldRow = point ? table.rowAt(ri) : rows[ri];
23647
24983
  let matchScope = null;
23648
24984
  if (fromSource) {
23649
24985
  let found = false;
@@ -23669,14 +25005,14 @@ function executeUpdate(env0, stmt) {
23669
25005
  const finalRow = fired.row;
23670
25006
  computeGeneratedColumns(env, table, finalRow);
23671
25007
  table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
23672
- rows[ri] = finalRow;
25008
+ table.replaceRow(ri, finalRow);
23673
25009
  try {
23674
25010
  checkNotNull(env, table, finalRow);
23675
25011
  checkChecks(env, table, finalRow);
23676
25012
  checkUnique(env, table, finalRow, ri);
23677
25013
  checkForeignKeys(env, table, finalRow);
23678
25014
  } catch (err) {
23679
- rows[ri] = oldRow;
25015
+ table.replaceRow(ri, oldRow);
23680
25016
  throw err;
23681
25017
  }
23682
25018
  indexUpdateRow(env, table, ri, oldRow, finalRow);
@@ -23694,12 +25030,29 @@ function executeUpdate(env0, stmt) {
23694
25030
  }
23695
25031
  return commandResult("UPDATE", updateCount);
23696
25032
  }
25033
+ function isPureUpdateValue(expr) {
25034
+ switch (expr.type) {
25035
+ case "param":
25036
+ case "number_lit":
25037
+ case "string_lit":
25038
+ case "bool_lit":
25039
+ case "null_lit":
25040
+ case "colref":
25041
+ return true;
25042
+ case "binop":
25043
+ return isPureUpdateValue(expr.left) && isPureUpdateValue(expr.right);
25044
+ case "unop":
25045
+ return isPureUpdateValue(expr.operand);
25046
+ default:
25047
+ return false;
25048
+ }
25049
+ }
23697
25050
  function executeDelete(env0, stmt) {
23698
25051
  const env = applyWith(env0, stmt.with);
23699
25052
  const table = requireTargetTable(env, stmt.table, "delete from");
23700
25053
  const label = stmt.alias ?? table.name;
23701
25054
  fireStatementTriggers(env, table, "before", "delete");
23702
- const rows = table.mutableRows();
25055
+ const rows = table.writeRows();
23703
25056
  const usingSource = stmt.using.length > 0 ? buildFrom(env, stmt.using) : null;
23704
25057
  const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
23705
25058
  const toDelete = [];
@@ -23729,6 +25082,7 @@ function executeDelete(env0, stmt) {
23729
25082
  if (skipped.has(ri)) continue;
23730
25083
  const row = rows[ri];
23731
25084
  handleReferencedDelete(env, table, row, 0);
25085
+ table.recordDurableDelete(row);
23732
25086
  rows.splice(ri, 1);
23733
25087
  deletedRows.unshift(row);
23734
25088
  }
@@ -23755,12 +25109,12 @@ function rowKeyFor(table, row, columns) {
23755
25109
  }
23756
25110
  return parts.join("");
23757
25111
  }
23758
- function referencingRowIdxs(ref, key) {
25112
+ function referencingRowIdxs(ref, key2) {
23759
25113
  const { table: rt, constraint: con } = ref;
23760
25114
  const out = [];
23761
25115
  for (let i = 0; i < rt.rowCount(); i++) {
23762
25116
  const k = rowKeyFor(rt, rt.rowAt(i), con.columns);
23763
- if (k === key) out.push(i);
25117
+ if (k === key2) out.push(i);
23764
25118
  }
23765
25119
  return out;
23766
25120
  }
@@ -23770,18 +25124,19 @@ function handleReferencedDelete(env, table, row, depth) {
23770
25124
  }
23771
25125
  for (const ref of referencingConstraints(env, table)) {
23772
25126
  const con = ref.constraint;
23773
- const key = rowKeyFor(table, row, con.refColumns);
23774
- if (key === null) continue;
23775
- const idxs = referencingRowIdxs(ref, key);
25127
+ const key2 = rowKeyFor(table, row, con.refColumns);
25128
+ if (key2 === null) continue;
25129
+ const idxs = referencingRowIdxs(ref, key2);
23776
25130
  if (idxs.length === 0) continue;
23777
25131
  const action = con.onDelete ?? "no_action";
23778
- const child = env.ctx.state.ensureWritableTable(ref.table);
23779
- const childRows = child.mutableRows();
25132
+ const child = env.ctx.state.ensureWritableTableForDml(ref.table);
25133
+ const childRows = child.writeRows();
23780
25134
  switch (action) {
23781
25135
  case "cascade": {
23782
25136
  for (let k = idxs.length - 1; k >= 0; k--) {
23783
25137
  const childRow = childRows[idxs[k]];
23784
25138
  handleReferencedDelete(env, child, childRow, depth + 1);
25139
+ child.recordDurableDelete(childRow);
23785
25140
  childRows.splice(idxs[k], 1);
23786
25141
  }
23787
25142
  break;
@@ -23793,7 +25148,7 @@ function handleReferencedDelete(env, table, row, depth) {
23793
25148
  newRow[child.columnIndex(c)] = null;
23794
25149
  }
23795
25150
  child.rowXmins.set(newRow, env.ctx.rowVersionXid());
23796
- childRows[i] = newRow;
25151
+ child.replaceRow(i, newRow);
23797
25152
  checkNotNull(env, child, newRow);
23798
25153
  checkChecks(env, child, newRow);
23799
25154
  }
@@ -23807,7 +25162,7 @@ function handleReferencedDelete(env, table, row, depth) {
23807
25162
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
23808
25163
  }
23809
25164
  child.rowXmins.set(newRow, env.ctx.rowVersionXid());
23810
- childRows[i] = newRow;
25165
+ child.replaceRow(i, newRow);
23811
25166
  checkNotNull(env, child, newRow);
23812
25167
  checkChecks(env, child, newRow);
23813
25168
  checkForeignKeys(env, child, newRow);
@@ -23833,8 +25188,8 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
23833
25188
  const idxs = referencingRowIdxs(ref, oldKey);
23834
25189
  if (idxs.length === 0) continue;
23835
25190
  const action = con.onUpdate ?? "no_action";
23836
- const child = env.ctx.state.ensureWritableTable(ref.table);
23837
- const childRows = child.mutableRows();
25191
+ const child = env.ctx.state.ensureWritableTableForDml(ref.table);
25192
+ const childRows = child.writeRows();
23838
25193
  switch (action) {
23839
25194
  case "cascade": {
23840
25195
  for (const i of idxs) {
@@ -23845,7 +25200,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
23845
25200
  newRow[localIdx] = newRows[r][refIdx] ?? null;
23846
25201
  }
23847
25202
  child.rowXmins.set(newRow, env.ctx.rowVersionXid());
23848
- childRows[i] = newRow;
25203
+ child.replaceRow(i, newRow);
23849
25204
  checkChecks(env, child, newRow);
23850
25205
  }
23851
25206
  break;
@@ -23855,7 +25210,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
23855
25210
  const newRow = childRows[i].slice();
23856
25211
  for (const c of con.columns) newRow[child.columnIndex(c)] = null;
23857
25212
  child.rowXmins.set(newRow, env.ctx.rowVersionXid());
23858
- childRows[i] = newRow;
25213
+ child.replaceRow(i, newRow);
23859
25214
  checkNotNull(env, child, newRow);
23860
25215
  }
23861
25216
  break;
@@ -23868,7 +25223,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
23868
25223
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
23869
25224
  }
23870
25225
  child.rowXmins.set(newRow, env.ctx.rowVersionXid());
23871
- childRows[i] = newRow;
25226
+ child.replaceRow(i, newRow);
23872
25227
  checkForeignKeys(env, child, newRow);
23873
25228
  }
23874
25229
  break;
@@ -24220,12 +25575,12 @@ function executeCopyFromData(env, stmt, data) {
24220
25575
  const delim = String(stmt.options.delimiter ?? (format === "csv" ? "," : " "));
24221
25576
  const nullStr = String(stmt.options.null ?? (format === "csv" ? "" : "\\N"));
24222
25577
  const quote2 = String(stmt.options.quote ?? '"');
24223
- const header = stmt.options.header === true || String(stmt.options.header ?? "").toLowerCase() === "true";
25578
+ const header2 = stmt.options.header === true || String(stmt.options.header ?? "").toLowerCase() === "true";
24224
25579
  let lines = format === "csv" ? splitCsvRecords(data, quote2) : data.split(/\r?\n/);
24225
25580
  const endMarker = lines.indexOf("\\.");
24226
25581
  if (endMarker !== -1) lines = lines.slice(0, endMarker);
24227
25582
  if (lines.length > 0 && lines[lines.length - 1] === "") lines = lines.slice(0, -1);
24228
- if (header && lines.length > 0) lines = lines.slice(1);
25583
+ if (header2 && lines.length > 0) lines = lines.slice(1);
24229
25584
  const valueRows = lines.map((line) => {
24230
25585
  let cells;
24231
25586
  if (format === "csv") {
@@ -24391,6 +25746,8 @@ function openSnapshot(snapshot, options = {}) {
24391
25746
  now = () => new Date(ms);
24392
25747
  }
24393
25748
  const state = snapshot.state.cloneShallow();
25749
+ for (const schema of state.schemas.values())
25750
+ for (const [name, table] of schema.tables) if (table.durableChanges) schema.tables.set(name, table.untrackedFork());
24394
25751
  state.prng = prng;
24395
25752
  state.clock = now;
24396
25753
  return createAdoptedDatabase({
@@ -25044,8 +26401,8 @@ function pgDepend(ctx) {
25044
26401
  for (const index of schema.indexes.values()) {
25045
26402
  const table = schema.tables.get(index.table);
25046
26403
  if (!table || index.isConstraint) continue;
25047
- for (const key of index.columns) {
25048
- const attnum = key.column === null ? 0 : table.columns.findIndex((c) => c.name === key.column) + 1;
26404
+ for (const key2 of index.columns) {
26405
+ const attnum = key2.column === null ? 0 : table.columns.findIndex((c) => c.name === key2.column) + 1;
25049
26406
  if (attnum > 0) rows.push([PG_CLASS_OID, index.oid ?? 0, 0, PG_CLASS_OID, table.oid, attnum, "a"]);
25050
26407
  }
25051
26408
  }
@@ -26659,10 +28016,10 @@ function assertUniqueIndexBuildable(env, table, index, name = index.name) {
26659
28016
  const spec = uniqueSpecOfIndex(table, index);
26660
28017
  const seen = /* @__PURE__ */ new Set();
26661
28018
  for (let i = 0; i < table.rowCount(); i++) {
26662
- const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
26663
- if (key === null) continue;
26664
- if (seen.has(key)) throw pgError("constraint_unique", `could not create unique index "${name}"`, "23505");
26665
- seen.add(key);
28019
+ const key2 = uniqueKeyOf(env, table, spec, table.rowAt(i));
28020
+ if (key2 === null) continue;
28021
+ if (seen.has(key2)) throw pgError("constraint_unique", `could not create unique index "${name}"`, "23505");
28022
+ seen.add(key2);
26666
28023
  }
26667
28024
  }
26668
28025
  function relationMissing(state, parts) {
@@ -27282,8 +28639,8 @@ function executeRenameEnum(env, enumData, newName) {
27282
28639
  const baseType = { ...domain.baseType, id: retype(domain.baseType.id) };
27283
28640
  const defaultExpr = domain.defaultExpr ? rewrite(domain.defaultExpr) : domain.defaultExpr;
27284
28641
  const checks = domain.checks.map((c) => ({ ...c, expr: rewrite(c.expr) }));
27285
- const same = baseType.id === domain.baseType.id && defaultExpr === domain.defaultExpr && checks.every((c, i) => c.expr === domain.checks[i]?.expr);
27286
- if (!same) sch.domains.set(name, { ...domain, baseType, defaultExpr, checks, shareCount: 0 });
28642
+ const same2 = baseType.id === domain.baseType.id && defaultExpr === domain.defaultExpr && checks.every((c, i) => c.expr === domain.checks[i]?.expr);
28643
+ if (!same2) sch.domains.set(name, { ...domain, baseType, defaultExpr, checks, shareCount: 0 });
27287
28644
  }
27288
28645
  for (const overloads of sch.functions.values()) {
27289
28646
  overloads.forEach((fn, index) => {
@@ -27291,15 +28648,15 @@ function executeRenameEnum(env, enumData, newName) {
27291
28648
  const returns = fn.returns === null ? null : retype(fn.returns);
27292
28649
  const returnsTable = fn.returnsTable?.map((c) => ({ ...c, type: retype(c.type) })) ?? null;
27293
28650
  const argDefaults = fn.argDefaults.map((d) => d ? rewrite(d) : d);
27294
- const same = argTypes.every((t, i) => t === fn.argTypes[i]) && returns === fn.returns && returnsTable?.every((c, i) => c.type === fn.returnsTable?.[i]?.type) !== false && argDefaults.every((d, i) => d === fn.argDefaults[i]);
27295
- if (!same) overloads[index] = { ...fn, argTypes, returns, returnsTable, argDefaults };
28651
+ const same2 = argTypes.every((t, i) => t === fn.argTypes[i]) && returns === fn.returns && returnsTable?.every((c, i) => c.type === fn.returnsTable?.[i]?.type) !== false && argDefaults.every((d, i) => d === fn.argDefaults[i]);
28652
+ if (!same2) overloads[index] = { ...fn, argTypes, returns, returnsTable, argDefaults };
27296
28653
  });
27297
28654
  }
27298
28655
  for (const [name, index] of [...sch.indexes]) {
27299
28656
  const columns = index.columns.map((c) => c.expr ? { ...c, expr: rewrite(c.expr) } : c);
27300
28657
  const where = index.where ? rewrite(index.where) : index.where;
27301
- const same = where === index.where && columns.every((c, i) => c === index.columns[i]);
27302
- if (!same) sch.indexes.set(name, { ...index, columns, where });
28658
+ const same2 = where === index.where && columns.every((c, i) => c === index.columns[i]);
28659
+ if (!same2) sch.indexes.set(name, { ...index, columns, where });
27303
28660
  }
27304
28661
  }
27305
28662
  const renamed = state.ensureWritableEnum(enumData);
@@ -27333,9 +28690,9 @@ function typeNameRewriter(isTarget, newName) {
27333
28690
  return { ...record, parts: [...record.parts.slice(0, -1), newName] };
27334
28691
  }
27335
28692
  let out = null;
27336
- for (const [key, value] of Object.entries(record)) {
28693
+ for (const [key2, value] of Object.entries(record)) {
27337
28694
  const next = walk(value);
27338
- if (next !== value) (out ??= { ...record })[key] = next;
28695
+ if (next !== value) (out ??= { ...record })[key2] = next;
27339
28696
  }
27340
28697
  return out ?? node;
27341
28698
  };
@@ -27455,7 +28812,7 @@ function renameSequenceReferences(env, seq, newName) {
27455
28812
  if (Array.isArray(value)) return value.map(rewrite);
27456
28813
  if (value === null || typeof value !== "object") return value;
27457
28814
  const node = value;
27458
- const updated = Object.fromEntries(Object.entries(node).map(([key, child]) => [key, rewrite(child)]));
28815
+ const updated = Object.fromEntries(Object.entries(node).map(([key2, child]) => [key2, rewrite(child)]));
27459
28816
  const rewriteLiteral = (literal2) => {
27460
28817
  if (literal2 && typeof literal2 === "object" && "type" in literal2 && literal2.type === "string_lit" && "value" in literal2 && typeof literal2.value === "string" && matches2(literal2.value)) {
27461
28818
  return { ...literal2, value: [seq.schema, newName].map(quoteIdent).join(".") };
@@ -28097,9 +29454,9 @@ function executeCreateFunction(env, stmt) {
28097
29454
  body,
28098
29455
  rawBody: stmt.body,
28099
29456
  settings: Object.fromEntries(
28100
- Object.entries(stmt.settings ?? {}).map(([key, value]) => [
28101
- key,
28102
- value === "__from_current__" ? state.getSetting(key) ?? "" : value
29457
+ Object.entries(stmt.settings ?? {}).map(([key2, value]) => [
29458
+ key2,
29459
+ value === "__from_current__" ? state.getSetting(key2) ?? "" : value
28103
29460
  ])
28104
29461
  ),
28105
29462
  strict: stmt.strict,
@@ -28873,12 +30230,12 @@ function executeDrop(env, stmt) {
28873
30230
  }
28874
30231
  function executeTruncate(env, stmt) {
28875
30232
  const state = env.ctx.state;
28876
- const tables = stmt.tables.map((parts) => {
30233
+ const tables2 = stmt.tables.map((parts) => {
28877
30234
  const t = state.findTable(parts);
28878
30235
  if (!t) throw pgError("undefined_table", `relation "${parts.join(".")}" does not exist`, "42P01");
28879
30236
  return state.ensureWritableTable(t);
28880
30237
  });
28881
- const set = new Set(tables);
30238
+ const set = new Set(tables2);
28882
30239
  if (stmt.cascade) {
28883
30240
  let grew = true;
28884
30241
  while (grew) {
@@ -29073,6 +30430,24 @@ var Statement = class _Statement {
29073
30430
  this.database = database;
29074
30431
  this.sql = sql;
29075
30432
  this.statements = statements;
30433
+ const observer = database.durabilityObserver;
30434
+ if (observer) {
30435
+ const execute = this.execute;
30436
+ this.execute = (params) => {
30437
+ observer.assertWritable();
30438
+ if (params.some((value) => value instanceof Uint8Array)) observer.exposed();
30439
+ try {
30440
+ const result = execute.call(this, params);
30441
+ if (result.columns.some(
30442
+ (column, index) => column.type === "bytea" && result.rows.some((row) => row[index] !== null && row[index] !== void 0)
30443
+ ))
30444
+ observer.exposed();
30445
+ return result;
30446
+ } finally {
30447
+ observer.changed();
30448
+ }
30449
+ };
30450
+ }
29076
30451
  }
29077
30452
  database;
29078
30453
  statements;
@@ -29105,7 +30480,7 @@ var Statement = class _Statement {
29105
30480
  */
29106
30481
  textResult(...params) {
29107
30482
  const res = this.execute(params);
29108
- const ctx = new EngineCtx(this.database.state);
30483
+ const ctx = new EngineCtx(this.database.engineState);
29109
30484
  return {
29110
30485
  columns: res.columns.map((c) => c.name),
29111
30486
  columnTypes: res.columns.map((c) => c.type === UNKNOWN ? "text" : c.type),
@@ -29142,7 +30517,7 @@ var Statement = class _Statement {
29142
30517
  const refused = this.database.transactions.inTransaction ? refusedInTransactionBlock(stmt) : null;
29143
30518
  if (refused) throw pgError("misuse", `${refused} cannot run inside a transaction block`, "25001");
29144
30519
  const env = {
29145
- ctx: new EngineCtx(this.database.state),
30520
+ ctx: new EngineCtx(this.database.engineState),
29146
30521
  params: typed,
29147
30522
  ctes: /* @__PURE__ */ new Map(),
29148
30523
  outer: null
@@ -29152,12 +30527,13 @@ var Statement = class _Statement {
29152
30527
  return last;
29153
30528
  }
29154
30529
  toRows(res) {
29155
- const ctx = new EngineCtx(this.database.state);
30530
+ const ctx = new EngineCtx(this.database.engineState);
29156
30531
  return res.rows.map((row) => {
29157
30532
  const obj = {};
29158
30533
  for (let i = 0; i < res.columns.length; i++) {
29159
30534
  const c = res.columns[i];
29160
- obj[c.name] = datumToJs(c.type, row[i] ?? null, ctx, this.database.int8Mode);
30535
+ const value = datumToJs(c.type, row[i] ?? null, ctx, this.database.int8Mode);
30536
+ obj[c.name] = value;
29161
30537
  }
29162
30538
  return obj;
29163
30539
  });
@@ -29175,6 +30551,10 @@ function project(point) {
29175
30551
  var Database = class {
29176
30552
  /** @internal Engine catalog, tables, session settings. */
29177
30553
  state;
30554
+ /** @internal Engine-only access; buffered mode observes public state exposure. */
30555
+ engineState;
30556
+ /** @internal Installed only by buffered durability. */
30557
+ durabilityObserver;
29178
30558
  /** Seed used to construct the PRNG. Ignored when {@link randomMode} is `"os"`. */
29179
30559
  seed;
29180
30560
  /** Entropy mode for `random()` / `gen_random_uuid()`. */
@@ -29204,10 +30584,10 @@ var Database = class {
29204
30584
  this.int8Mode = options.int8Mode;
29205
30585
  this.prng = options.prng;
29206
30586
  this.now = options.now;
29207
- this.state = options.state;
29208
- this.state.prng = this.prng;
29209
- this.state.clock = () => this.now();
29210
- this.transactions = txManagerFor(this.state);
30587
+ this.engineState = options.state;
30588
+ this.engineState.prng = this.prng;
30589
+ this.engineState.clock = () => this.now();
30590
+ this.transactions = txManagerFor(this.engineState);
29211
30591
  } else {
29212
30592
  this.seed = options.seed ?? DEFAULT_DATABASE_SEED;
29213
30593
  this.randomMode = options.random ?? "deterministic";
@@ -29215,9 +30595,10 @@ var Database = class {
29215
30595
  this.int8Mode = options.int8 ?? "bigint";
29216
30596
  this.prng = this.randomMode === "os" ? new OsEntropy() : new Prng(this.seed);
29217
30597
  this.now = resolveClock(options.now);
29218
- this.state = new DatabaseState(this.prng, () => this.now());
29219
- this.transactions = txManagerFor(this.state);
30598
+ this.engineState = new DatabaseState(this.prng, () => this.now());
30599
+ this.transactions = txManagerFor(this.engineState);
29220
30600
  }
30601
+ this.state = this.engineState;
29221
30602
  this.timeline = new Timeline({
29222
30603
  now: () => this.now().getTime(),
29223
30604
  ...options.maxCheckpoints !== void 0 ? { maxCheckpoints: options.maxCheckpoints } : {}
@@ -29244,14 +30625,15 @@ var Database = class {
29244
30625
  * a live in-memory snapshot.
29245
30626
  */
29246
30627
  registerFunction(spec) {
30628
+ this.durabilityObserver?.assertWritable();
29247
30629
  this.assertOpen();
29248
30630
  const parts = spec.name.split(".").map((p) => p.trim()).filter((p) => p.length > 0);
29249
30631
  if (parts.length === 0) throw pgError("syntax", "function name is required", "42601");
29250
- const schemaName = (parts.length >= 2 ? parts[0] : this.state.currentSchema()).toLowerCase();
30632
+ const schemaName = (parts.length >= 2 ? parts[0] : this.engineState.currentSchema()).toLowerCase();
29251
30633
  const name = parts[parts.length - 1].toLowerCase();
29252
- const functions = schemaName === "pg_catalog" ? this.state.systemFunctions : this.state.getSchema(schemaName).functions;
29253
- const argTypes = spec.args.map((a) => resolveTypeName(this.state, parseTypeName(a)).column.id);
29254
- const returns = resolveTypeName(this.state, parseTypeName(spec.returns)).column.id;
30634
+ const functions = schemaName === "pg_catalog" ? this.engineState.systemFunctions : this.engineState.getSchema(schemaName).functions;
30635
+ const argTypes = spec.args.map((a) => resolveTypeName(this.engineState, parseTypeName(a)).column.id);
30636
+ const returns = resolveTypeName(this.engineState, parseTypeName(spec.returns)).column.id;
29255
30637
  const fn = {
29256
30638
  name,
29257
30639
  schema: schemaName,
@@ -29265,7 +30647,7 @@ var Database = class {
29265
30647
  body: null,
29266
30648
  rawBody: null,
29267
30649
  strict: spec.strict ?? true,
29268
- oid: this.state.nextOid(),
30650
+ oid: this.engineState.nextOid(),
29269
30651
  jsImpl: spec.fn
29270
30652
  };
29271
30653
  const existing = functions.get(name) ?? [];
@@ -29275,6 +30657,7 @@ var Database = class {
29275
30657
  if (sameSig !== -1) existing[sameSig] = fn;
29276
30658
  else existing.push(fn);
29277
30659
  functions.set(name, existing);
30660
+ this.durabilityObserver?.exposed();
29278
30661
  }
29279
30662
  /** Execute a single-statement query and return all rows keyed by column name. */
29280
30663
  query(sql, params = [], options = {}) {
@@ -29301,6 +30684,7 @@ var Database = class {
29301
30684
  */
29302
30685
  transaction(fn) {
29303
30686
  this.assertOpen();
30687
+ this.durabilityObserver?.assertWritable();
29304
30688
  this.apiTransactionDepth++;
29305
30689
  try {
29306
30690
  if (!this.transactions.inTransaction) {
@@ -29327,6 +30711,7 @@ var Database = class {
29327
30711
  }
29328
30712
  } finally {
29329
30713
  this.apiTransactionDepth--;
30714
+ this.durabilityObserver?.changed();
29330
30715
  }
29331
30716
  }
29332
30717
  /**
@@ -29421,7 +30806,7 @@ var Database = class {
29421
30806
  */
29422
30807
  fault(faults) {
29423
30808
  this.assertOpen();
29424
- Object.assign(this.state.faults, faults);
30809
+ Object.assign(this.engineState.faults, faults);
29425
30810
  }
29426
30811
  /** Close the database. Further SQL throws. Idempotent. */
29427
30812
  close() {
@@ -29431,6 +30816,7 @@ var Database = class {
29431
30816
  }
29432
30817
  if (this.transactions.inTransaction) this.transactions.rollback();
29433
30818
  this.closed = true;
30819
+ this.durabilityObserver?.closed?.();
29434
30820
  }
29435
30821
  /**
29436
30822
  * Execute `COPY table [(cols)] FROM STDIN` with the given text/csv payload
@@ -29449,13 +30835,18 @@ var Database = class {
29449
30835
  if (statements.length !== 1 || !stmt || stmt.type !== "copy" || stmt.direction !== "from") {
29450
30836
  throw pgError("misuse", "copyFrom() requires a single COPY ... FROM STDIN statement", "XX000");
29451
30837
  }
29452
- const env = { ctx: new EngineCtx(this.state), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
29453
- return executeCopyFromData(env, stmt, data).rowCount;
30838
+ this.durabilityObserver?.assertWritable();
30839
+ try {
30840
+ const env = { ctx: new EngineCtx(this.engineState), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
30841
+ return executeCopyFromData(env, stmt, data).rowCount;
30842
+ } finally {
30843
+ this.durabilityObserver?.changed();
30844
+ }
29454
30845
  }
29455
30846
  /** Rows affected by the most recent INSERT / UPDATE / DELETE. */
29456
30847
  get changes() {
29457
30848
  this.assertOpen();
29458
- return this.state.changes;
30849
+ return this.engineState.changes;
29459
30850
  }
29460
30851
  /** @internal */
29461
30852
  assertOpen() {
@@ -29467,7 +30858,7 @@ var Database = class {
29467
30858
  }
29468
30859
  captureLive() {
29469
30860
  return captureSnapshot(
29470
- this.state,
30861
+ this.engineState,
29471
30862
  this.prng,
29472
30863
  this.now,
29473
30864
  this.seed,
@@ -29477,7 +30868,8 @@ var Database = class {
29477
30868
  );
29478
30869
  }
29479
30870
  install(snapshot) {
29480
- this.state.restoreFrom(snapshot.state.cloneShallow());
30871
+ this.durabilityObserver?.exposed();
30872
+ this.engineState.restoreFrom(snapshot.state.cloneShallow());
29481
30873
  this.prng.setState(snapshot.prngState);
29482
30874
  if (!this.systemClock) this.now = fixedClock(new Date(snapshot.nowMs));
29483
30875
  }
@@ -29719,6 +31111,13 @@ var Writer = class {
29719
31111
  this.view.setBigInt64(this.len, value, true);
29720
31112
  this.len += 8;
29721
31113
  }
31114
+ /** Finite integer Number, encoded identically to i64(BigInt(value)) without allocation. */
31115
+ i64Number(value) {
31116
+ this.ensure(8);
31117
+ this.view.setUint32(this.len, value >>> 0, true);
31118
+ this.view.setUint32(this.len + 4, Math.floor(value / 4294967296) >>> 0, true);
31119
+ this.len += 8;
31120
+ }
29722
31121
  f64(value) {
29723
31122
  this.ensure(8);
29724
31123
  this.view.setFloat64(this.len, value, true);
@@ -29729,6 +31128,13 @@ var Writer = class {
29729
31128
  this.buf.set(value, this.len);
29730
31129
  this.len += value.length;
29731
31130
  }
31131
+ /** Reserve one contiguous region. Fill it before any subsequent Writer call can grow the buffer. */
31132
+ block(byteLength) {
31133
+ this.ensure(byteLength);
31134
+ const block = new DataView(this.buf.buffer, this.len, byteLength);
31135
+ this.len += byteLength;
31136
+ return block;
31137
+ }
29732
31138
  /** Length-prefixed UTF-8. */
29733
31139
  text(value) {
29734
31140
  const encoded = utf8Encode(value);
@@ -29741,7 +31147,7 @@ var Writer = class {
29741
31147
  }
29742
31148
  finish() {
29743
31149
  if (this.len === this.buf.length) return this.buf;
29744
- return this.buf.subarray(0, this.len).slice();
31150
+ return this.buf.slice(0, this.len);
29745
31151
  }
29746
31152
  fail() {
29747
31153
  throw new PostgresError("snapshot_format", "invalid or truncated postgres-mem snapshot", "XX000");
@@ -29909,8 +31315,8 @@ function readBjv(r, intern) {
29909
31315
  const count = readVarintU32(r);
29910
31316
  const out = {};
29911
31317
  for (let i = 0; i < count; i++) {
29912
- const key = readBjv(r, intern);
29913
- out[key] = readBjv(r, intern);
31318
+ const key2 = readBjv(r, intern);
31319
+ out[key2] = readBjv(r, intern);
29914
31320
  }
29915
31321
  return out;
29916
31322
  }
@@ -29958,15 +31364,18 @@ function writeInternTable(w, strings) {
29958
31364
  writeVarintU32(w, strings.length);
29959
31365
  if (strings.length === 0) return;
29960
31366
  const offsets = [];
31367
+ const encoded = [];
29961
31368
  let total = 0;
29962
31369
  for (const s of strings) {
29963
31370
  offsets.push(total);
29964
- total += utf8Encode(s).length;
31371
+ const bytes = utf8Encode(s);
31372
+ encoded.push(bytes);
31373
+ total += bytes.length;
29965
31374
  }
29966
31375
  writeVarintU32(w, total);
29967
31376
  const base = w.position + offsets.length * 4;
29968
31377
  for (const off of offsets) w.u32(base + off);
29969
- for (const s of strings) w.textBytes(s);
31378
+ for (const bytes of encoded) w.raw(bytes);
29970
31379
  }
29971
31380
  function readInternTable(r) {
29972
31381
  const count = readVarintU32(r);
@@ -29986,12 +31395,15 @@ function readInternTable(r) {
29986
31395
  }
29987
31396
 
29988
31397
  // src/serialization/codec.ts
29989
- var MAGIC = utf8Encode("PGMM");
31398
+ var MAGIC2 = utf8Encode("PGMM");
29990
31399
  var VERSION = 3;
29991
31400
  function encodeDatabaseState(state, runtime) {
29992
31401
  const pool = new InternPool();
29993
31402
  const schemas = [...state.schemas.values()].sort((a, b) => compareNames(a.name, b.name));
31403
+ const internValues = /* @__PURE__ */ new Map();
29994
31404
  for (const schema of schemas) {
31405
+ const values = [];
31406
+ internValues.set(schema, values);
29995
31407
  pool.count(schema.name);
29996
31408
  for (const table of sortedValues(schema.tables)) {
29997
31409
  pool.count(table.name);
@@ -30002,8 +31414,13 @@ function encodeDatabaseState(state, runtime) {
30002
31414
  pool.count(column.domain ?? "");
30003
31415
  if (column.identity) pool.count(column.identity.sequence);
30004
31416
  }
30005
- for (const row of table.allRows()) {
30006
- for (const d of row) if (typeof d === "string") pool.count(d);
31417
+ for (const row of table.serializationRows()) {
31418
+ for (const d of row) {
31419
+ if (typeof d === "string") {
31420
+ pool.count(d);
31421
+ values.push(d);
31422
+ } else if (d !== null && typeof d === "object" && !(d instanceof Uint8Array)) values.push(d);
31423
+ }
30007
31424
  }
30008
31425
  }
30009
31426
  for (const view of sortedValues(schema.views)) {
@@ -30011,7 +31428,12 @@ function encodeDatabaseState(state, runtime) {
30011
31428
  pool.count(view.schema);
30012
31429
  if (view.matRows) {
30013
31430
  for (const row of view.matRows) {
30014
- for (const d of row) if (typeof d === "string") pool.count(d);
31431
+ for (const d of row) {
31432
+ if (typeof d === "string") {
31433
+ pool.count(d);
31434
+ values.push(d);
31435
+ } else if (d !== null && typeof d === "object" && !(d instanceof Uint8Array)) values.push(d);
31436
+ }
30015
31437
  }
30016
31438
  }
30017
31439
  }
@@ -30044,7 +31466,7 @@ function encodeDatabaseState(state, runtime) {
30044
31466
  }
30045
31467
  }
30046
31468
  pool.finalize();
30047
- forceAllEncodeIntern(pool, state, schemas);
31469
+ forceAllEncodeIntern(pool, state, schemas, internValues);
30048
31470
  const internId = (s) => pool.id(s);
30049
31471
  const forceId = (s) => {
30050
31472
  const id = pool.id(s);
@@ -30052,7 +31474,7 @@ function encodeDatabaseState(state, runtime) {
30052
31474
  return id;
30053
31475
  };
30054
31476
  const w = new Writer(64 * 1024);
30055
- w.raw(MAGIC);
31477
+ w.raw(MAGIC2);
30056
31478
  w.u32(VERSION);
30057
31479
  w.u32(state.snapshotOidCounter());
30058
31480
  w.u32(state.changes);
@@ -30067,13 +31489,13 @@ function encodeDatabaseState(state, runtime) {
30067
31489
  for (const schema of schemas) {
30068
31490
  writeVarintU32(w, forceId(schema.name));
30069
31491
  w.u32(schema.oid);
30070
- const tables = sortedValues(schema.tables);
30071
- writeVarintU32(w, tables.length);
30072
- for (const table of tables) {
31492
+ const tables2 = sortedValues(schema.tables);
31493
+ writeVarintU32(w, tables2.length);
31494
+ for (const table of tables2) {
30073
31495
  writeBjv(
30074
31496
  w,
30075
31497
  {
30076
- xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
31498
+ xmins: table.serializationRows().map((row) => table.rowXmins.get(row) ?? 2),
30077
31499
  name: table.name,
30078
31500
  schema: table.schema,
30079
31501
  columns: table.columns,
@@ -30086,7 +31508,7 @@ function encodeDatabaseState(state, runtime) {
30086
31508
  },
30087
31509
  forceId
30088
31510
  );
30089
- const rows = table.allRows();
31511
+ const rows = table.serializationRows();
30090
31512
  writeVarintU32(w, rows.length);
30091
31513
  for (let c = 0; c < table.columns.length; c++) writePackedColumn(w, rows, c, internId, forceId);
30092
31514
  }
@@ -30142,7 +31564,7 @@ function decodeDatabaseState(snapshot, prng, clock) {
30142
31564
  function decodeInner(snapshot, prng, clock) {
30143
31565
  const r = new Reader(snapshot);
30144
31566
  const magic = r.raw(4);
30145
- if (!magic.every((byte, index) => byte === MAGIC[index])) {
31567
+ if (!magic.every((byte, index) => byte === MAGIC2[index])) {
30146
31568
  throw new PostgresError("snapshot_format", "invalid postgres-mem snapshot magic", "XX000");
30147
31569
  }
30148
31570
  const version = r.u32();
@@ -30412,44 +31834,57 @@ function writePackedColumn(w, rows, col, internId, forceId) {
30412
31834
  }
30413
31835
  if (pack === PACK_FLOAT) {
30414
31836
  w.align4();
31837
+ const block = w.block((n - nulls) * 8);
31838
+ let offset = 0;
30415
31839
  for (let i = 0; i < n; i++) {
30416
31840
  if (bits[i >> 3] & 1 << (i & 7)) continue;
30417
- w.f64(rows[i][col]);
31841
+ block.setFloat64(offset, rows[i][col], true);
31842
+ offset += 8;
30418
31843
  }
30419
31844
  return;
30420
31845
  }
30421
31846
  if (pack === PACK_INT) {
30422
31847
  w.align4();
31848
+ const block = w.block((n - nulls) * 8);
31849
+ let offset = 0;
30423
31850
  for (let i = 0; i < n; i++) {
30424
31851
  if (bits[i >> 3] & 1 << (i & 7)) continue;
30425
31852
  const v = rows[i][col];
30426
- w.i64(typeof v === "bigint" ? v : BigInt(v));
31853
+ if (typeof v === "bigint") block.setBigInt64(offset, v, true);
31854
+ else {
31855
+ block.setUint32(offset, v >>> 0, true);
31856
+ block.setUint32(offset + 4, Math.floor(v / 4294967296) >>> 0, true);
31857
+ }
31858
+ offset += 8;
30427
31859
  }
30428
31860
  return;
30429
31861
  }
30430
31862
  if (pack === PACK_TEXT_INTERN) {
30431
31863
  w.align4();
31864
+ const block = w.block((n - nulls) * 4);
31865
+ let offset = 0;
30432
31866
  for (let i = 0; i < n; i++) {
30433
31867
  if (bits[i >> 3] & 1 << (i & 7)) continue;
30434
- w.u32(internId(rows[i][col]));
31868
+ block.setUint32(offset, internId(rows[i][col]), true);
31869
+ offset += 4;
30435
31870
  }
30436
31871
  return;
30437
31872
  }
30438
31873
  if (pack === PACK_TEXT_INLINE) {
30439
31874
  const offsets = [];
31875
+ const encoded = [];
30440
31876
  let blobLen = 0;
30441
31877
  for (let i = 0; i < n; i++) {
30442
31878
  if (bits[i >> 3] & 1 << (i & 7)) continue;
30443
31879
  offsets.push(blobLen);
30444
- blobLen += utf8Encode(rows[i][col]).length;
31880
+ const bytes = utf8Encode(rows[i][col]);
31881
+ encoded.push(bytes);
31882
+ blobLen += bytes.length;
30445
31883
  }
30446
31884
  writeVarintU32(w, offsets.length);
30447
31885
  for (const off of offsets) writeVarintU32(w, off);
30448
31886
  writeVarintU32(w, blobLen);
30449
- for (let i = 0; i < n; i++) {
30450
- if (bits[i >> 3] & 1 << (i & 7)) continue;
30451
- w.textBytes(rows[i][col]);
30452
- }
31887
+ for (const bytes of encoded) w.raw(bytes);
30453
31888
  return;
30454
31889
  }
30455
31890
  if (pack === PACK_BLOB) {
@@ -30530,10 +31965,10 @@ function writeSchemaCatalog(w, schema, forceId) {
30530
31965
  const domains = sortedValues(schema.domains);
30531
31966
  writeVarintU32(w, domains.length);
30532
31967
  for (const d of domains) writeBjv(w, stripRuntimeFields(d), forceId);
30533
- const functionEntries = [...schema.functions.entries()].map(([key, overloads]) => [key, overloads.filter((f) => f.language !== "js")]).filter((entry) => entry[1].length > 0).sort((a, b) => compareNames(a[0], b[0]));
31968
+ const functionEntries = [...schema.functions.entries()].map(([key2, overloads]) => [key2, overloads.filter((f) => f.language !== "js")]).filter((entry) => entry[1].length > 0).sort((a, b) => compareNames(a[0], b[0]));
30534
31969
  writeVarintU32(w, functionEntries.length);
30535
- for (const [key, overloads] of functionEntries) {
30536
- writeVarintU32(w, forceId(key));
31970
+ for (const [key2, overloads] of functionEntries) {
31971
+ writeVarintU32(w, forceId(key2));
30537
31972
  writeVarintU32(w, overloads.length);
30538
31973
  for (const f of overloads) {
30539
31974
  const { jsImpl: _js, ...meta } = f;
@@ -30596,11 +32031,11 @@ function readSchemaCatalog(r, schema, intern, str) {
30596
32031
  }
30597
32032
  const fnCount = readVarintU32(r);
30598
32033
  for (let i = 0; i < fnCount; i++) {
30599
- const key = str(readVarintU32(r));
32034
+ const key2 = str(readVarintU32(r));
30600
32035
  const overloadCount = readVarintU32(r);
30601
32036
  const overloads = [];
30602
32037
  for (let oi = 0; oi < overloadCount; oi++) overloads.push(readBjv(r, intern));
30603
- schema.functions.set(key, overloads);
32038
+ schema.functions.set(key2, overloads);
30604
32039
  }
30605
32040
  const indexCount = readVarintU32(r);
30606
32041
  for (let i = 0; i < indexCount; i++) {
@@ -30649,7 +32084,7 @@ function compareNames(a, b) {
30649
32084
  function sortedValues(map) {
30650
32085
  return [...map.values()].sort((a, b) => compareNames(a.name, b.name));
30651
32086
  }
30652
- function forceAllEncodeIntern(pool, state, schemas) {
32087
+ function forceAllEncodeIntern(pool, state, schemas, internValues) {
30653
32088
  forceSchemaIntern(pool, state, schemas);
30654
32089
  for (const [k, v] of state.settings) {
30655
32090
  pool.forceId(k);
@@ -30661,18 +32096,7 @@ function forceAllEncodeIntern(pool, state, schemas) {
30661
32096
  }
30662
32097
  for (const schema of schemas) {
30663
32098
  pool.forceId(schema.name);
30664
- for (const table of sortedValues(schema.tables)) {
30665
- for (const row of table.allRows()) {
30666
- for (const d of row) forceDatumIntern(pool, d);
30667
- }
30668
- }
30669
- for (const view of sortedValues(schema.views)) {
30670
- if (view.matRows) {
30671
- for (const row of view.matRows) {
30672
- for (const d of row) forceDatumIntern(pool, d);
30673
- }
30674
- }
30675
- }
32099
+ for (const value of internValues.get(schema) ?? []) forceDatumIntern(pool, value);
30676
32100
  }
30677
32101
  }
30678
32102
  function forceDatumIntern(pool, value) {
@@ -30717,7 +32141,8 @@ function forceSchemaIntern(pool, state, schemas) {
30717
32141
  pool.forceId(table.name);
30718
32142
  pool.forceId(table.schema);
30719
32143
  forceBjvStrings(pool, {
30720
- xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
32144
+ // Only strings are interned here. Traversing every numeric xmin cannot add an id.
32145
+ xmins: [],
30721
32146
  name: table.name,
30722
32147
  schema: table.schema,
30723
32148
  columns: table.columns,
@@ -30765,8 +32190,8 @@ function forceSchemaIntern(pool, state, schemas) {
30765
32190
  pool.forceId(idx.table);
30766
32191
  forceBjvStrings(pool, indexBjv(idx));
30767
32192
  }
30768
- for (const [key, overloads] of schema.functions) {
30769
- pool.forceId(key);
32193
+ for (const [key2, overloads] of schema.functions) {
32194
+ pool.forceId(key2);
30770
32195
  for (const fn of overloads) {
30771
32196
  if (fn.language === "js") continue;
30772
32197
  const { jsImpl: _js, ...meta } = fn;
@@ -30796,6 +32221,265 @@ function forceBjvStrings(pool, value) {
30796
32221
  }
30797
32222
  registerCodec({ encodeDatabaseState, decodeDatabaseState });
30798
32223
 
32224
+ // src/api/buffered.ts
32225
+ var key = (schema, name) => JSON.stringify([schema, name]);
32226
+ var same = (a, b) => a.length === b.length && a.every((byte, index) => byte === b[index]);
32227
+ function tables(state) {
32228
+ return new Map(
32229
+ [...state.schemas.values()].flatMap(
32230
+ (schema) => [...schema.tables.values()].map((table) => [key(schema.name, table.name), table])
32231
+ )
32232
+ );
32233
+ }
32234
+ function extra(state) {
32235
+ return { xidCounter: state.xidCounter, sequenceCurrval: [...state.sequenceCurrval], prepared: [...state.prepared] };
32236
+ }
32237
+ function encodeBufferedCheckpoint(db) {
32238
+ const snap = captureSnapshot(db.engineState, db.prng, db.now, db.seed, db.randomMode, db.systemClock, db.int8Mode);
32239
+ const info = [...tables(snap.state).values()].map((table) => ({
32240
+ schema: table.schema,
32241
+ name: table.name,
32242
+ ids: Array.from({ length: table.rowCount() }, (_, id) => id),
32243
+ deleted: [],
32244
+ nextId: table.rowCount()
32245
+ }));
32246
+ return encodeDurableCheckpoint(
32247
+ packDurableRecord({ ...extra(snap.state), checkpoint: true, tables: info }, snap.encode())
32248
+ );
32249
+ }
32250
+ function decodeBufferedDatabase(bytes, options) {
32251
+ const records = readDurableJournal(bytes);
32252
+ const db = records ? recover(records, options) : Snapshot.decode(bytes).open(options);
32253
+ for (const table of tables(db.engineState).values()) table.disableDurabilityTracking();
32254
+ return db;
32255
+ }
32256
+ function recover(records, options) {
32257
+ let db;
32258
+ const rows = /* @__PURE__ */ new Map();
32259
+ try {
32260
+ for (const bytes of records) {
32261
+ const { metadata, snapshot } = unpackDurableRecord(bytes);
32262
+ const next = Snapshot.decode(snapshot).open(options);
32263
+ next.engineState.xidCounter = metadata.xidCounter;
32264
+ next.engineState.sequenceCurrval = new Map(metadata.sequenceCurrval);
32265
+ next.engineState.prepared = new Map(metadata.prepared);
32266
+ if (metadata.checkpoint) rows.clear();
32267
+ else if (!db) throw new Error("Missing buffered checkpoint");
32268
+ const changes = tables(next.engineState);
32269
+ for (const info of metadata.tables) {
32270
+ const name = key(info.schema, info.name);
32271
+ const table = changes.get(name);
32272
+ if (!table || table.rowCount() !== info.ids.length) throw new Error("Invalid incremental row IDs");
32273
+ let target = rows.get(name);
32274
+ if (!target) {
32275
+ target = { rows: /* @__PURE__ */ new Map(), nextId: 0 };
32276
+ rows.set(name, target);
32277
+ }
32278
+ target.nextId = info.nextId;
32279
+ for (const id of info.deleted) target.rows.delete(id);
32280
+ table.materializeSlab();
32281
+ for (let i = 0; i < info.ids.length; i++) {
32282
+ const row = table.rowAt(i);
32283
+ target.rows.set(info.ids[i], { row, xmin: table.rowXmins.get(row) ?? 2 });
32284
+ }
32285
+ }
32286
+ db?.close();
32287
+ db = next;
32288
+ }
32289
+ if (!db) throw new Error("Missing buffered checkpoint");
32290
+ for (const [name, table] of tables(db.engineState)) {
32291
+ const stored = rows.get(name);
32292
+ if (!stored) throw new Error("Missing buffered table");
32293
+ const ordered = [...stored.rows].sort((a, b) => a[0] - b[0]);
32294
+ table.rows = ordered.map(([, value]) => value.row);
32295
+ table.rowXmins = new WeakMap(ordered.map(([, value]) => [value.row, value.xmin]));
32296
+ table.indexStores = null;
32297
+ table.enableDurabilityTracking(
32298
+ ordered.map(([id]) => id),
32299
+ stored.nextId
32300
+ );
32301
+ }
32302
+ const snap = captureSnapshot(db.engineState, db.prng, db.now, db.seed, db.randomMode, db.systemClock, db.int8Mode);
32303
+ const result = snap.open(options);
32304
+ for (const [name, table] of tables(result.engineState)) {
32305
+ const stored = rows.get(name);
32306
+ const ids = [...stored.rows.keys()].sort((a, b) => a - b);
32307
+ table.enableDurabilityTracking(ids, stored.nextId);
32308
+ }
32309
+ db.close();
32310
+ return result;
32311
+ } catch (error) {
32312
+ db?.close();
32313
+ throw error;
32314
+ }
32315
+ }
32316
+ function codec2(options, closeBackend) {
32317
+ let exposed = false;
32318
+ function capture(db, previous, checkpoint, baselineOnly = false) {
32319
+ db.assertOpen();
32320
+ if (db.transactions.inTransaction)
32321
+ throw pgError("transaction_state", "cannot persist during a transaction", "25P01");
32322
+ const currentTables = tables(db.engineState);
32323
+ const shape = packDurableRecord(
32324
+ [...currentTables].map(([name, table]) => [name, table.oid, table.columns, table.constraints, table.triggers]),
32325
+ new Uint8Array()
32326
+ );
32327
+ checkpoint ||= exposed || !previous || !same(shape, previous.shape) || [...currentTables].some(
32328
+ ([name, table]) => table.durableUnsafe || !table.durableChanges || table.durableEpoch !== previous?.tables.get(name)?.durableEpoch
32329
+ );
32330
+ for (const table of currentTables.values()) table.enableDurabilityTracking();
32331
+ const snap = captureSnapshot(db.engineState, db.prng, db.now, db.seed, db.randomMode, db.systemClock, db.int8Mode);
32332
+ const capturedTables = tables(snap.state);
32333
+ const metadataState = snap.state.cloneShallow();
32334
+ for (const schema of metadataState.schemas.values())
32335
+ schema.tables = new Map([...schema.tables].map(([name, table]) => [name, table.emptyForDurability()]));
32336
+ const runtime = { prngState: snap.prngState, nowMs: snap.nowMs };
32337
+ const extras = extra(snap.state);
32338
+ const metadata = packDurableRecord(extras, encodeDatabaseState(metadataState, runtime));
32339
+ const token = {
32340
+ metadata,
32341
+ shape,
32342
+ tables: new Map(
32343
+ [...capturedTables].map(([name, table]) => [
32344
+ name,
32345
+ {
32346
+ durableChanges: table.durableChanges.fork(),
32347
+ durableEpoch: table.durableEpoch
32348
+ }
32349
+ ])
32350
+ )
32351
+ };
32352
+ if (baselineOnly) return { token, checkpoint: true };
32353
+ const info = [];
32354
+ let changed = false;
32355
+ for (const [name, table] of capturedTables) {
32356
+ const ids = [];
32357
+ const deleted = [];
32358
+ if (checkpoint) {
32359
+ for (let i = 0; i < table.rowCount(); i++) ids.push(table.durableRowId(table.rowAt(i)));
32360
+ } else {
32361
+ const destination = metadataState.schemas.get(table.schema).tables.get(table.name);
32362
+ const destinationRows = destination.writeRows();
32363
+ for (const change of table.durableChanges.changes(previous?.tables.get(name)?.durableChanges ?? void 0)) {
32364
+ if (change.deleted) continue;
32365
+ changed = true;
32366
+ if (change.value.row) {
32367
+ ids.push(change.key);
32368
+ destinationRows.push(change.value.row);
32369
+ destination.rowXmins.set(change.value.row, change.value.xmin);
32370
+ } else deleted.push(change.key);
32371
+ }
32372
+ }
32373
+ info.push({ schema: table.schema, name: table.name, ids, deleted, nextId: table.durableNextId });
32374
+ }
32375
+ if (!checkpoint && !changed && previous && same(metadata, previous.metadata)) return { token, checkpoint: false };
32376
+ return {
32377
+ token,
32378
+ checkpoint,
32379
+ bytes: packDurableRecord(
32380
+ { ...extras, checkpoint, tables: info },
32381
+ checkpoint ? snap.encode() : encodeDatabaseState(metadataState, runtime)
32382
+ )
32383
+ };
32384
+ }
32385
+ return {
32386
+ create: () => new Database(options.databaseOptions),
32387
+ decode: (bytes) => decodeBufferedDatabase(bytes, options.databaseOptions),
32388
+ decodeJournal: (records) => recover(records, options.databaseOptions),
32389
+ encode: (db) => captureSnapshot(db.engineState, db.prng, db.now, db.seed, db.randomMode, db.systemClock, db.int8Mode).encode(),
32390
+ canCapture: (db) => !db.transactions.inTransaction,
32391
+ capture,
32392
+ baseline: (db) => capture(db, void 0, true, true).token,
32393
+ acknowledge(db, token) {
32394
+ const liveTables = tables(db.engineState);
32395
+ for (const [name, table] of token.tables) {
32396
+ const live = liveTables.get(name);
32397
+ if (!live?.durableChanges || !table.durableChanges || live.durableEpoch !== table.durableEpoch) continue;
32398
+ for (const [id, row] of table.durableChanges)
32399
+ if (live.durableChanges.get(id) === row) live.durableChanges.delete(id);
32400
+ }
32401
+ },
32402
+ subscribe(db, observer) {
32403
+ const descriptor = Object.getOwnPropertyDescriptor(db, "state");
32404
+ db.durabilityObserver = observer;
32405
+ Object.defineProperty(db, "state", {
32406
+ enumerable: true,
32407
+ configurable: true,
32408
+ get() {
32409
+ exposed = true;
32410
+ observer.exposed();
32411
+ return db.engineState;
32412
+ }
32413
+ });
32414
+ return () => {
32415
+ db.durabilityObserver = void 0;
32416
+ Object.defineProperty(db, "state", descriptor);
32417
+ };
32418
+ },
32419
+ async close(db) {
32420
+ db.close();
32421
+ await closeBackend();
32422
+ }
32423
+ };
32424
+ }
32425
+ async function openBufferedDurableDatabase(options) {
32426
+ const backend = options.backend ?? new IndexedDBDurabilityBackend({ durability: "relaxed" });
32427
+ const closeBackend = async () => {
32428
+ if (!options.backend && backend instanceof IndexedDBDurabilityBackend) await backend.close();
32429
+ };
32430
+ try {
32431
+ return await openBufferedDurable({
32432
+ ...options,
32433
+ backend,
32434
+ lifecycle: options.lifecycle ?? browserDurabilityLifecycle,
32435
+ codec: codec2(options, closeBackend)
32436
+ });
32437
+ } catch (error) {
32438
+ await closeBackend();
32439
+ throw error;
32440
+ }
32441
+ }
32442
+
32443
+ // src/api/durable.ts
32444
+ function openDurableDatabase(options) {
32445
+ const backend = options.backend ?? new IndexedDBDurabilityBackend();
32446
+ let journal = false;
32447
+ return openDurable({
32448
+ key: options.key,
32449
+ backend,
32450
+ pageSize: options.pageSize,
32451
+ codec: {
32452
+ create: () => new Database(options.databaseOptions),
32453
+ decode: (bytes) => {
32454
+ journal = isDurableJournal(bytes);
32455
+ return decodeBufferedDatabase(bytes, options.databaseOptions);
32456
+ },
32457
+ encode: (db) => {
32458
+ db.assertOpen();
32459
+ if (db.transactions.inTransaction)
32460
+ throw pgError("transaction_state", "cannot persist during a transaction", "25P01");
32461
+ if (journal) return encodeBufferedCheckpoint(db);
32462
+ return captureSnapshot(
32463
+ db.engineState,
32464
+ db.prng,
32465
+ db.now,
32466
+ db.seed,
32467
+ db.randomMode,
32468
+ db.systemClock,
32469
+ db.int8Mode
32470
+ ).encode();
32471
+ },
32472
+ close: async (db) => {
32473
+ db.close();
32474
+ if (!options.backend && backend instanceof IndexedDBDurabilityBackend) await backend.close();
32475
+ }
32476
+ }
32477
+ }).catch(async (error) => {
32478
+ if (!options.backend && backend instanceof IndexedDBDurabilityBackend) await backend.close();
32479
+ throw error;
32480
+ });
32481
+ }
32482
+
30799
32483
  // src/api/schema-report.ts
30800
32484
  var bounded = (value, fallback2, max) => {
30801
32485
  if (value === void 0) return fallback2;
@@ -30809,7 +32493,7 @@ function analyzeSchema(sql, options = {}) {
30809
32493
  const diagnosticLimit = bounded(options.maxDiagnostics, 100, 1e3);
30810
32494
  const report = {
30811
32495
  engine: "mockingbird-postgres",
30812
- version: true ? "3.11.0" : "source-tree",
32496
+ version: true ? "3.12.0" : "source-tree",
30813
32497
  statements: 0,
30814
32498
  accepted: 0,
30815
32499
  compatible: null,
@@ -30974,9 +32658,23 @@ function analyzeSchema(sql, options = {}) {
30974
32658
  }
30975
32659
  export {
30976
32660
  Database,
32661
+ DurabilityConflictError,
32662
+ IndexedDBDurabilityBackend,
32663
+ LocalStorageDurabilityBackend,
32664
+ MemoryDurabilityBackend,
30977
32665
  PostgresError,
30978
32666
  Snapshot,
30979
32667
  Statement,
30980
- analyzeSchema
32668
+ analyzeSchema,
32669
+ browserDurabilityLifecycle,
32670
+ encodeDurableCheckpoint,
32671
+ openBufferedDurable,
32672
+ openBufferedDurableDatabase,
32673
+ openDurable,
32674
+ openDurableDatabase,
32675
+ packDurableRecord,
32676
+ readDurableJournal,
32677
+ unpackDurableRecord,
32678
+ withDurability
30981
32679
  };
30982
32680
  //# sourceMappingURL=index.js.map