@crvouga/mockingbird-service-postgres 3.6.0 → 3.7.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/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # Changelog — @crvouga/mockingbird-service-postgres
2
2
 
3
- ## 3.6.0 (2026-10-16)
3
+ ## 3.7.0 (2026-10-17)
4
+
5
+ ### Features
6
+
7
+ - resolve fleet and emulator issue batch ([26d2f8c](https://github.com/crvouga/mockingbird/commit/26d2f8cee99fefed93192204bac44fb1be35c1da))
8
+
9
+ ## 3.6.0 (2026-10-15)
4
10
 
5
11
  ### Features
6
12
 
package/COMPATIBILITY.md CHANGED
@@ -141,3 +141,34 @@ PostgreSQL; clock profiles are supported. This adds fleet orchestration around e
141
141
  snapshot semantics, not a broader SQL compatibility claim. Acceptance evidence is
142
142
  `packages/adapters/node/fleet.management.test.ts` using the unmodified `pg` wire client.
143
143
  See [Fleets](../../../docs/FLEETS.md).
144
+
145
+ ## Schema preflight and row-version metadata
146
+
147
+ `analyzeSchema(sql, options)` (the package's main export) checks plain schema SQL in a discarded
148
+ in-memory database and returns a JSON-serializable report, including the installed build version,
149
+ statement offsets/lines/columns, object names, SQLSTATEs, independent failures and identifiable
150
+ missing prerequisites. Defaults cap input at 1 MiB, statements at 1,000 and diagnostics at 100;
151
+ configurable hard caps are 4 MiB, 10,000 and 1,000. It does not execute data statements, contact an
152
+ oracle or change an existing database. Accepted statements remain explicitly **unknown** for full
153
+ semantic compatibility, including deferred SQL/PL/pgSQL bodies and dynamic SQL. A detected gap sets
154
+ `compatible: false`; otherwise it stays `null`, never a claim of a verified import. Source-tree
155
+ execution identifies the version as `source-tree`; published builds embed their package version.
156
+ Lexical errors that prevent reliable statement recovery terminate the scan.
157
+
158
+ SQL and PL/pgSQL function definitions retain comma-separated `SET` lists (including `search_path`),
159
+ apply them during calls and restore the caller's settings on return or error. Portable snapshots
160
+ retain these settings. Sequence functions accept explicit `regclass` input, and
161
+ `pg_get_serial_sequence` finds owned serial, identity and explicitly owned sequences using exact
162
+ column-name case; ownership follows sequence/table/column renames and snapshots.
163
+
164
+ Stored tables expose `xmin` and `alias.xmin` as hidden `xid` system columns. INSERT, UPDATE, upsert,
165
+ COPY and referential-action writes stamp row versions with a local transaction identity; explicit
166
+ transactions share that identity, including wire workspace replay and commit. Rollback restores
167
+ committed row metadata. Snapshots preserve identities and continue allocation above retained IDs;
168
+ legacy PGMM snapshots without metadata expose frozen xid `2`. Each database/namespace owns its
169
+ allocator. These identities are version markers, not permanent globally unique row identifiers.
170
+ The implementation does not add full MVCC, VACUUM/freeze maintenance, physical tuple metadata or
171
+ xid wraparound management; it fails when the 32-bit allocation space is exhausted.
172
+
173
+ Evidence: `tests/contract/regressions/issue-queue.test.ts` (PostgreSQL 18.3 differential contracts),
174
+ `tests/contract/api/schema-report.test.ts`, and `tests/wire/issue-queue.test.ts`.
package/README.md CHANGED
@@ -529,6 +529,11 @@ search, `ON CONFLICT DO NOTHING/UPDATE`, `RETURNING`, `PREPARE`/`EXECUTE`/`DEALL
529
529
 
530
530
  ## API
531
531
 
532
+ `analyzeSchema(sql, options?)` returns bounded, JSON-serializable schema compatibility diagnostics
533
+ without changing an application database. Accepted statements remain semantically unverified;
534
+ see [schema preflight and row-version metadata](COMPATIBILITY.md#schema-preflight-and-row-version-metadata)
535
+ for limits, the report contract and `xmin` support.
536
+
532
537
  Stable runtime exports of the main entry:
533
538
 
534
539
  | Export | Description |
package/dist/admin.js CHANGED
@@ -5051,6 +5051,12 @@ var invalidName = () => {
5051
5051
  throw pgError("syntax", "invalid name syntax", "42602");
5052
5052
  };
5053
5053
  function parseNamespaceInput(text) {
5054
+ const parsed = parseRelationInput(text);
5055
+ if ("oid" in parsed) return parsed;
5056
+ if (parsed.parts.length !== 1) invalidName();
5057
+ return { name: parsed.parts[0] };
5058
+ }
5059
+ function parseRelationInput(text) {
5054
5060
  if (text === "-") return { oid: 0 };
5055
5061
  if (/^\d+$/.test(text)) return { oid: parseOidText(text) };
5056
5062
  const names = [];
@@ -5086,8 +5092,8 @@ function parseNamespaceInput(text) {
5086
5092
  skipSpace();
5087
5093
  if (at === text.length) invalidName();
5088
5094
  }
5089
- if (names.length !== 1) invalidName();
5090
- return { name: names[0] };
5095
+ if (names.length === 0 || names.length > 3) invalidName();
5096
+ return { parts: names };
5091
5097
  }
5092
5098
  function namespaceText(oid, name) {
5093
5099
  if (oid === 0) return "-";
@@ -5160,6 +5166,7 @@ var TYPE_ALIASES = {
5160
5166
  regtype: "regtype",
5161
5167
  regproc: "regproc",
5162
5168
  regnamespace: "regnamespace",
5169
+ xid: "xid",
5163
5170
  oid: "oid",
5164
5171
  void: "void",
5165
5172
  record: "record",
@@ -5236,6 +5243,7 @@ var TYPE_OIDS = {
5236
5243
  regproc: 24,
5237
5244
  text: 25,
5238
5245
  oid: 26,
5246
+ xid: 28,
5239
5247
  json: 114,
5240
5248
  float4: 700,
5241
5249
  float8: 701,
@@ -5554,6 +5562,7 @@ function recordText(rec, ctx) {
5554
5562
  return `(${parts.join(",")})`;
5555
5563
  }
5556
5564
  function datumText(t, v, ctx) {
5565
+ if (t === "regclass") return v === 0 ? "-" : ctx.relationName?.(v) ?? String(v);
5557
5566
  if (t === "regnamespace") return namespaceText(v, ctx.namespaceName?.(v));
5558
5567
  if (v === null) throw pgError("internal", "datumText called with null");
5559
5568
  if (isArrayType(t)) return arrayText(v, ctx);
@@ -5564,6 +5573,7 @@ function datumText(t, v, ctx) {
5564
5573
  case "int2":
5565
5574
  case "int4":
5566
5575
  case "oid":
5576
+ case "xid":
5567
5577
  return String(v);
5568
5578
  case "int8":
5569
5579
  return String(v);
@@ -5628,6 +5638,12 @@ function datumText(t, v, ctx) {
5628
5638
  }
5629
5639
  var UTC_INPUT = { zoneOffsetForNaive: () => 0 };
5630
5640
  function datumFromText(t, text, ctx) {
5641
+ if (t === "regclass") {
5642
+ const parsed = parseRelationInput(text);
5643
+ if ("oid" in parsed) return parsed.oid;
5644
+ if (!ctx.relationOid) throw unsupported("regclass input without a catalog");
5645
+ return ctx.relationOid(parsed.parts);
5646
+ }
5631
5647
  if (t === "regnamespace") {
5632
5648
  const parsed = parseNamespaceInput(text);
5633
5649
  if ("oid" in parsed) return parsed.oid;
@@ -5649,6 +5665,7 @@ function datumFromText(t, text, ctx) {
5649
5665
  case "int8":
5650
5666
  return parseIntegerText(text, t);
5651
5667
  case "oid":
5668
+ case "xid":
5652
5669
  return parseOidText(text);
5653
5670
  case "float4":
5654
5671
  return Math.fround(parseFloatText(text, "float4"));
@@ -5805,6 +5822,8 @@ var TableData = class _TableData {
5805
5822
  schema;
5806
5823
  columns;
5807
5824
  rows;
5825
+ rowXmins = /* @__PURE__ */ new WeakMap();
5826
+ slabXmins = null;
5808
5827
  /** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
5809
5828
  slab = null;
5810
5829
  constraints;
@@ -5847,6 +5866,11 @@ var TableData = class _TableData {
5847
5866
  materializeSlab() {
5848
5867
  if (!this.slab) return;
5849
5868
  this.rows = this.slab.materialize();
5869
+ if (this.slabXmins)
5870
+ this.rows.forEach((row, index) => {
5871
+ this.rowXmins.set(row, this.slabXmins[index] ?? 2);
5872
+ });
5873
+ this.slabXmins = null;
5850
5874
  this.slab = null;
5851
5875
  this.indexStores = null;
5852
5876
  }
@@ -5880,6 +5904,10 @@ var TableData = class _TableData {
5880
5904
  } else {
5881
5905
  t.rows = this.rows.map((r) => r.slice());
5882
5906
  }
5907
+ t.rows.forEach((row, index) => {
5908
+ const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.rows[index]);
5909
+ if (xmin !== void 0) t.rowXmins.set(row, xmin);
5910
+ });
5883
5911
  t.unlogged = this.unlogged;
5884
5912
  t.constraints = this.constraints.map((c) => ({ ...c }));
5885
5913
  t.triggers = this.triggers.map((tr) => ({ ...tr }));
@@ -5965,6 +5993,14 @@ var DatabaseState = class _DatabaseState {
5965
5993
  clock;
5966
5994
  changes = 0;
5967
5995
  oidCounter = 16384;
5996
+ /** Local monotonic xid allocator; 2 denotes a row from a legacy snapshot without metadata. */
5997
+ xidCounter = 3;
5998
+ transactionXid = null;
5999
+ allocateXid() {
6000
+ if (this.xidCounter > 4294967295)
6001
+ throw pgError("program_limit_exceeded", "transaction ID space exhausted; xid wraparound is not modeled", "54000");
6002
+ return this.xidCounter++;
6003
+ }
5968
6004
  inTransaction = false;
5969
6005
  /** Transaction-only events: included in rollback clones, never in exported snapshots. */
5970
6006
  pendingTriggers = [];
@@ -6178,6 +6214,8 @@ var DatabaseState = class _DatabaseState {
6178
6214
  s.sequenceCurrval = new Map(this.sequenceCurrval);
6179
6215
  s.tableStats = new Map(this.tableStats);
6180
6216
  s.oidCounter = this.oidCounter;
6217
+ s.xidCounter = this.xidCounter;
6218
+ s.transactionXid = this.transactionXid;
6181
6219
  for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
6182
6220
  return s;
6183
6221
  }
@@ -6197,6 +6235,8 @@ var DatabaseState = class _DatabaseState {
6197
6235
  s.sequenceCurrval = new Map(this.sequenceCurrval);
6198
6236
  s.tableStats = new Map(this.tableStats);
6199
6237
  s.oidCounter = this.oidCounter;
6238
+ s.xidCounter = this.xidCounter;
6239
+ s.transactionXid = this.transactionXid;
6200
6240
  for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
6201
6241
  return s;
6202
6242
  }
@@ -6272,6 +6312,8 @@ var DatabaseState = class _DatabaseState {
6272
6312
  this.sequenceCurrval = other.sequenceCurrval;
6273
6313
  this.tableStats = other.tableStats;
6274
6314
  this.oidCounter = other.oidCounter;
6315
+ this.xidCounter = Math.max(this.xidCounter, other.xidCounter);
6316
+ this.transactionXid = other.transactionXid;
6275
6317
  }
6276
6318
  /** @internal Snapshot codec access to the oid allocator. */
6277
6319
  snapshotOidCounter() {
@@ -6348,6 +6390,11 @@ function zoneOffsetForNaive(zone, naiveMicros) {
6348
6390
  // src/expressions/context.ts
6349
6391
  var EngineCtx = class {
6350
6392
  state;
6393
+ writeXid = null;
6394
+ rowVersionXid() {
6395
+ if (this.state.inTransaction) return this.state.transactionXid ??= this.state.allocateXid();
6396
+ return this.writeXid ??= this.state.allocateXid();
6397
+ }
6351
6398
  /** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
6352
6399
  txNow;
6353
6400
  /** statement timestamp */
@@ -6362,6 +6409,23 @@ var EngineCtx = class {
6362
6409
  timezone() {
6363
6410
  return this.state.getSetting("timezone") ?? "UTC";
6364
6411
  }
6412
+ relationOid(parts) {
6413
+ const target = this.state.resolveRelationSchema(parts);
6414
+ const schema = target ? this.state.schemas.get(target.schema) : void 0;
6415
+ const relation = target ? schema?.sequences.get(target.name) ?? schema?.tables.get(target.name) ?? schema?.views.get(target.name) : void 0;
6416
+ if (!relation) throw pgError("undefined_table", `relation "${parts.join(".")}" does not exist`, "42P01");
6417
+ return relation.oid;
6418
+ }
6419
+ relationName(oid) {
6420
+ for (const schema of this.state.schemas.values()) {
6421
+ for (const relation of [...schema.tables.values(), ...schema.sequences.values(), ...schema.views.values()]) {
6422
+ if (relation.oid !== oid) continue;
6423
+ const visible = this.state.resolveRelationSchema([relation.name])?.schema === schema.name;
6424
+ return (visible ? [relation.name] : [schema.name, relation.name]).map(quoteIdentifier).join(".");
6425
+ }
6426
+ }
6427
+ return null;
6428
+ }
6365
6429
  namespaceOid(name) {
6366
6430
  const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
6367
6431
  if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
@@ -6662,7 +6726,7 @@ function castTo(env, value, target, opts = {}) {
6662
6726
  return tv(target, makeArray(toElem, items, arr.dims.slice(), arr.lbs.slice()));
6663
6727
  }
6664
6728
  if (from === "oid" && target === "regnamespace") return tv(target, v);
6665
- if (from === "regnamespace" && (target === "oid" || target === "int4" || target === "int8")) {
6729
+ if ((from === "regnamespace" || from === "regclass") && (target === "oid" || target === "int4" || target === "int8")) {
6666
6730
  return tv(target, target === "int8" ? BigInt(v) : v);
6667
6731
  }
6668
6732
  if ((from === "int4" || from === "int8" || from === "int2") && (target === "oid" || target === "regnamespace")) {
@@ -7363,6 +7427,8 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
7363
7427
  case "int2":
7364
7428
  case "int4":
7365
7429
  case "oid":
7430
+ case "regclass":
7431
+ case "xid":
7366
7432
  case "regnamespace":
7367
7433
  case "date":
7368
7434
  return expectNumber(a, t) - expectNumber(b, t);
@@ -7482,6 +7548,8 @@ function datumKey(t, v) {
7482
7548
  case "int2":
7483
7549
  case "int4":
7484
7550
  case "oid":
7551
+ case "regclass":
7552
+ case "xid":
7485
7553
  case "date":
7486
7554
  return `i${v}`;
7487
7555
  case "float4":
@@ -10387,7 +10455,7 @@ function databaseCatalogContext(state) {
10387
10455
  var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
10388
10456
  function findSequenceForCall(ctx, name) {
10389
10457
  const parts = parseQualifiedName(name);
10390
- const seq = ctx.state.findSequence(parts);
10458
+ const seq = /^\d+$/.test(name) ? [...ctx.state.schemas.values()].flatMap((schema) => [...schema.sequences.values()]).find((sequence) => sequence.oid === Number(name)) : ctx.state.findSequence(parts);
10391
10459
  if (!seq) {
10392
10460
  throw pgError("undefined_table", `relation "${name}" does not exist`, "42P01");
10393
10461
  }
@@ -10611,14 +10679,16 @@ function getMiscFunctions() {
10611
10679
  "pg_get_serial_sequence",
10612
10680
  strict("text", (ctx, args) => {
10613
10681
  const tableName2 = argText(ctx, args[0]);
10614
- const column = argText(ctx, args[1]).toLowerCase();
10682
+ const column = argText(ctx, args[1]);
10615
10683
  const table = ctx.state.findTable(parseQualifiedName(tableName2));
10616
10684
  if (!table) throw pgError("undefined_table", `relation "${tableName2}" does not exist`, "42P01");
10617
10685
  const col = table.columns.find((c) => c.name === column);
10618
10686
  if (!col)
10619
10687
  throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
10620
- if (!col.identity) return tv("text", null);
10621
- return tv("text", col.identity.sequence.split(".").map(quoteIdent).join("."));
10688
+ const seq = [...ctx.state.schemas.get(table.schema)?.sequences.values() ?? []].find(
10689
+ (candidate) => candidate.ownedBy?.table === table.name && candidate.ownedBy.column === column
10690
+ );
10691
+ return tv("text", seq ? [seq.schema, seq.name].map(quoteIdent).join(".") : null);
10622
10692
  })
10623
10693
  );
10624
10694
  m.set("format_type", (ctx, args) => {
@@ -15562,7 +15632,7 @@ var RowScope = class {
15562
15632
  let count3 = 0;
15563
15633
  for (let i = 0; i < this.columns.length; i++) {
15564
15634
  const c = this.columns[i];
15565
- if (c.name === name2 && !c.hidden) {
15635
+ if (c.name === name2 && (!c.hidden || c.system)) {
15566
15636
  count3++;
15567
15637
  if (count3 > 1) {
15568
15638
  throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
@@ -15600,7 +15670,7 @@ var RowScope = class {
15600
15670
  const names = [];
15601
15671
  for (let i = 0; i < this.columns.length; i++) {
15602
15672
  const c = this.columns[i];
15603
- if (c.table === rangeVar) {
15673
+ if (c.table === rangeVar && !c.system) {
15604
15674
  types.push(c.type);
15605
15675
  values.push(this.row[i] ?? null);
15606
15676
  names.push(c.name);
@@ -16043,7 +16113,7 @@ function tryIndexedFromItem(env, item, where) {
16043
16113
  if (!table) return null;
16044
16114
  const alias = item.alias ?? item.name[item.name.length - 1];
16045
16115
  table.materializeSlab();
16046
- return tryIndexedTableRows(env, table, alias, where);
16116
+ return tryIndexedTableRows(env, table, alias, where)?.map((row) => [...row, table.rowXmins.get(row) ?? 2]) ?? null;
16047
16117
  }
16048
16118
  function joinKeyFromRow(row, colIdxs, srcTypes, unifiedTypes, ctx) {
16049
16119
  const parts = [];
@@ -18533,6 +18603,7 @@ var Parser = class {
18533
18603
  let sqlBody = null;
18534
18604
  let volatility = null;
18535
18605
  let strict2 = false;
18606
+ const settings = {};
18536
18607
  for (; ; ) {
18537
18608
  if (this.eatKw("language")) {
18538
18609
  language = this.peek().type === "string" ? this.next().value : this.ident(true);
@@ -18590,8 +18661,23 @@ var Parser = class {
18590
18661
  continue;
18591
18662
  }
18592
18663
  if (this.eatKw("set")) {
18593
- this.ident(true);
18594
- if (this.eatOp("=") || this.eatKw("to")) this.next();
18664
+ const key = this.ident(true).toLowerCase();
18665
+ if (this.eatKw("from")) {
18666
+ this.expectKw("current");
18667
+ settings[key] = "__from_current__";
18668
+ } else {
18669
+ if (!this.eatOp("=")) this.expectKw("to");
18670
+ const values = [];
18671
+ do {
18672
+ const value = this.next();
18673
+ if (!["string", "ident", "quoted_ident", "number"].includes(value.type))
18674
+ this.errorAt(value, "expected setting value");
18675
+ values.push(
18676
+ key === "search_path" && /[^a-z0-9_]/.test(value.value) ? `"${value.value.replaceAll('"', '""')}"` : value.value
18677
+ );
18678
+ } while (this.eatPunct(","));
18679
+ settings[key] = values.join(", ");
18680
+ }
18595
18681
  continue;
18596
18682
  }
18597
18683
  if (this.eatKw("window")) throw unsupported("window functions via CREATE FUNCTION");
@@ -18671,7 +18757,8 @@ var Parser = class {
18671
18757
  body,
18672
18758
  sqlBody,
18673
18759
  volatility,
18674
- strict: strict2
18760
+ strict: strict2,
18761
+ settings
18675
18762
  };
18676
18763
  }
18677
18764
  parseCreateTrigger(orReplace, constraint) {
@@ -18780,8 +18867,8 @@ var Parser = class {
18780
18867
  type: "alter_sequence",
18781
18868
  name,
18782
18869
  ifExists,
18783
- options: { ownedBy: void 0 },
18784
- ...{ renameTo: to }
18870
+ options: {},
18871
+ renameTo: to
18785
18872
  };
18786
18873
  }
18787
18874
  if (this.atKw("set") && (this.atKw("logged", 1) || this.atKw("unlogged", 1))) {
@@ -21357,7 +21444,20 @@ function runFunctionBody(env, fn, args) {
21357
21444
  }
21358
21445
  return last;
21359
21446
  }
21447
+ function withFunctionSettings(env, fn, run) {
21448
+ const state = env.ctx.state;
21449
+ const saved = new Map(state.localSettings);
21450
+ for (const [name, value] of Object.entries(fn.settings ?? {})) state.localSettings.set(name, value);
21451
+ try {
21452
+ return run();
21453
+ } finally {
21454
+ state.localSettings = saved;
21455
+ }
21456
+ }
21360
21457
  function callSqlFunctionScalar(env, fn, args) {
21458
+ return withFunctionSettings(env, fn, () => callSqlFunctionScalarBody(env, fn, args));
21459
+ }
21460
+ function callSqlFunctionScalarBody(env, fn, args) {
21361
21461
  const retT = fn.returns ?? "text";
21362
21462
  if (fn.language === "plpgsql") {
21363
21463
  return callPlpgsqlScalar(env, fn, args);
@@ -21387,6 +21487,9 @@ function callSqlFunctionScalar(env, fn, args) {
21387
21487
  return castTo(env.ctx, tv(rawT, raw), retT, {});
21388
21488
  }
21389
21489
  function callSqlFunctionSet(env, fn, args) {
21490
+ return withFunctionSettings(env, fn, () => callSqlFunctionSetBody(env, fn, args));
21491
+ }
21492
+ function callSqlFunctionSetBody(env, fn, args) {
21390
21493
  if (fn.language === "plpgsql") {
21391
21494
  return callPlpgsqlSet(env, fn, args);
21392
21495
  }
@@ -21541,15 +21644,17 @@ function executeRecursiveCte(env, cte, query) {
21541
21644
  return rel3;
21542
21645
  }
21543
21646
  function renameWithAliases(rel3, label, colAliases, what) {
21544
- if (colAliases && colAliases.length > rel3.columns.length) {
21647
+ const visibleWidth = rel3.columns.filter((column) => !column.system).length;
21648
+ if (colAliases && colAliases.length > visibleWidth) {
21545
21649
  throw pgError(
21546
21650
  "invalid_column_reference",
21547
- `table "${what}" has ${rel3.columns.length} columns available but ${colAliases.length} columns specified`,
21651
+ `table "${what}" has ${visibleWidth} columns available but ${colAliases.length} columns specified`,
21548
21652
  "42P10"
21549
21653
  );
21550
21654
  }
21551
21655
  const columns = rel3.columns.map((c, i) => ({
21552
- name: colAliases?.[i] ?? c.name,
21656
+ ...c,
21657
+ name: c.system ? c.name : colAliases?.[i] ?? c.name,
21553
21658
  type: c.type === UNKNOWN ? "text" : c.type,
21554
21659
  table: label
21555
21660
  }));
@@ -21570,8 +21675,11 @@ function materializeItem(env, item, scope) {
21570
21675
  if (table) {
21571
21676
  table.materializeSlab();
21572
21677
  const rel3 = {
21573
- columns: table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
21574
- rows: table.rows
21678
+ columns: [
21679
+ ...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
21680
+ { name: "xmin", type: "xid", table: label, hidden: true, system: true }
21681
+ ],
21682
+ rows: table.rows.map((row) => [...row, table.rowXmins.get(row) ?? 2])
21575
21683
  };
21576
21684
  return { rel: renameWithAliases(rel3, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
21577
21685
  }
@@ -22201,7 +22309,7 @@ function resolveColIdx(columns, parts) {
22201
22309
  let found = -1;
22202
22310
  for (let i = 0; i < columns.length; i++) {
22203
22311
  const c = columns[i];
22204
- if (!c.hidden && c.name === name2) {
22312
+ if ((!c.hidden || c.system) && c.name === name2) {
22205
22313
  if (found !== -1) return null;
22206
22314
  found = i;
22207
22315
  }
@@ -22785,7 +22893,7 @@ function expandTargets(core, columns) {
22785
22893
  let any = false;
22786
22894
  for (let i = 0; i < columns.length; i++) {
22787
22895
  const c = columns[i];
22788
- if (c.table === label) {
22896
+ if (c.table === label && !c.system) {
22789
22897
  any = true;
22790
22898
  items.push({ name: c.name, kind: "col", colIdx: i, expr: null, hidden: false });
22791
22899
  }
@@ -23390,6 +23498,7 @@ var TransactionManager = class {
23390
23498
  this.base = null;
23391
23499
  this.savepoints = [];
23392
23500
  this.state.inTransaction = false;
23501
+ this.state.transactionXid = null;
23393
23502
  this.state.localSettings.clear();
23394
23503
  this.state.pendingTriggers = [];
23395
23504
  this.state.constraintModes.clear();
@@ -23402,6 +23511,7 @@ var TransactionManager = class {
23402
23511
  this.base = null;
23403
23512
  this.savepoints = [];
23404
23513
  this.state.inTransaction = false;
23514
+ this.state.transactionXid = null;
23405
23515
  this.state.localSettings.clear();
23406
23516
  this.state.pendingTriggers = [];
23407
23517
  this.state.constraintModes.clear();
@@ -23436,6 +23546,7 @@ var TransactionManager = class {
23436
23546
  this.base = null;
23437
23547
  this.savepoints = [];
23438
23548
  this.state.inTransaction = false;
23549
+ this.state.transactionXid = null;
23439
23550
  this.freezeDepth = 0;
23440
23551
  }
23441
23552
  };
@@ -23639,6 +23750,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
23639
23750
  const updated = existing.slice();
23640
23751
  applyUpdateSets(env, table, sets, scope, updated);
23641
23752
  computeGeneratedColumns(env, table, updated);
23753
+ table.rowXmins.set(updated, env.ctx.rowVersionXid());
23642
23754
  rows[existingIdx] = updated;
23643
23755
  indexUpdateRow(env, table, existingIdx, existing, updated);
23644
23756
  checkNotNull(env, table, updated);
@@ -23724,6 +23836,7 @@ function executeInsert(env0, stmt) {
23724
23836
  checkChecks(env, table, newRow);
23725
23837
  checkUnique(env, table, newRow, rows.length);
23726
23838
  checkForeignKeys(env, table, newRow);
23839
+ table.rowXmins.set(newRow, env.ctx.rowVersionXid());
23727
23840
  rows.push(newRow);
23728
23841
  indexInsertRow(env, table, rows.length - 1, newRow);
23729
23842
  insertedCount++;
@@ -23841,6 +23954,7 @@ function executeUpdate(env0, stmt) {
23841
23954
  if (fired.row === null) continue;
23842
23955
  const finalRow = fired.row;
23843
23956
  computeGeneratedColumns(env, table, finalRow);
23957
+ table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
23844
23958
  rows[ri] = finalRow;
23845
23959
  try {
23846
23960
  checkNotNull(env, table, finalRow);
@@ -23960,6 +24074,7 @@ function handleReferencedDelete(env, table, row, depth) {
23960
24074
  for (const c of con.columns) {
23961
24075
  newRow[child.columnIndex(c)] = null;
23962
24076
  }
24077
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
23963
24078
  childRows[i] = newRow;
23964
24079
  checkNotNull(env, child, newRow);
23965
24080
  checkChecks(env, child, newRow);
@@ -23973,6 +24088,7 @@ function handleReferencedDelete(env, table, row, depth) {
23973
24088
  const ci = child.columnIndex(c);
23974
24089
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
23975
24090
  }
24091
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
23976
24092
  childRows[i] = newRow;
23977
24093
  checkNotNull(env, child, newRow);
23978
24094
  checkChecks(env, child, newRow);
@@ -24010,6 +24126,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
24010
24126
  const refIdx = table.columnIndex(con.refColumns[c]);
24011
24127
  newRow[localIdx] = newRows[r][refIdx] ?? null;
24012
24128
  }
24129
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
24013
24130
  childRows[i] = newRow;
24014
24131
  checkChecks(env, child, newRow);
24015
24132
  }
@@ -24019,6 +24136,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
24019
24136
  for (const i of idxs) {
24020
24137
  const newRow = childRows[i].slice();
24021
24138
  for (const c of con.columns) newRow[child.columnIndex(c)] = null;
24139
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
24022
24140
  childRows[i] = newRow;
24023
24141
  checkNotNull(env, child, newRow);
24024
24142
  }
@@ -24031,6 +24149,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
24031
24149
  const ci = child.columnIndex(c);
24032
24150
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
24033
24151
  }
24152
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
24034
24153
  childRows[i] = newRow;
24035
24154
  checkForeignKeys(env, child, newRow);
24036
24155
  }
@@ -27075,13 +27194,63 @@ function executeCreateSequence(env, stmt) {
27075
27194
  schema.sequences.set(name, seq);
27076
27195
  return commandResult("CREATE SEQUENCE", 0);
27077
27196
  }
27197
+ function renameSequenceReferences(env, seq, newName) {
27198
+ const state = env.ctx.state;
27199
+ const matches3 = (value) => {
27200
+ try {
27201
+ const input = parseRelationInput(value);
27202
+ if ("oid" in input) return input.oid === seq.oid;
27203
+ return state.findSequence(input.parts)?.oid === seq.oid;
27204
+ } catch {
27205
+ return false;
27206
+ }
27207
+ };
27208
+ const rewrite = (value) => {
27209
+ if (Array.isArray(value)) return value.map(rewrite);
27210
+ if (value === null || typeof value !== "object") return value;
27211
+ const node = value;
27212
+ const updated = Object.fromEntries(Object.entries(node).map(([key, child]) => [key, rewrite(child)]));
27213
+ const rewriteLiteral = (literal2) => {
27214
+ if (literal2 && typeof literal2 === "object" && "type" in literal2 && literal2.type === "string_lit" && "value" in literal2 && typeof literal2.value === "string" && matches3(literal2.value)) {
27215
+ return { ...literal2, value: [seq.schema, newName].map(quoteIdent).join(".") };
27216
+ }
27217
+ return literal2;
27218
+ };
27219
+ if (node.type === "func" && Array.isArray(node.name) && ["nextval", "currval", "setval"].includes(String(node.name.at(-1))) && Array.isArray(updated.args))
27220
+ updated.args[0] = rewriteLiteral(updated.args[0]);
27221
+ if (node.type === "cast" && node.target && typeof node.target === "object" && "parts" in node.target && Array.isArray(node.target.parts) && node.target.parts.at(-1) === "regclass")
27222
+ updated.expr = rewriteLiteral(updated.expr);
27223
+ return updated;
27224
+ };
27225
+ for (const schema of state.schemas.values()) {
27226
+ for (const table of [...schema.tables.values()]) {
27227
+ const writable = state.ensureWritableTable(table);
27228
+ for (const column of writable.columns) {
27229
+ if (column.defaultExpr) column.defaultExpr = rewrite(column.defaultExpr);
27230
+ if (column.identity?.sequence === `${seq.schema}.${seq.name}`)
27231
+ column.identity = { ...column.identity, sequence: `${seq.schema}.${newName}` };
27232
+ }
27233
+ }
27234
+ }
27235
+ }
27078
27236
  function executeAlterSequence(env, stmt) {
27079
27237
  const state = env.ctx.state;
27080
- const seq = state.findSequence(stmt.name);
27081
- if (!seq) {
27238
+ const foundSequence = state.findSequence(stmt.name);
27239
+ if (!foundSequence) {
27082
27240
  if (stmt.ifExists) return commandResult("ALTER SEQUENCE", 0);
27083
27241
  throw pgError("undefined_table", `relation "${stmt.name.join(".")}" does not exist`, "42P01");
27084
27242
  }
27243
+ const seq = state.ensureWritableSequence(foundSequence);
27244
+ if (stmt.renameTo) {
27245
+ const schema = state.getSchema(seq.schema);
27246
+ if (schema.hasRelation(stmt.renameTo))
27247
+ throw pgError("duplicate_table", `relation "${stmt.renameTo}" already exists`, "42P07");
27248
+ renameSequenceReferences(env, seq, stmt.renameTo);
27249
+ schema.sequences.delete(seq.name);
27250
+ seq.name = stmt.renameTo;
27251
+ schema.sequences.set(seq.name, seq);
27252
+ return commandResult("ALTER SEQUENCE", 0);
27253
+ }
27085
27254
  const o = stmt.options;
27086
27255
  if (o.logged !== void 0) {
27087
27256
  setSequenceLogged(state, seq, o.logged);
@@ -27139,7 +27308,7 @@ function buildColumn(env, schema, tableName2, def, out, taken) {
27139
27308
  col.defaultExpr = {
27140
27309
  type: "func",
27141
27310
  name: ["nextval"],
27142
- args: [{ type: "string_lit", value: `${schema.name}.${seqName}` }]
27311
+ args: [{ type: "string_lit", value: [schema.name, seqName].map(quoteIdent).join(".") }]
27143
27312
  };
27144
27313
  }
27145
27314
  for (const c of def.constraints) {
@@ -27392,7 +27561,11 @@ function executeCreateTableAs(env, stmt) {
27392
27561
  const table = new TableData(schema.name, name, columns, state.nextOid(), stmt.temp);
27393
27562
  table.unlogged = stmt.unlogged === true;
27394
27563
  if (stmt.withData) {
27395
- for (const row of rel3.rows) table.mutableRows().push(row.slice());
27564
+ for (const row of rel3.rows) {
27565
+ const stored = row.slice();
27566
+ table.rowXmins.set(stored, env.ctx.rowVersionXid());
27567
+ table.mutableRows().push(stored);
27568
+ }
27396
27569
  }
27397
27570
  schema.tables.set(name, table);
27398
27571
  const count2 = stmt.withData ? table.rowCount() : 0;
@@ -27661,6 +27834,12 @@ function executeCreateFunction(env, stmt) {
27661
27834
  language: lang,
27662
27835
  body,
27663
27836
  rawBody: stmt.body,
27837
+ settings: Object.fromEntries(
27838
+ Object.entries(stmt.settings ?? {}).map(([key, value]) => [
27839
+ key,
27840
+ value === "__from_current__" ? state.getSetting(key) ?? "" : value
27841
+ ])
27842
+ ),
27664
27843
  strict: stmt.strict,
27665
27844
  oid: state.nextOid()
27666
27845
  };
@@ -27845,6 +28024,7 @@ function executeAlterTable(env, stmt) {
27845
28024
  }
27846
28025
  const next = row.slice();
27847
28026
  next[idx] = nv;
28027
+ table.rowXmins.set(next, table.rowXmins.get(rows[i]) ?? 2);
27848
28028
  rows[i] = next;
27849
28029
  }
27850
28030
  col.type = resolved.column;
@@ -27946,6 +28126,11 @@ function executeAlterTable(env, stmt) {
27946
28126
  );
27947
28127
  }
27948
28128
  table.columns[idx].name = action.to;
28129
+ for (const seq of [...schema.sequences.values()]) {
28130
+ if (seq.ownedBy?.table === table.name && seq.ownedBy.column === action.from) {
28131
+ state.ensureWritableSequence(seq).ownedBy = { table: table.name, column: action.to };
28132
+ }
28133
+ }
27949
28134
  for (const con of table.constraints) {
27950
28135
  if (con.kind === "primary_key" || con.kind === "unique" || con.kind === "foreign_key") {
27951
28136
  con.columns = con.columns.map((c) => c === action.from ? action.to : c);
@@ -27982,6 +28167,11 @@ function executeAlterTable(env, stmt) {
27982
28167
  throw pgError("duplicate_table", `relation "${action.to}" already exists`, "42P07");
27983
28168
  }
27984
28169
  const oldName = table.name;
28170
+ for (const seq of [...schema.sequences.values()]) {
28171
+ if (seq.ownedBy?.table === oldName) {
28172
+ state.ensureWritableSequence(seq).ownedBy = { ...seq.ownedBy, table: action.to };
28173
+ }
28174
+ }
27985
28175
  schema.tables.delete(table.name);
27986
28176
  table.name = action.to;
27987
28177
  schema.tables.set(action.to, table);