@crvouga/mockingbird-service-postgres 3.11.0 → 3.12.1

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.
@@ -1,6 +1,252 @@
1
1
  // src/wire/index.ts
2
2
  import { createServer } from "node:net";
3
3
 
4
+ // ../../core/dist/fork-map.js
5
+ var ForkMap = class _ForkMap {
6
+ owner = {};
7
+ index = { owner: this.owner, groups: [] };
8
+ order = { owner: this.owner, cells: [] };
9
+ shift = 0;
10
+ length = 0;
11
+ count = 0;
12
+ nextSequence = 0;
13
+ layout = 0;
14
+ cleared = 0;
15
+ version = 0;
16
+ constructor(entries) {
17
+ if (entries)
18
+ for (const [key, value] of entries)
19
+ this.set(key, value);
20
+ }
21
+ get size() {
22
+ return this.count;
23
+ }
24
+ get [Symbol.toStringTag]() {
25
+ return "Map";
26
+ }
27
+ fork() {
28
+ const copy = new _ForkMap();
29
+ copy.index = this.index;
30
+ copy.order = this.order;
31
+ copy.shift = this.shift;
32
+ copy.length = this.length;
33
+ copy.count = this.count;
34
+ copy.nextSequence = this.nextSequence;
35
+ this.owner = {};
36
+ return copy;
37
+ }
38
+ /** Visit changed hash buckets only. Values must be replaced, rather than mutated in place. */
39
+ *changes(previous) {
40
+ if (previous?.index === this.index)
41
+ return;
42
+ for (let group = 0; group < 32; group++) {
43
+ const currentGroup = this.index.groups[group];
44
+ const oldGroup = previous?.index.groups[group];
45
+ if (currentGroup === oldGroup)
46
+ continue;
47
+ for (let bucket = 0; bucket < 32; bucket++) {
48
+ const current = currentGroup?.buckets[bucket]?.data;
49
+ const old = oldGroup?.buckets[bucket]?.data;
50
+ if (current === old)
51
+ continue;
52
+ if (current)
53
+ for (const [key, entry] of current) {
54
+ const before = old?.get(key);
55
+ if (!before || !Object.is(before.value, entry.value) || before.sequence !== entry.sequence)
56
+ yield { key, value: entry.value, deleted: false };
57
+ }
58
+ if (old) {
59
+ for (const key of old.keys())
60
+ if (!current?.has(key))
61
+ yield { key, deleted: true };
62
+ }
63
+ }
64
+ }
65
+ }
66
+ get(key) {
67
+ return this.find(key)?.value;
68
+ }
69
+ has(key) {
70
+ return this.find(key) !== void 0;
71
+ }
72
+ set(key, value) {
73
+ if (typeof key === "number" && key === 0)
74
+ key = 0;
75
+ const hash = hashKey(key);
76
+ const existing = this.bucket(hash)?.get(key);
77
+ if (existing && Object.is(existing.value, value))
78
+ return this;
79
+ const entry = existing ? { ...existing, value } : { key, value, position: this.length++, sequence: this.nextSequence++ };
80
+ this.writableBucket(hash).set(key, entry);
81
+ this.writeOrder(entry.position, entry);
82
+ if (!existing)
83
+ this.count++;
84
+ this.version++;
85
+ return this;
86
+ }
87
+ delete(key) {
88
+ const hash = hashKey(key);
89
+ const entry = this.bucket(hash)?.get(key);
90
+ if (!entry)
91
+ return false;
92
+ this.writableBucket(hash).delete(key);
93
+ this.writeOrder(entry.position, void 0);
94
+ this.count--;
95
+ this.version++;
96
+ if (this.length > 1024 && this.length > this.count * 2)
97
+ this.compact();
98
+ return true;
99
+ }
100
+ clear() {
101
+ this.index = { owner: this.owner, groups: [] };
102
+ this.order = { owner: this.owner, cells: [] };
103
+ this.shift = this.length = this.count = this.nextSequence = 0;
104
+ this.layout++;
105
+ this.cleared++;
106
+ this.version++;
107
+ }
108
+ entries() {
109
+ return this.iterate(0);
110
+ }
111
+ keys() {
112
+ return this.iterate(1);
113
+ }
114
+ values() {
115
+ return this.iterate(2);
116
+ }
117
+ [Symbol.iterator]() {
118
+ return this.entries();
119
+ }
120
+ forEach(callback, thisArg) {
121
+ for (const [key, value] of this)
122
+ callback.call(thisArg, value, key, this);
123
+ }
124
+ find(key) {
125
+ return this.bucket(hashKey(key))?.get(key);
126
+ }
127
+ bucket(hash) {
128
+ return this.index.groups[hash >>> 5 & 31]?.buckets[hash & 31]?.data;
129
+ }
130
+ writableBucket(hash) {
131
+ if (this.index.owner !== this.owner)
132
+ this.index = { owner: this.owner, groups: this.index.groups.slice() };
133
+ const groupIndex = hash >>> 5 & 31;
134
+ let group = this.index.groups[groupIndex];
135
+ if (!group || group.owner !== this.owner) {
136
+ group = { owner: this.owner, buckets: group?.buckets.slice() ?? [] };
137
+ this.index.groups[groupIndex] = group;
138
+ }
139
+ const at = hash & 31;
140
+ let bucket = group.buckets[at];
141
+ if (!bucket || bucket.owner !== this.owner) {
142
+ bucket = { owner: this.owner, data: bucket ? this.copyBucket(bucket.data) : /* @__PURE__ */ new Map() };
143
+ group.buckets[at] = bucket;
144
+ }
145
+ return bucket.data;
146
+ }
147
+ copyBucket(bucket) {
148
+ return new Map(bucket);
149
+ }
150
+ leaf(position) {
151
+ let node = this.order;
152
+ for (let shift = this.shift; shift > 0; shift -= 5)
153
+ node = node.cells[Math.floor(position / 2 ** shift) & 31];
154
+ return node;
155
+ }
156
+ writeOrder(position, entry) {
157
+ while (position >= 2 ** (this.shift + 5)) {
158
+ this.order = { owner: this.owner, cells: [this.order] };
159
+ this.shift += 5;
160
+ }
161
+ if (this.order.owner !== this.owner)
162
+ this.order = { owner: this.owner, cells: this.order.cells.slice() };
163
+ let node = this.order;
164
+ for (let shift = this.shift; shift > 0; shift -= 5) {
165
+ const at = Math.floor(position / 2 ** shift) & 31;
166
+ let child = node.cells[at];
167
+ if (!child || child.owner !== this.owner) {
168
+ child = { owner: this.owner, cells: child?.cells.slice() ?? [] };
169
+ node.cells[at] = child;
170
+ }
171
+ node = child;
172
+ }
173
+ node.cells[position & 31] = entry;
174
+ }
175
+ compact() {
176
+ const entries = [];
177
+ for (let position = 0; position < this.length; position++) {
178
+ const entry = this.leaf(position).cells[position & 31];
179
+ if (entry)
180
+ entries.push(entry);
181
+ }
182
+ this.index = { owner: this.owner, groups: [] };
183
+ this.order = { owner: this.owner, cells: [] };
184
+ this.shift = this.length = this.count = 0;
185
+ for (const original of entries) {
186
+ const entry = { ...original, position: this.length++ };
187
+ this.writableBucket(hashKey(entry.key)).set(entry.key, entry);
188
+ this.writeOrder(entry.position, entry);
189
+ this.count++;
190
+ }
191
+ this.layout++;
192
+ }
193
+ *iterate(kind) {
194
+ let position = 0;
195
+ let layout = this.layout;
196
+ let cleared = this.cleared;
197
+ let lastSequence = -1;
198
+ let version = -1;
199
+ let leaf;
200
+ let page = -1;
201
+ for (; ; ) {
202
+ if (cleared !== this.cleared) {
203
+ position = 0;
204
+ lastSequence = -1;
205
+ cleared = this.cleared;
206
+ }
207
+ if (layout !== this.layout) {
208
+ position = 0;
209
+ while (position < this.length) {
210
+ const entry2 = this.leaf(position).cells[position & 31];
211
+ if (entry2 && entry2.sequence > lastSequence)
212
+ break;
213
+ position++;
214
+ }
215
+ layout = this.layout;
216
+ }
217
+ if (position >= this.length)
218
+ return;
219
+ const nextPage = Math.floor(position / 32);
220
+ if (page !== nextPage || version !== this.version) {
221
+ leaf = this.leaf(position);
222
+ page = nextPage;
223
+ version = this.version;
224
+ }
225
+ const entry = leaf?.cells[position++ & 31];
226
+ if (!entry)
227
+ continue;
228
+ lastSequence = entry.sequence;
229
+ yield kind === 0 ? [entry.key, entry.value] : kind === 1 ? entry.key : entry.value;
230
+ }
231
+ }
232
+ };
233
+ function hashKey(key) {
234
+ if (typeof key === "number" && Number.isInteger(key))
235
+ return mix((key | 0) ^ (key / 4294967296 | 0));
236
+ if (typeof key === "bigint")
237
+ return mix(Number(BigInt.asIntN(32, key ^ key >> 32n)));
238
+ const text = String(key);
239
+ let hash = 2166136261;
240
+ for (let i = 0; i < text.length; i++)
241
+ hash = Math.imul(hash ^ text.charCodeAt(i), 16777619);
242
+ return hash;
243
+ }
244
+ function mix(value) {
245
+ value = Math.imul(value ^ value >>> 16, 73244475);
246
+ value = Math.imul(value ^ value >>> 16, 73244475);
247
+ return value ^ value >>> 16;
248
+ }
249
+
4
250
  // ../../core/dist/timeline.js
5
251
  var BRANCH_PATTERN = /^[A-Za-z0-9_.-]{1,64}$/;
6
252
  var Timeline = class {
@@ -4794,10 +5040,81 @@ function parseArrayText(t, text, ctx) {
4794
5040
 
4795
5041
  // src/storage/database-state.ts
4796
5042
  var TableData = class _TableData {
5043
+ /** @internal Optional physical row journal; IDs remain stable across heap splices. */
5044
+ durableChanges = null;
5045
+ durableNextId = 0;
5046
+ durableEpoch;
5047
+ durableUnsafe = false;
5048
+ durableIds;
5049
+ enableDurabilityTracking(ids, nextId) {
5050
+ if (this.durableChanges && !this.durableUnsafe && !ids) return;
5051
+ this.materializeSlab();
5052
+ this.durableIds = /* @__PURE__ */ new WeakMap();
5053
+ this.durableChanges = new ForkMap();
5054
+ this.durableNextId = nextId ?? this.#rows.length;
5055
+ for (let i = 0; i < this.#rows.length; i++) this.durableIds.set(this.#rows[i], ids?.[i] ?? i);
5056
+ this.durableEpoch = {};
5057
+ this.durableUnsafe = false;
5058
+ }
5059
+ durableRowId(row) {
5060
+ const id = this.durableIds?.get(row);
5061
+ if (id === void 0) throw new Error("Untracked durable row");
5062
+ return id;
5063
+ }
5064
+ disableDurabilityTracking() {
5065
+ this.durableChanges = null;
5066
+ this.durableIds = void 0;
5067
+ this.durableEpoch = void 0;
5068
+ this.durableUnsafe = false;
5069
+ }
5070
+ recordDurableRow(row, previous) {
5071
+ if (!this.durableChanges) return;
5072
+ const id = (previous && this.durableIds?.get(previous)) ?? this.durableIds?.get(row) ?? this.durableNextId++;
5073
+ this.durableIds.set(row, id);
5074
+ this.durableChanges.set(id, { row, xmin: this.rowXmins.get(row) ?? 2 });
5075
+ }
5076
+ recordDurableDelete(row) {
5077
+ if (this.durableChanges) this.durableChanges.set(this.durableRowId(row), { row: null, xmin: 0 });
5078
+ }
5079
+ /** @internal Metadata twin with no visits/copies of existing rows or index entries. */
5080
+ emptyForDurability() {
5081
+ const copy = new _TableData(this.schema, this.name, this.columns, this.oid, this.temp);
5082
+ copy.constraints = this.constraints;
5083
+ copy.triggers = this.triggers;
5084
+ copy.unlogged = this.unlogged;
5085
+ return copy;
5086
+ }
5087
+ /** @internal Serialization/SQL scans must not count as public native-array exposure. */
5088
+ serializationRows() {
5089
+ this.materializeSlab();
5090
+ return this.materializedRows();
5091
+ }
5092
+ /** @internal Internal mutable array access, with ordinary public mutableRows kept intact. */
5093
+ writeRows() {
5094
+ return this.serializationRows();
5095
+ }
5096
+ /** @internal Ordinary snapshot branches must not inherit a persistence journal. */
5097
+ untrackedFork() {
5098
+ const copy = this.emptyForDurability();
5099
+ copy.rowXmins = this.rowXmins;
5100
+ copy.slabXmins = this.slabXmins;
5101
+ if (this.slab) copy.slab = this.slab;
5102
+ else {
5103
+ copy.#rows = this.#rows;
5104
+ copy.#rowPatches = this.#rowPatches?.fork() ?? null;
5105
+ copy.#rowsShared = this.#rowsShared = true;
5106
+ copy.tuplesShared = this.tuplesShared = true;
5107
+ }
5108
+ copy.indexStores = this.indexStores ? new Map([...this.indexStores].map(([name, store]) => [name, store.clone()])) : null;
5109
+ return copy;
5110
+ }
4797
5111
  name;
4798
5112
  schema;
4799
5113
  columns;
4800
- rows;
5114
+ #rows = [];
5115
+ #rowPatches = null;
5116
+ #rowsShared = false;
5117
+ #rowsExposed = false;
4801
5118
  rowXmins = /* @__PURE__ */ new WeakMap();
4802
5119
  slabXmins = null;
4803
5120
  /** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
@@ -4813,22 +5130,54 @@ var TableData = class _TableData {
4813
5130
  shareCount = 0;
4814
5131
  /** Derived unique/btree index maps; null until built or invalidated. */
4815
5132
  indexStores = null;
5133
+ /** DML replaces tuples; DDL must detach them before changing cells in place. */
5134
+ tuplesShared = false;
4816
5135
  constructor(schema, name, columns, oid, temp = false) {
4817
5136
  this.schema = schema;
4818
5137
  this.name = name;
4819
5138
  this.columns = columns;
4820
- this.rows = [];
5139
+ Object.defineProperty(this, "rows", {
5140
+ enumerable: true,
5141
+ configurable: true,
5142
+ get: this.nativeRows,
5143
+ set: this.setNativeRows
5144
+ });
4821
5145
  this.constraints = [];
4822
5146
  this.triggers = [];
4823
5147
  this.temp = temp;
4824
5148
  this.oid = oid;
4825
5149
  }
4826
5150
  rowCount() {
4827
- return this.slab ? this.slab.rowCount : this.rows.length;
5151
+ return this.slab ? this.slab.rowCount : this.#rows.length;
4828
5152
  }
4829
5153
  rowAt(index) {
4830
5154
  if (this.slab) return this.slab.rowAt(index);
4831
- return this.rows[index] ?? [];
5155
+ return this.#rowPatches?.get(index) ?? this.#rows[index] ?? [];
5156
+ }
5157
+ /** Replace an existing tuple without copying the array of unchanged row references. */
5158
+ replaceRow(index, row) {
5159
+ if (this.durableChanges) this.recordDurableRow(row, this.rowAt(index));
5160
+ if (this.#rowPatches) this.#rowPatches.set(index, row);
5161
+ else this.#rows[index] = row;
5162
+ }
5163
+ materializedRows() {
5164
+ if (this.#rowsShared) this.#rows = this.#rows.slice();
5165
+ if (this.#rowPatches) for (const [index, row] of this.#rowPatches) this.#rows[index] = row;
5166
+ this.#rowPatches = null;
5167
+ this.#rowsShared = false;
5168
+ return this.#rows;
5169
+ }
5170
+ nativeRows() {
5171
+ if (this.durableChanges) this.durableUnsafe = true;
5172
+ this.#rowsExposed = true;
5173
+ return this.materializedRows();
5174
+ }
5175
+ setNativeRows(rows) {
5176
+ if (this.durableChanges) this.durableUnsafe = true;
5177
+ this.#rows = rows;
5178
+ this.#rowPatches = null;
5179
+ this.#rowsShared = false;
5180
+ this.#rowsExposed = true;
4832
5181
  }
4833
5182
  /** All rows for scans; materializes slab once into `rows` when needed. */
4834
5183
  allRows() {
@@ -4837,13 +5186,15 @@ var TableData = class _TableData {
4837
5186
  }
4838
5187
  attachSlab(slab) {
4839
5188
  this.slab = slab;
4840
- this.rows = [];
5189
+ this.#rows = [];
5190
+ this.#rowPatches = null;
5191
+ this.#rowsShared = false;
4841
5192
  }
4842
5193
  materializeSlab() {
4843
5194
  if (!this.slab) return;
4844
- this.rows = this.slab.materialize();
5195
+ this.#rows = this.slab.materialize();
4845
5196
  if (this.slabXmins)
4846
- this.rows.forEach((row, index) => {
5197
+ this.#rows.forEach((row, index) => {
4847
5198
  this.rowXmins.set(row, this.slabXmins[index] ?? 2);
4848
5199
  });
4849
5200
  this.slabXmins = null;
@@ -4867,7 +5218,7 @@ var TableData = class _TableData {
4867
5218
  columnIndex(name) {
4868
5219
  return this.columns.findIndex((c) => c.name === name);
4869
5220
  }
4870
- clone() {
5221
+ cloneMetadata() {
4871
5222
  const t = new _TableData(
4872
5223
  this.schema,
4873
5224
  this.name,
@@ -4875,21 +5226,68 @@ var TableData = class _TableData {
4875
5226
  this.oid,
4876
5227
  this.temp
4877
5228
  );
5229
+ t.unlogged = this.unlogged;
5230
+ t.durableChanges = this.durableChanges?.fork() ?? null;
5231
+ t.durableIds = this.durableIds;
5232
+ t.durableNextId = this.durableNextId;
5233
+ t.durableEpoch = this.durableEpoch;
5234
+ t.durableUnsafe = this.durableUnsafe;
5235
+ t.constraints = this.constraints.map((c) => ({ ...c }));
5236
+ t.triggers = this.triggers.map((tr) => ({ ...tr }));
5237
+ t.indexStores = this.indexStores ? new Map([...this.indexStores].map(([k, v]) => [k, v.clone()])) : null;
5238
+ return t;
5239
+ }
5240
+ clone() {
5241
+ const t = this.cloneMetadata();
5242
+ if (t.durableChanges) t.durableUnsafe = true;
4878
5243
  if (this.slab) {
4879
- t.rows = this.slab.materialize().map((r) => r.slice());
5244
+ t.#rows = this.slab.materialize().map((r) => r.slice());
4880
5245
  } else {
4881
- t.rows = this.rows.map((r) => r.slice());
5246
+ t.#rows = this.materializedRows().map((r) => r.slice());
4882
5247
  }
4883
- t.rows.forEach((row, index) => {
4884
- const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.rows[index]);
5248
+ t.#rows.forEach((row, index) => {
5249
+ const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.#rows[index]);
4885
5250
  if (xmin !== void 0) t.rowXmins.set(row, xmin);
4886
5251
  });
4887
- t.unlogged = this.unlogged;
4888
- t.constraints = this.constraints.map((c) => ({ ...c }));
4889
- t.triggers = this.triggers.map((tr) => ({ ...tr }));
4890
- t.indexStores = this.indexStores ? new Map([...this.indexStores].map(([k, v]) => [k, v.clone()])) : null;
4891
5252
  return t;
4892
5253
  }
5254
+ /** DML creates new tuple arrays; retain existing tuples and xmin bindings until DDL. */
5255
+ cloneForDml() {
5256
+ if (this.triggers.length > 0) return this.cloneForWrite();
5257
+ const t = this.cloneMetadata();
5258
+ t.rowXmins = this.rowXmins;
5259
+ if (this.slab) {
5260
+ t.#rows = this.slab.materialize();
5261
+ if (this.slabXmins) {
5262
+ for (let index = 0; index < t.#rows.length; index++)
5263
+ t.rowXmins.set(t.#rows[index], this.slabXmins[index] ?? 2);
5264
+ }
5265
+ } else {
5266
+ if (this.#rows.length >= 4096 && !this.#rowsExposed) {
5267
+ this.#rowPatches ??= new ForkMap();
5268
+ t.#rowPatches = this.#rowPatches.fork();
5269
+ t.#rows = this.#rows;
5270
+ t.#rowsShared = this.#rowsShared = true;
5271
+ } else t.#rows = this.materializedRows().slice();
5272
+ this.tuplesShared = true;
5273
+ }
5274
+ t.tuplesShared = true;
5275
+ return t;
5276
+ }
5277
+ /** A live DML fork can be unfrozen while its unchanged tuples still belong to history. */
5278
+ ownTuples() {
5279
+ if (this.durableChanges) this.durableUnsafe = true;
5280
+ if (!this.tuplesShared) return;
5281
+ const xmins = /* @__PURE__ */ new WeakMap();
5282
+ this.rows = this.rows.map((row) => {
5283
+ const copy = row.slice();
5284
+ const xmin = this.rowXmins.get(row);
5285
+ if (xmin !== void 0) xmins.set(copy, xmin);
5286
+ return copy;
5287
+ });
5288
+ this.rowXmins = xmins;
5289
+ this.tuplesShared = false;
5290
+ }
4893
5291
  /** Independent writable copy (row tuples copied so ALTER COLUMN is isolated). */
4894
5292
  cloneForWrite() {
4895
5293
  const t = this.clone();
@@ -5243,12 +5641,21 @@ var DatabaseState = class _DatabaseState {
5243
5641
  }
5244
5642
  }
5245
5643
  ensureWritableTable(table) {
5246
- if (!table.frozen) return table;
5644
+ if (!table.frozen) {
5645
+ table.ownTuples();
5646
+ return table;
5647
+ }
5247
5648
  const schema = this.schemas.get(table.schema);
5248
5649
  const copy = table.cloneForWrite();
5249
5650
  schema?.tables.set(table.name, copy);
5250
5651
  return copy;
5251
5652
  }
5653
+ ensureWritableTableForDml(table) {
5654
+ if (!table.frozen) return table;
5655
+ const copy = table.cloneForDml();
5656
+ this.schemas.get(table.schema)?.tables.set(table.name, copy);
5657
+ return copy;
5658
+ }
5252
5659
  ensureWritableSequence(seq) {
5253
5660
  if ((seq.shareCount ?? 0) === 0) return seq;
5254
5661
  const schema = this.schemas.get(seq.schema);
@@ -8364,7 +8771,7 @@ function evalPgcryptoFunction(ctx, fn, args) {
8364
8771
  // src/functions/hash-fns.ts
8365
8772
  var utf83 = new TextEncoder();
8366
8773
  var rot = (x, k) => (x << k | x >>> 32 - k) >>> 0;
8367
- function mix(s) {
8774
+ function mix2(s) {
8368
8775
  s[0] = s[0] - s[2] >>> 0;
8369
8776
  s[0] = (s[0] ^ rot(s[2], 4)) >>> 0;
8370
8777
  s[2] = s[2] + s[1] >>> 0;
@@ -8408,7 +8815,7 @@ function hashAny(k, seed) {
8408
8815
  const bits = BigInt.asUintN(64, seed);
8409
8816
  s[0] = s[0] + Number(bits >> 32n) >>> 0;
8410
8817
  s[1] = s[1] + Number(bits & 0xffffffffn) >>> 0;
8411
- mix(s);
8818
+ mix2(s);
8412
8819
  }
8413
8820
  let at = 0;
8414
8821
  let len = k.length;
@@ -8416,7 +8823,7 @@ function hashAny(k, seed) {
8416
8823
  s[0] = s[0] + word(k, at) >>> 0;
8417
8824
  s[1] = s[1] + word(k, at + 4) >>> 0;
8418
8825
  s[2] = s[2] + word(k, at + 8) >>> 0;
8419
- mix(s);
8826
+ mix2(s);
8420
8827
  }
8421
8828
  for (let i = len - 1; i >= 0; i--) {
8422
8829
  const byte = k[at + i];
@@ -14988,6 +15395,21 @@ var IndexStore = class _IndexStore {
14988
15395
  name;
14989
15396
  unique;
14990
15397
  entries = /* @__PURE__ */ new Map();
15398
+ integerKeys = null;
15399
+ shared = false;
15400
+ ownedBuckets = /* @__PURE__ */ new WeakSet();
15401
+ writableBucket(key, bucket) {
15402
+ if (this.ownedBuckets.has(bucket)) return bucket;
15403
+ const copy = bucket.slice();
15404
+ this.entries.set(key, copy);
15405
+ this.ownedBuckets.add(copy);
15406
+ return copy;
15407
+ }
15408
+ detach() {
15409
+ if (!this.shared) return;
15410
+ if (!(this.entries instanceof ForkMap)) this.entries = new Map(this.entries);
15411
+ this.shared = false;
15412
+ }
14991
15413
  constructor(name, unique = false) {
14992
15414
  this.name = name;
14993
15415
  this.unique = unique;
@@ -15006,36 +15428,78 @@ var IndexStore = class _IndexStore {
15006
15428
  }
15007
15429
  insert(key, rowIdx) {
15008
15430
  if (this.unique) this.checkUnique(key, rowIdx);
15431
+ this.detach();
15432
+ this.integerKeys = null;
15009
15433
  const existing = this.entries.get(key);
15010
15434
  if (!existing) {
15011
- this.entries.set(key, [rowIdx]);
15435
+ const bucket = [rowIdx];
15436
+ this.ownedBuckets.add(bucket);
15437
+ this.entries.set(key, bucket);
15012
15438
  return;
15013
15439
  }
15014
15440
  if (existing.includes(rowIdx)) return;
15015
- existing.push(rowIdx);
15441
+ this.writableBucket(key, existing).push(rowIdx);
15016
15442
  }
15017
15443
  remove(key, rowIdx) {
15018
15444
  const existing = this.entries.get(key);
15019
15445
  if (!existing) return;
15020
15446
  const at = existing.indexOf(rowIdx);
15021
15447
  if (at < 0) return;
15022
- existing.splice(at, 1);
15023
- if (existing.length === 0) this.entries.delete(key);
15448
+ this.detach();
15449
+ this.integerKeys = null;
15450
+ if (existing.length === 1) this.entries.delete(key);
15451
+ else {
15452
+ const remaining = this.writableBucket(key, existing);
15453
+ remaining.splice(at, 1);
15454
+ this.entries.set(key, remaining);
15455
+ }
15024
15456
  }
15025
15457
  lookup(key) {
15026
15458
  return this.entries.get(key) ?? [];
15027
15459
  }
15460
+ /** Ordered access for a single int2/int4 key (the planner validates the key type). */
15461
+ integerRange(lower, upper, includeLower, includeUpper) {
15462
+ const keys = this.integerKeys ??= [...this.entries].map(([key, rows]) => ({ value: Number(key.slice(1)), rows })).sort((a, b) => a.value - b.value);
15463
+ let lo = 0;
15464
+ let hi = keys.length;
15465
+ while (lo < hi) {
15466
+ const mid = lo + hi >>> 1;
15467
+ const value = keys[mid].value;
15468
+ if (value < lower || !includeLower && value === lower) lo = mid + 1;
15469
+ else hi = mid;
15470
+ }
15471
+ const result = [];
15472
+ for (let i = lo; i < keys.length; i++) {
15473
+ const key = keys[i];
15474
+ if (key.value > upper || !includeUpper && key.value === upper) break;
15475
+ result.push(...key.rows);
15476
+ }
15477
+ return result.sort((a, b) => a - b);
15478
+ }
15028
15479
  clear() {
15029
- this.entries.clear();
15480
+ this.entries = /* @__PURE__ */ new Map();
15481
+ this.shared = false;
15482
+ this.integerKeys = null;
15030
15483
  }
15031
15484
  clone() {
15032
15485
  const copy = new _IndexStore(this.name, this.unique);
15033
- for (const [key, rowids] of this.entries) copy.entries.set(key, [...rowids]);
15486
+ if (this.entries.size >= 4096 && !(this.entries instanceof ForkMap)) this.entries = new ForkMap(this.entries);
15487
+ copy.entries = this.entries instanceof ForkMap ? this.entries.fork() : this.entries;
15488
+ copy.integerKeys = this.integerKeys;
15489
+ copy.shared = true;
15490
+ this.shared = true;
15491
+ this.ownedBuckets = /* @__PURE__ */ new WeakSet();
15034
15492
  return copy;
15035
15493
  }
15036
15494
  };
15037
15495
 
15038
15496
  // src/indexes/maintain.ts
15497
+ function prepareDmlIndexStores(env, table) {
15498
+ if (table.indexStores || !table.frozen || table.triggers.length > 0) return;
15499
+ const specs = uniqueSpecsFor(env, table);
15500
+ if (specs.some((spec) => spec.where || spec.keys.some((key) => key.expr))) return;
15501
+ ensureIndexStores(env, table);
15502
+ }
15039
15503
  function ensureIndexStores(env, table) {
15040
15504
  if (table.indexStores) return table.indexStores;
15041
15505
  const stores = /* @__PURE__ */ new Map();
@@ -15086,8 +15550,19 @@ function indexRemoveRow(env, table, rowIdx, row) {
15086
15550
  }
15087
15551
  }
15088
15552
  function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
15089
- indexRemoveRow(env, table, rowIdx, oldRow);
15090
- indexInsertRow(env, table, rowIdx, newRow);
15553
+ const specs = uniqueSpecsFor(env, table);
15554
+ if (specs.some((spec) => spec.where || spec.keys.some((key) => key.expr))) {
15555
+ indexRemoveRow(env, table, rowIdx, oldRow);
15556
+ indexInsertRow(env, table, rowIdx, newRow);
15557
+ return;
15558
+ }
15559
+ for (const spec of specs) {
15560
+ const before = uniqueKeyOf(env, table, spec, oldRow);
15561
+ const after = uniqueKeyOf(env, table, spec, newRow);
15562
+ if (before === after) continue;
15563
+ if (before !== null) table.indexStores?.get(spec.name)?.remove(before, rowIdx);
15564
+ if (after !== null) indexStoreFor(env, table, spec).insert(after, rowIdx);
15565
+ }
15091
15566
  }
15092
15567
  function rebuildTableIndexes(env, table) {
15093
15568
  table.indexStores = null;
@@ -15304,6 +15779,82 @@ function conjunctions(expr) {
15304
15779
  }
15305
15780
  return [expr];
15306
15781
  }
15782
+ function tryPointRowIndices(env, table, alias, where) {
15783
+ const eqs = [];
15784
+ for (const part of conjunctions(where)) {
15785
+ const eq = equalityAgainstConst(part);
15786
+ if (!eq || !["param", "number_lit", "string_lit", "bool_lit", "null_lit"].includes(eq.valueExpr.type)) return null;
15787
+ if (part.type !== "binop") return null;
15788
+ const column = part.left.type === "colref" ? part.left : part.right;
15789
+ if (column.type !== "colref") return null;
15790
+ if (column.parts.length > 1 && column.parts[column.parts.length - 2] !== alias) return null;
15791
+ eqs.push(eq);
15792
+ }
15793
+ for (const spec of uniqueSpecsFor(env, table)) {
15794
+ if (spec.where || spec.keys.length !== eqs.length || spec.keys.some((key2) => key2.expr) || !eqs.every((eq, index) => eq.column === spec.columnNames[index]))
15795
+ continue;
15796
+ const values = table.columns.map(() => null);
15797
+ let matches2 = true;
15798
+ for (let index = 0; index < spec.keys.length; index++) {
15799
+ const key2 = spec.keys[index];
15800
+ const column = table.columns[key2.colIdx];
15801
+ const eq = eqs[index];
15802
+ if (!column || !eq || column.domain) {
15803
+ matches2 = false;
15804
+ break;
15805
+ }
15806
+ const value = evalExpr(env.ctx, makeEvalScope(env, null), eq.valueExpr);
15807
+ if (value.t !== column.type.id && !(column.type.id === "text" && value.t === "unknown" && typeof value.v === "string")) {
15808
+ matches2 = false;
15809
+ break;
15810
+ }
15811
+ values[key2.colIdx] = value.v;
15812
+ }
15813
+ if (!matches2) continue;
15814
+ const key = uniqueKeyOf(env, table, spec, values);
15815
+ return { indices: key === null ? [] : indexStoreFor(env, table, spec).lookup(key), indexName: spec.name };
15816
+ }
15817
+ return null;
15818
+ }
15819
+ function recordIndexScan(env, table, name) {
15820
+ const schema = env.ctx.state.schemas.get(table.schema);
15821
+ const index = schema?.indexes.get(name);
15822
+ if (schema && index) {
15823
+ const lastScan = env.ctx.state.clock().getTime();
15824
+ schema.indexes.set(name, { ...index, scans: (index.scans ?? 0n) + 1n, lastScan });
15825
+ }
15826
+ }
15827
+ function tryRangeRowIndices(env, table, alias, where) {
15828
+ const parts = conjunctions(where);
15829
+ if (parts.length !== 2) return null;
15830
+ const bounds = [];
15831
+ for (const part of parts) {
15832
+ if (part.type !== "binop" || ![">", ">=", "<", "<="].includes(part.op)) return null;
15833
+ const column2 = part.left.type === "colref" ? part.left : part.right;
15834
+ const value = part.left.type === "colref" ? part.right : part.left;
15835
+ if (column2.type !== "colref" || column2.parts.length > 2 || column2.parts.length === 2 && column2.parts[0] !== alias || !["param", "number_lit"].includes(value.type))
15836
+ return null;
15837
+ const op = part.left === column2 ? part.op : { ">": "<", ">=": "<=", "<": ">", "<=": ">=" }[part.op];
15838
+ bounds.push({ column: column2.parts.at(-1), op, value });
15839
+ }
15840
+ const lower = bounds.find((bound) => bound.op === ">" || bound.op === ">=");
15841
+ const upper = bounds.find((bound) => bound.op === "<" || bound.op === "<=");
15842
+ if (!lower || !upper || lower.column !== upper.column) return null;
15843
+ const column = table.columns.find((column2) => column2.name === lower.column);
15844
+ if (!column || column.domain || !["int2", "int4"].includes(column.type.id)) return null;
15845
+ for (const spec of uniqueSpecsFor(env, table)) {
15846
+ if (spec.where || spec.keys.length !== 1 || spec.keys[0].expr || spec.columnNames[0] !== lower.column) continue;
15847
+ const low = evalExpr(env.ctx, makeEvalScope(env, null), lower.value);
15848
+ const high = evalExpr(env.ctx, makeEvalScope(env, null), upper.value);
15849
+ if (low.t !== column.type.id || high.t !== column.type.id || typeof low.v !== "number" || typeof high.v !== "number")
15850
+ return null;
15851
+ return {
15852
+ indices: indexStoreFor(env, table, spec).integerRange(low.v, high.v, lower.op === ">=", upper.op === "<="),
15853
+ indexName: spec.name
15854
+ };
15855
+ }
15856
+ return null;
15857
+ }
15307
15858
  function tryIndexedTableRows(env, table, alias, where) {
15308
15859
  const parts = conjunctions(where);
15309
15860
  const eqs = [];
@@ -15340,12 +15891,7 @@ function tryIndexedTableRows(env, table, alias, where) {
15340
15891
  const key = uniqueKeyOf(env, table, spec, probeRow);
15341
15892
  if (key === null) return [];
15342
15893
  const hits = indexStoreFor(env, table, spec).lookup(key);
15343
- const schema = env.ctx.state.schemas.get(table.schema);
15344
- const index = schema?.indexes.get(spec.name);
15345
- if (schema && index) {
15346
- const lastScan = env.ctx.state.clock().getTime();
15347
- schema.indexes.set(spec.name, { ...index, scans: (index.scans ?? 0n) + 1n, lastScan });
15348
- }
15894
+ recordIndexScan(env, table, spec.name);
15349
15895
  return hits.map((i) => table.rowAt(i));
15350
15896
  }
15351
15897
  function tryIndexedFromItem(env, item, where) {
@@ -21321,7 +21867,7 @@ function renameWithAliases(rel4, label, colAliases, what) {
21321
21867
  }));
21322
21868
  return { columns, rows: rel4.rows };
21323
21869
  }
21324
- function materializeItem(env, item, scope) {
21870
+ function materializeItem(env, item, scope, shapeOnly = false) {
21325
21871
  switch (item.type) {
21326
21872
  case "from_table": {
21327
21873
  const label = item.alias ?? item.name[item.name.length - 1];
@@ -21340,7 +21886,7 @@ function materializeItem(env, item, scope) {
21340
21886
  ...table.columns.map((c) => ({ name: c.name, type: c.type.id, mod: c.type.mod, table: label })),
21341
21887
  { name: "xmin", type: "xid", table: label, hidden: true, system: true }
21342
21888
  ],
21343
- rows: table.rows.map((row) => [...row, table.rowXmins.get(row) ?? 2])
21889
+ rows: shapeOnly ? [] : table.serializationRows().map((row) => [...row, table.rowXmins.get(row) ?? 2])
21344
21890
  };
21345
21891
  return { rel: renameWithAliases(rel4, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
21346
21892
  }
@@ -22613,14 +23159,30 @@ function checkPredicateType(env, columns, rangeVars, e, kind, extras) {
22613
23159
  function executeCore(env0, core, orderBy, opts) {
22614
23160
  const env = env0;
22615
23161
  const ctx = env.ctx;
22616
- const source = buildFrom(env, core.from, core.where);
23162
+ const item = core.from.length === 1 ? core.from[0] : null;
23163
+ 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;
23164
+ const point = pointTable && core.where && item?.type === "from_table" ? tryPointRowIndices(env, pointTable, item.alias ?? item.name[item.name.length - 1], core.where) : null;
23165
+ const range = !point && pointTable && core.where && item?.type === "from_table" ? tryRangeRowIndices(env, pointTable, item.alias ?? item.name[item.name.length - 1], core.where) : null;
23166
+ const access = point ?? range;
23167
+ const source = access && item ? materializeItem(env, item, env.outer, true) : buildFrom(env, core.from, core.where);
22617
23168
  const srcCols = source.rel.columns;
22618
23169
  const rangeVars = source.rangeVars;
22619
23170
  const rowScope = (row) => new RowScope(srcCols, row, env.outer, rangeVars);
22620
23171
  let srcRows = source.rel.rows;
22621
23172
  if (core.where) {
22622
23173
  checkPredicateType(env, srcCols, rangeVars, core.where, "WHERE");
22623
- if (core.from.length === 1) {
23174
+ if (access && pointTable) {
23175
+ pointTable.materializeSlab();
23176
+ srcRows = access.indices.map((index) => {
23177
+ const row = pointTable.rowAt(index);
23178
+ return [...row, pointTable.rowXmins.get(row) ?? 2];
23179
+ });
23180
+ if (range) {
23181
+ const where = core.where;
23182
+ srcRows = srcRows.filter((row) => evalPredicate2(env, rowScope(row), where));
23183
+ }
23184
+ recordIndexScan(env, pointTable, access.indexName);
23185
+ } else if (core.from.length === 1) {
22624
23186
  const indexed = tryIndexedFromItem(env, core.from[0], core.where);
22625
23187
  if (indexed !== null) {
22626
23188
  srcRows = indexed;
@@ -22801,11 +23363,11 @@ function executeCore(env0, core, orderBy, opts) {
22801
23363
  }
22802
23364
  }
22803
23365
  }
22804
- const item = { name: `__ord${orderExprs.length}`, kind: "expr", colIdx: -1, expr: ob.expr, hidden: true };
23366
+ const item2 = { name: `__ord${orderExprs.length}`, kind: "expr", colIdx: -1, expr: ob.expr, hidden: true };
22805
23367
  const spec = { colIdx: projItems.length, dir, nullsFirst };
22806
- projItems.push(item);
23368
+ projItems.push(item2);
22807
23369
  sortSpecs.push(spec);
22808
- orderExprs.push({ item, spec });
23370
+ orderExprs.push({ item: item2, spec });
22809
23371
  }
22810
23372
  if (core.distinct && !core.distinct.on && sortSpecs.length > 0 && !opts?.hasLimit) {
22811
23373
  const used = new Set(sortSpecs.map((s) => s.colIdx));
@@ -23179,7 +23741,7 @@ var TransactionManager = class {
23179
23741
  return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
23180
23742
  }
23181
23743
  restore(snap) {
23182
- this.state.restoreFrom(snap.state);
23744
+ this.state.restoreFrom(snap.state.cloneShallow());
23183
23745
  this.state.prng.setState(snap.prngState);
23184
23746
  }
23185
23747
  thawOnce() {
@@ -23279,7 +23841,10 @@ function withStatementRollback(env, fn) {
23279
23841
  function requireTargetTable(env, parts, verb) {
23280
23842
  const state = env.ctx.state;
23281
23843
  const table = state.findTable(parts);
23282
- if (table) return state.ensureWritableTable(table);
23844
+ if (table) {
23845
+ prepareDmlIndexStores(env, table);
23846
+ return state.ensureWritableTableForDml(table);
23847
+ }
23283
23848
  const view = state.findView(parts);
23284
23849
  if (view) {
23285
23850
  throw pgError("wrong_object_type", `cannot ${verb} view "${view.name}"`, "42809");
@@ -23447,7 +24012,7 @@ function resolveArbiters(env, table, clause) {
23447
24012
  return matches2.map((spec) => ({ spec }));
23448
24013
  }
23449
24014
  function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, where) {
23450
- const rows = table.mutableRows();
24015
+ const rows = table.writeRows();
23451
24016
  const existing = rows[existingIdx];
23452
24017
  const cols = [
23453
24018
  ...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
@@ -23459,7 +24024,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
23459
24024
  applyUpdateSets(env, table, sets, scope, updated);
23460
24025
  computeGeneratedColumns(env, table, updated);
23461
24026
  table.rowXmins.set(updated, env.ctx.rowVersionXid());
23462
- rows[existingIdx] = updated;
24027
+ table.replaceRow(existingIdx, updated);
23463
24028
  indexUpdateRow(env, table, existingIdx, existing, updated);
23464
24029
  checkNotNull(env, table, updated);
23465
24030
  checkChecks(env, table, updated);
@@ -23471,7 +24036,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
23471
24036
  function executeInsert(env0, stmt) {
23472
24037
  const env = applyWith(env0, stmt.with);
23473
24038
  const table = requireTargetTable(env, stmt.table, "insert into");
23474
- const rows = table.mutableRows();
24039
+ const rows = table.writeRows();
23475
24040
  const label = stmt.alias ?? table.name;
23476
24041
  const colIdxs = insertTargetColumns(env, table, stmt);
23477
24042
  const sourceRows = insertSourceRows(env, stmt, colIdxs);
@@ -23555,6 +24120,7 @@ function executeInsert(env0, stmt) {
23555
24120
  checkForeignKeys(env, table, newRow);
23556
24121
  table.rowXmins.set(newRow, env.ctx.rowVersionXid());
23557
24122
  rows.push(newRow);
24123
+ table.recordDurableRow(newRow);
23558
24124
  indexInsertRow(env, table, rows.length - 1, newRow);
23559
24125
  insertedCount++;
23560
24126
  insertedRows.push(newRow);
@@ -23647,13 +24213,17 @@ function executeUpdate(env0, stmt) {
23647
24213
  const label = stmt.alias ?? table.name;
23648
24214
  fireStatementTriggers(env, table, "before", "update");
23649
24215
  const fromSource = stmt.from.length > 0 ? buildFrom(env, stmt.from) : null;
23650
- const rows = table.mutableRows();
23651
24216
  const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
23652
24217
  const updatedRows = [];
23653
24218
  const replacedRows = [];
23654
24219
  let updateCount = 0;
23655
- for (let ri = 0; ri < rows.length; ri++) {
23656
- const oldRow = rows[ri];
24220
+ 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(
24221
+ (set) => set.columns.every((column) => column.subscripts === null && column.fields.length === 0) && "type" in set.value && isPureUpdateValue(set.value)
24222
+ ) && referencingConstraints(env, table).length === 0 ? tryPointRowIndices(env, table, label, stmt.where) : null;
24223
+ const rows = point ? null : table.writeRows();
24224
+ for (let candidate = 0; candidate < (point ? point.indices.length : rows.length); candidate++) {
24225
+ const ri = point ? point.indices[candidate] : candidate;
24226
+ const oldRow = point ? table.rowAt(ri) : rows[ri];
23657
24227
  let matchScope = null;
23658
24228
  if (fromSource) {
23659
24229
  let found = false;
@@ -23679,14 +24249,14 @@ function executeUpdate(env0, stmt) {
23679
24249
  const finalRow = fired.row;
23680
24250
  computeGeneratedColumns(env, table, finalRow);
23681
24251
  table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
23682
- rows[ri] = finalRow;
24252
+ table.replaceRow(ri, finalRow);
23683
24253
  try {
23684
24254
  checkNotNull(env, table, finalRow);
23685
24255
  checkChecks(env, table, finalRow);
23686
24256
  checkUnique(env, table, finalRow, ri);
23687
24257
  checkForeignKeys(env, table, finalRow);
23688
24258
  } catch (err) {
23689
- rows[ri] = oldRow;
24259
+ table.replaceRow(ri, oldRow);
23690
24260
  throw err;
23691
24261
  }
23692
24262
  indexUpdateRow(env, table, ri, oldRow, finalRow);
@@ -23704,12 +24274,29 @@ function executeUpdate(env0, stmt) {
23704
24274
  }
23705
24275
  return commandResult("UPDATE", updateCount);
23706
24276
  }
24277
+ function isPureUpdateValue(expr) {
24278
+ switch (expr.type) {
24279
+ case "param":
24280
+ case "number_lit":
24281
+ case "string_lit":
24282
+ case "bool_lit":
24283
+ case "null_lit":
24284
+ case "colref":
24285
+ return true;
24286
+ case "binop":
24287
+ return isPureUpdateValue(expr.left) && isPureUpdateValue(expr.right);
24288
+ case "unop":
24289
+ return isPureUpdateValue(expr.operand);
24290
+ default:
24291
+ return false;
24292
+ }
24293
+ }
23707
24294
  function executeDelete(env0, stmt) {
23708
24295
  const env = applyWith(env0, stmt.with);
23709
24296
  const table = requireTargetTable(env, stmt.table, "delete from");
23710
24297
  const label = stmt.alias ?? table.name;
23711
24298
  fireStatementTriggers(env, table, "before", "delete");
23712
- const rows = table.mutableRows();
24299
+ const rows = table.writeRows();
23713
24300
  const usingSource = stmt.using.length > 0 ? buildFrom(env, stmt.using) : null;
23714
24301
  const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
23715
24302
  const toDelete = [];
@@ -23739,6 +24326,7 @@ function executeDelete(env0, stmt) {
23739
24326
  if (skipped.has(ri)) continue;
23740
24327
  const row = rows[ri];
23741
24328
  handleReferencedDelete(env, table, row, 0);
24329
+ table.recordDurableDelete(row);
23742
24330
  rows.splice(ri, 1);
23743
24331
  deletedRows.unshift(row);
23744
24332
  }
@@ -23785,13 +24373,14 @@ function handleReferencedDelete(env, table, row, depth) {
23785
24373
  const idxs = referencingRowIdxs(ref, key);
23786
24374
  if (idxs.length === 0) continue;
23787
24375
  const action = con.onDelete ?? "no_action";
23788
- const child = env.ctx.state.ensureWritableTable(ref.table);
23789
- const childRows = child.mutableRows();
24376
+ const child = env.ctx.state.ensureWritableTableForDml(ref.table);
24377
+ const childRows = child.writeRows();
23790
24378
  switch (action) {
23791
24379
  case "cascade": {
23792
24380
  for (let k = idxs.length - 1; k >= 0; k--) {
23793
24381
  const childRow = childRows[idxs[k]];
23794
24382
  handleReferencedDelete(env, child, childRow, depth + 1);
24383
+ child.recordDurableDelete(childRow);
23795
24384
  childRows.splice(idxs[k], 1);
23796
24385
  }
23797
24386
  break;
@@ -23803,7 +24392,7 @@ function handleReferencedDelete(env, table, row, depth) {
23803
24392
  newRow[child.columnIndex(c)] = null;
23804
24393
  }
23805
24394
  child.rowXmins.set(newRow, env.ctx.rowVersionXid());
23806
- childRows[i] = newRow;
24395
+ child.replaceRow(i, newRow);
23807
24396
  checkNotNull(env, child, newRow);
23808
24397
  checkChecks(env, child, newRow);
23809
24398
  }
@@ -23817,7 +24406,7 @@ function handleReferencedDelete(env, table, row, depth) {
23817
24406
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
23818
24407
  }
23819
24408
  child.rowXmins.set(newRow, env.ctx.rowVersionXid());
23820
- childRows[i] = newRow;
24409
+ child.replaceRow(i, newRow);
23821
24410
  checkNotNull(env, child, newRow);
23822
24411
  checkChecks(env, child, newRow);
23823
24412
  checkForeignKeys(env, child, newRow);
@@ -23843,8 +24432,8 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
23843
24432
  const idxs = referencingRowIdxs(ref, oldKey);
23844
24433
  if (idxs.length === 0) continue;
23845
24434
  const action = con.onUpdate ?? "no_action";
23846
- const child = env.ctx.state.ensureWritableTable(ref.table);
23847
- const childRows = child.mutableRows();
24435
+ const child = env.ctx.state.ensureWritableTableForDml(ref.table);
24436
+ const childRows = child.writeRows();
23848
24437
  switch (action) {
23849
24438
  case "cascade": {
23850
24439
  for (const i of idxs) {
@@ -23855,7 +24444,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
23855
24444
  newRow[localIdx] = newRows[r][refIdx] ?? null;
23856
24445
  }
23857
24446
  child.rowXmins.set(newRow, env.ctx.rowVersionXid());
23858
- childRows[i] = newRow;
24447
+ child.replaceRow(i, newRow);
23859
24448
  checkChecks(env, child, newRow);
23860
24449
  }
23861
24450
  break;
@@ -23865,7 +24454,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
23865
24454
  const newRow = childRows[i].slice();
23866
24455
  for (const c of con.columns) newRow[child.columnIndex(c)] = null;
23867
24456
  child.rowXmins.set(newRow, env.ctx.rowVersionXid());
23868
- childRows[i] = newRow;
24457
+ child.replaceRow(i, newRow);
23869
24458
  checkNotNull(env, child, newRow);
23870
24459
  }
23871
24460
  break;
@@ -23878,7 +24467,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
23878
24467
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
23879
24468
  }
23880
24469
  child.rowXmins.set(newRow, env.ctx.rowVersionXid());
23881
- childRows[i] = newRow;
24470
+ child.replaceRow(i, newRow);
23882
24471
  checkForeignKeys(env, child, newRow);
23883
24472
  }
23884
24473
  break;
@@ -24401,6 +24990,8 @@ function openSnapshot(snapshot, options = {}) {
24401
24990
  now = () => new Date(ms);
24402
24991
  }
24403
24992
  const state = snapshot.state.cloneShallow();
24993
+ for (const schema of state.schemas.values())
24994
+ for (const [name, table] of schema.tables) if (table.durableChanges) schema.tables.set(name, table.untrackedFork());
24404
24995
  state.prng = prng;
24405
24996
  state.clock = now;
24406
24997
  return createAdoptedDatabase({
@@ -29086,6 +29677,24 @@ var Statement = class _Statement {
29086
29677
  this.database = database;
29087
29678
  this.sql = sql;
29088
29679
  this.statements = statements;
29680
+ const observer = database.durabilityObserver;
29681
+ if (observer) {
29682
+ const execute = this.execute;
29683
+ this.execute = (params) => {
29684
+ observer.assertWritable();
29685
+ if (params.some((value) => value instanceof Uint8Array)) observer.exposed();
29686
+ try {
29687
+ const result = execute.call(this, params);
29688
+ if (result.columns.some(
29689
+ (column, index) => column.type === "bytea" && result.rows.some((row) => row[index] !== null && row[index] !== void 0)
29690
+ ))
29691
+ observer.exposed();
29692
+ return result;
29693
+ } finally {
29694
+ observer.changed();
29695
+ }
29696
+ };
29697
+ }
29089
29698
  }
29090
29699
  database;
29091
29700
  statements;
@@ -29118,7 +29727,7 @@ var Statement = class _Statement {
29118
29727
  */
29119
29728
  textResult(...params) {
29120
29729
  const res = this.execute(params);
29121
- const ctx = new EngineCtx(this.database.state);
29730
+ const ctx = new EngineCtx(this.database.engineState);
29122
29731
  return {
29123
29732
  columns: res.columns.map((c) => c.name),
29124
29733
  columnTypes: res.columns.map((c) => c.type === UNKNOWN ? "text" : c.type),
@@ -29155,7 +29764,7 @@ var Statement = class _Statement {
29155
29764
  const refused = this.database.transactions.inTransaction ? refusedInTransactionBlock(stmt) : null;
29156
29765
  if (refused) throw pgError("misuse", `${refused} cannot run inside a transaction block`, "25001");
29157
29766
  const env = {
29158
- ctx: new EngineCtx(this.database.state),
29767
+ ctx: new EngineCtx(this.database.engineState),
29159
29768
  params: typed,
29160
29769
  ctes: /* @__PURE__ */ new Map(),
29161
29770
  outer: null
@@ -29165,12 +29774,13 @@ var Statement = class _Statement {
29165
29774
  return last;
29166
29775
  }
29167
29776
  toRows(res) {
29168
- const ctx = new EngineCtx(this.database.state);
29777
+ const ctx = new EngineCtx(this.database.engineState);
29169
29778
  return res.rows.map((row) => {
29170
29779
  const obj = {};
29171
29780
  for (let i = 0; i < res.columns.length; i++) {
29172
29781
  const c = res.columns[i];
29173
- obj[c.name] = datumToJs(c.type, row[i] ?? null, ctx, this.database.int8Mode);
29782
+ const value = datumToJs(c.type, row[i] ?? null, ctx, this.database.int8Mode);
29783
+ obj[c.name] = value;
29174
29784
  }
29175
29785
  return obj;
29176
29786
  });
@@ -29188,6 +29798,10 @@ function project(point) {
29188
29798
  var Database = class {
29189
29799
  /** @internal Engine catalog, tables, session settings. */
29190
29800
  state;
29801
+ /** @internal Engine-only access; buffered mode observes public state exposure. */
29802
+ engineState;
29803
+ /** @internal Installed only by buffered durability. */
29804
+ durabilityObserver;
29191
29805
  /** Seed used to construct the PRNG. Ignored when {@link randomMode} is `"os"`. */
29192
29806
  seed;
29193
29807
  /** Entropy mode for `random()` / `gen_random_uuid()`. */
@@ -29217,10 +29831,10 @@ var Database = class {
29217
29831
  this.int8Mode = options.int8Mode;
29218
29832
  this.prng = options.prng;
29219
29833
  this.now = options.now;
29220
- this.state = options.state;
29221
- this.state.prng = this.prng;
29222
- this.state.clock = () => this.now();
29223
- this.transactions = txManagerFor(this.state);
29834
+ this.engineState = options.state;
29835
+ this.engineState.prng = this.prng;
29836
+ this.engineState.clock = () => this.now();
29837
+ this.transactions = txManagerFor(this.engineState);
29224
29838
  } else {
29225
29839
  this.seed = options.seed ?? DEFAULT_DATABASE_SEED;
29226
29840
  this.randomMode = options.random ?? "deterministic";
@@ -29228,9 +29842,10 @@ var Database = class {
29228
29842
  this.int8Mode = options.int8 ?? "bigint";
29229
29843
  this.prng = this.randomMode === "os" ? new OsEntropy() : new Prng(this.seed);
29230
29844
  this.now = resolveClock(options.now);
29231
- this.state = new DatabaseState(this.prng, () => this.now());
29232
- this.transactions = txManagerFor(this.state);
29845
+ this.engineState = new DatabaseState(this.prng, () => this.now());
29846
+ this.transactions = txManagerFor(this.engineState);
29233
29847
  }
29848
+ this.state = this.engineState;
29234
29849
  this.timeline = new Timeline({
29235
29850
  now: () => this.now().getTime(),
29236
29851
  ...options.maxCheckpoints !== void 0 ? { maxCheckpoints: options.maxCheckpoints } : {}
@@ -29257,14 +29872,15 @@ var Database = class {
29257
29872
  * a live in-memory snapshot.
29258
29873
  */
29259
29874
  registerFunction(spec) {
29875
+ this.durabilityObserver?.assertWritable();
29260
29876
  this.assertOpen();
29261
29877
  const parts = spec.name.split(".").map((p) => p.trim()).filter((p) => p.length > 0);
29262
29878
  if (parts.length === 0) throw pgError("syntax", "function name is required", "42601");
29263
- const schemaName = (parts.length >= 2 ? parts[0] : this.state.currentSchema()).toLowerCase();
29879
+ const schemaName = (parts.length >= 2 ? parts[0] : this.engineState.currentSchema()).toLowerCase();
29264
29880
  const name = parts[parts.length - 1].toLowerCase();
29265
- const functions = schemaName === "pg_catalog" ? this.state.systemFunctions : this.state.getSchema(schemaName).functions;
29266
- const argTypes = spec.args.map((a) => resolveTypeName(this.state, parseTypeName(a)).column.id);
29267
- const returns = resolveTypeName(this.state, parseTypeName(spec.returns)).column.id;
29881
+ const functions = schemaName === "pg_catalog" ? this.engineState.systemFunctions : this.engineState.getSchema(schemaName).functions;
29882
+ const argTypes = spec.args.map((a) => resolveTypeName(this.engineState, parseTypeName(a)).column.id);
29883
+ const returns = resolveTypeName(this.engineState, parseTypeName(spec.returns)).column.id;
29268
29884
  const fn = {
29269
29885
  name,
29270
29886
  schema: schemaName,
@@ -29278,7 +29894,7 @@ var Database = class {
29278
29894
  body: null,
29279
29895
  rawBody: null,
29280
29896
  strict: spec.strict ?? true,
29281
- oid: this.state.nextOid(),
29897
+ oid: this.engineState.nextOid(),
29282
29898
  jsImpl: spec.fn
29283
29899
  };
29284
29900
  const existing = functions.get(name) ?? [];
@@ -29288,6 +29904,7 @@ var Database = class {
29288
29904
  if (sameSig !== -1) existing[sameSig] = fn;
29289
29905
  else existing.push(fn);
29290
29906
  functions.set(name, existing);
29907
+ this.durabilityObserver?.exposed();
29291
29908
  }
29292
29909
  /** Execute a single-statement query and return all rows keyed by column name. */
29293
29910
  query(sql, params = [], options = {}) {
@@ -29314,6 +29931,7 @@ var Database = class {
29314
29931
  */
29315
29932
  transaction(fn) {
29316
29933
  this.assertOpen();
29934
+ this.durabilityObserver?.assertWritable();
29317
29935
  this.apiTransactionDepth++;
29318
29936
  try {
29319
29937
  if (!this.transactions.inTransaction) {
@@ -29340,6 +29958,7 @@ var Database = class {
29340
29958
  }
29341
29959
  } finally {
29342
29960
  this.apiTransactionDepth--;
29961
+ this.durabilityObserver?.changed();
29343
29962
  }
29344
29963
  }
29345
29964
  /**
@@ -29434,7 +30053,7 @@ var Database = class {
29434
30053
  */
29435
30054
  fault(faults) {
29436
30055
  this.assertOpen();
29437
- Object.assign(this.state.faults, faults);
30056
+ Object.assign(this.engineState.faults, faults);
29438
30057
  }
29439
30058
  /** Close the database. Further SQL throws. Idempotent. */
29440
30059
  close() {
@@ -29444,6 +30063,7 @@ var Database = class {
29444
30063
  }
29445
30064
  if (this.transactions.inTransaction) this.transactions.rollback();
29446
30065
  this.closed = true;
30066
+ this.durabilityObserver?.closed?.();
29447
30067
  }
29448
30068
  /**
29449
30069
  * Execute `COPY table [(cols)] FROM STDIN` with the given text/csv payload
@@ -29462,13 +30082,18 @@ var Database = class {
29462
30082
  if (statements.length !== 1 || !stmt || stmt.type !== "copy" || stmt.direction !== "from") {
29463
30083
  throw pgError("misuse", "copyFrom() requires a single COPY ... FROM STDIN statement", "XX000");
29464
30084
  }
29465
- const env = { ctx: new EngineCtx(this.state), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
29466
- return executeCopyFromData(env, stmt, data).rowCount;
30085
+ this.durabilityObserver?.assertWritable();
30086
+ try {
30087
+ const env = { ctx: new EngineCtx(this.engineState), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
30088
+ return executeCopyFromData(env, stmt, data).rowCount;
30089
+ } finally {
30090
+ this.durabilityObserver?.changed();
30091
+ }
29467
30092
  }
29468
30093
  /** Rows affected by the most recent INSERT / UPDATE / DELETE. */
29469
30094
  get changes() {
29470
30095
  this.assertOpen();
29471
- return this.state.changes;
30096
+ return this.engineState.changes;
29472
30097
  }
29473
30098
  /** @internal */
29474
30099
  assertOpen() {
@@ -29480,7 +30105,7 @@ var Database = class {
29480
30105
  }
29481
30106
  captureLive() {
29482
30107
  return captureSnapshot(
29483
- this.state,
30108
+ this.engineState,
29484
30109
  this.prng,
29485
30110
  this.now,
29486
30111
  this.seed,
@@ -29490,7 +30115,8 @@ var Database = class {
29490
30115
  );
29491
30116
  }
29492
30117
  install(snapshot) {
29493
- this.state.restoreFrom(snapshot.state.cloneShallow());
30118
+ this.durabilityObserver?.exposed();
30119
+ this.engineState.restoreFrom(snapshot.state.cloneShallow());
29494
30120
  this.prng.setState(snapshot.prngState);
29495
30121
  if (!this.systemClock) this.now = fixedClock(new Date(snapshot.nowMs));
29496
30122
  }
@@ -30686,6 +31312,13 @@ var Writer = class {
30686
31312
  this.view.setBigInt64(this.len, value, true);
30687
31313
  this.len += 8;
30688
31314
  }
31315
+ /** Finite integer Number, encoded identically to i64(BigInt(value)) without allocation. */
31316
+ i64Number(value) {
31317
+ this.ensure(8);
31318
+ this.view.setUint32(this.len, value >>> 0, true);
31319
+ this.view.setUint32(this.len + 4, Math.floor(value / 4294967296) >>> 0, true);
31320
+ this.len += 8;
31321
+ }
30689
31322
  f64(value) {
30690
31323
  this.ensure(8);
30691
31324
  this.view.setFloat64(this.len, value, true);
@@ -30696,6 +31329,13 @@ var Writer = class {
30696
31329
  this.buf.set(value, this.len);
30697
31330
  this.len += value.length;
30698
31331
  }
31332
+ /** Reserve one contiguous region. Fill it before any subsequent Writer call can grow the buffer. */
31333
+ block(byteLength) {
31334
+ this.ensure(byteLength);
31335
+ const block = new DataView(this.buf.buffer, this.len, byteLength);
31336
+ this.len += byteLength;
31337
+ return block;
31338
+ }
30699
31339
  /** Length-prefixed UTF-8. */
30700
31340
  text(value) {
30701
31341
  const encoded = utf8Encode(value);
@@ -30708,7 +31348,7 @@ var Writer = class {
30708
31348
  }
30709
31349
  finish() {
30710
31350
  if (this.len === this.buf.length) return this.buf;
30711
- return this.buf.subarray(0, this.len).slice();
31351
+ return this.buf.slice(0, this.len);
30712
31352
  }
30713
31353
  fail() {
30714
31354
  throw new PostgresError("snapshot_format", "invalid or truncated postgres-mem snapshot", "XX000");
@@ -30925,15 +31565,18 @@ function writeInternTable(w, strings) {
30925
31565
  writeVarintU32(w, strings.length);
30926
31566
  if (strings.length === 0) return;
30927
31567
  const offsets = [];
31568
+ const encoded = [];
30928
31569
  let total = 0;
30929
31570
  for (const s of strings) {
30930
31571
  offsets.push(total);
30931
- total += utf8Encode(s).length;
31572
+ const bytes = utf8Encode(s);
31573
+ encoded.push(bytes);
31574
+ total += bytes.length;
30932
31575
  }
30933
31576
  writeVarintU32(w, total);
30934
31577
  const base = w.position + offsets.length * 4;
30935
31578
  for (const off of offsets) w.u32(base + off);
30936
- for (const s of strings) w.textBytes(s);
31579
+ for (const bytes of encoded) w.raw(bytes);
30937
31580
  }
30938
31581
  function readInternTable(r) {
30939
31582
  const count = readVarintU32(r);
@@ -30958,7 +31601,10 @@ var VERSION = 3;
30958
31601
  function encodeDatabaseState(state, runtime) {
30959
31602
  const pool = new InternPool();
30960
31603
  const schemas = [...state.schemas.values()].sort((a, b) => compareNames(a.name, b.name));
31604
+ const internValues = /* @__PURE__ */ new Map();
30961
31605
  for (const schema of schemas) {
31606
+ const values = [];
31607
+ internValues.set(schema, values);
30962
31608
  pool.count(schema.name);
30963
31609
  for (const table of sortedValues(schema.tables)) {
30964
31610
  pool.count(table.name);
@@ -30969,8 +31615,13 @@ function encodeDatabaseState(state, runtime) {
30969
31615
  pool.count(column.domain ?? "");
30970
31616
  if (column.identity) pool.count(column.identity.sequence);
30971
31617
  }
30972
- for (const row of table.allRows()) {
30973
- for (const d of row) if (typeof d === "string") pool.count(d);
31618
+ for (const row of table.serializationRows()) {
31619
+ for (const d of row) {
31620
+ if (typeof d === "string") {
31621
+ pool.count(d);
31622
+ values.push(d);
31623
+ } else if (d !== null && typeof d === "object" && !(d instanceof Uint8Array)) values.push(d);
31624
+ }
30974
31625
  }
30975
31626
  }
30976
31627
  for (const view of sortedValues(schema.views)) {
@@ -30978,7 +31629,12 @@ function encodeDatabaseState(state, runtime) {
30978
31629
  pool.count(view.schema);
30979
31630
  if (view.matRows) {
30980
31631
  for (const row of view.matRows) {
30981
- for (const d of row) if (typeof d === "string") pool.count(d);
31632
+ for (const d of row) {
31633
+ if (typeof d === "string") {
31634
+ pool.count(d);
31635
+ values.push(d);
31636
+ } else if (d !== null && typeof d === "object" && !(d instanceof Uint8Array)) values.push(d);
31637
+ }
30982
31638
  }
30983
31639
  }
30984
31640
  }
@@ -31011,7 +31667,7 @@ function encodeDatabaseState(state, runtime) {
31011
31667
  }
31012
31668
  }
31013
31669
  pool.finalize();
31014
- forceAllEncodeIntern(pool, state, schemas);
31670
+ forceAllEncodeIntern(pool, state, schemas, internValues);
31015
31671
  const internId = (s) => pool.id(s);
31016
31672
  const forceId = (s) => {
31017
31673
  const id = pool.id(s);
@@ -31040,7 +31696,7 @@ function encodeDatabaseState(state, runtime) {
31040
31696
  writeBjv(
31041
31697
  w,
31042
31698
  {
31043
- xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
31699
+ xmins: table.serializationRows().map((row) => table.rowXmins.get(row) ?? 2),
31044
31700
  name: table.name,
31045
31701
  schema: table.schema,
31046
31702
  columns: table.columns,
@@ -31053,7 +31709,7 @@ function encodeDatabaseState(state, runtime) {
31053
31709
  },
31054
31710
  forceId
31055
31711
  );
31056
- const rows = table.allRows();
31712
+ const rows = table.serializationRows();
31057
31713
  writeVarintU32(w, rows.length);
31058
31714
  for (let c = 0; c < table.columns.length; c++) writePackedColumn(w, rows, c, internId, forceId);
31059
31715
  }
@@ -31379,44 +32035,57 @@ function writePackedColumn(w, rows, col, internId, forceId) {
31379
32035
  }
31380
32036
  if (pack === PACK_FLOAT) {
31381
32037
  w.align4();
32038
+ const block = w.block((n - nulls) * 8);
32039
+ let offset = 0;
31382
32040
  for (let i = 0; i < n; i++) {
31383
32041
  if (bits[i >> 3] & 1 << (i & 7)) continue;
31384
- w.f64(rows[i][col]);
32042
+ block.setFloat64(offset, rows[i][col], true);
32043
+ offset += 8;
31385
32044
  }
31386
32045
  return;
31387
32046
  }
31388
32047
  if (pack === PACK_INT) {
31389
32048
  w.align4();
32049
+ const block = w.block((n - nulls) * 8);
32050
+ let offset = 0;
31390
32051
  for (let i = 0; i < n; i++) {
31391
32052
  if (bits[i >> 3] & 1 << (i & 7)) continue;
31392
32053
  const v = rows[i][col];
31393
- w.i64(typeof v === "bigint" ? v : BigInt(v));
32054
+ if (typeof v === "bigint") block.setBigInt64(offset, v, true);
32055
+ else {
32056
+ block.setUint32(offset, v >>> 0, true);
32057
+ block.setUint32(offset + 4, Math.floor(v / 4294967296) >>> 0, true);
32058
+ }
32059
+ offset += 8;
31394
32060
  }
31395
32061
  return;
31396
32062
  }
31397
32063
  if (pack === PACK_TEXT_INTERN) {
31398
32064
  w.align4();
32065
+ const block = w.block((n - nulls) * 4);
32066
+ let offset = 0;
31399
32067
  for (let i = 0; i < n; i++) {
31400
32068
  if (bits[i >> 3] & 1 << (i & 7)) continue;
31401
- w.u32(internId(rows[i][col]));
32069
+ block.setUint32(offset, internId(rows[i][col]), true);
32070
+ offset += 4;
31402
32071
  }
31403
32072
  return;
31404
32073
  }
31405
32074
  if (pack === PACK_TEXT_INLINE) {
31406
32075
  const offsets = [];
32076
+ const encoded = [];
31407
32077
  let blobLen = 0;
31408
32078
  for (let i = 0; i < n; i++) {
31409
32079
  if (bits[i >> 3] & 1 << (i & 7)) continue;
31410
32080
  offsets.push(blobLen);
31411
- blobLen += utf8Encode(rows[i][col]).length;
32081
+ const bytes = utf8Encode(rows[i][col]);
32082
+ encoded.push(bytes);
32083
+ blobLen += bytes.length;
31412
32084
  }
31413
32085
  writeVarintU32(w, offsets.length);
31414
32086
  for (const off of offsets) writeVarintU32(w, off);
31415
32087
  writeVarintU32(w, blobLen);
31416
- for (let i = 0; i < n; i++) {
31417
- if (bits[i >> 3] & 1 << (i & 7)) continue;
31418
- w.textBytes(rows[i][col]);
31419
- }
32088
+ for (const bytes of encoded) w.raw(bytes);
31420
32089
  return;
31421
32090
  }
31422
32091
  if (pack === PACK_BLOB) {
@@ -31616,7 +32285,7 @@ function compareNames(a, b) {
31616
32285
  function sortedValues(map) {
31617
32286
  return [...map.values()].sort((a, b) => compareNames(a.name, b.name));
31618
32287
  }
31619
- function forceAllEncodeIntern(pool, state, schemas) {
32288
+ function forceAllEncodeIntern(pool, state, schemas, internValues) {
31620
32289
  forceSchemaIntern(pool, state, schemas);
31621
32290
  for (const [k, v] of state.settings) {
31622
32291
  pool.forceId(k);
@@ -31628,18 +32297,7 @@ function forceAllEncodeIntern(pool, state, schemas) {
31628
32297
  }
31629
32298
  for (const schema of schemas) {
31630
32299
  pool.forceId(schema.name);
31631
- for (const table of sortedValues(schema.tables)) {
31632
- for (const row of table.allRows()) {
31633
- for (const d of row) forceDatumIntern(pool, d);
31634
- }
31635
- }
31636
- for (const view of sortedValues(schema.views)) {
31637
- if (view.matRows) {
31638
- for (const row of view.matRows) {
31639
- for (const d of row) forceDatumIntern(pool, d);
31640
- }
31641
- }
31642
- }
32300
+ for (const value of internValues.get(schema) ?? []) forceDatumIntern(pool, value);
31643
32301
  }
31644
32302
  }
31645
32303
  function forceDatumIntern(pool, value) {
@@ -31684,7 +32342,8 @@ function forceSchemaIntern(pool, state, schemas) {
31684
32342
  pool.forceId(table.name);
31685
32343
  pool.forceId(table.schema);
31686
32344
  forceBjvStrings(pool, {
31687
- xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
32345
+ // Only strings are interned here. Traversing every numeric xmin cannot add an id.
32346
+ xmins: [],
31688
32347
  name: table.name,
31689
32348
  schema: table.schema,
31690
32349
  columns: table.columns,