@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.
@@ -2803,6 +2803,12 @@ var invalidName = () => {
2803
2803
  throw pgError("syntax", "invalid name syntax", "42602");
2804
2804
  };
2805
2805
  function parseNamespaceInput(text) {
2806
+ const parsed = parseRelationInput(text);
2807
+ if ("oid" in parsed) return parsed;
2808
+ if (parsed.parts.length !== 1) invalidName();
2809
+ return { name: parsed.parts[0] };
2810
+ }
2811
+ function parseRelationInput(text) {
2806
2812
  if (text === "-") return { oid: 0 };
2807
2813
  if (/^\d+$/.test(text)) return { oid: parseOidText(text) };
2808
2814
  const names = [];
@@ -2838,8 +2844,8 @@ function parseNamespaceInput(text) {
2838
2844
  skipSpace();
2839
2845
  if (at === text.length) invalidName();
2840
2846
  }
2841
- if (names.length !== 1) invalidName();
2842
- return { name: names[0] };
2847
+ if (names.length === 0 || names.length > 3) invalidName();
2848
+ return { parts: names };
2843
2849
  }
2844
2850
  function namespaceText(oid, name) {
2845
2851
  if (oid === 0) return "-";
@@ -2912,6 +2918,7 @@ var TYPE_ALIASES = {
2912
2918
  regtype: "regtype",
2913
2919
  regproc: "regproc",
2914
2920
  regnamespace: "regnamespace",
2921
+ xid: "xid",
2915
2922
  oid: "oid",
2916
2923
  void: "void",
2917
2924
  record: "record",
@@ -2988,6 +2995,7 @@ var TYPE_OIDS = {
2988
2995
  regproc: 24,
2989
2996
  text: 25,
2990
2997
  oid: 26,
2998
+ xid: 28,
2991
2999
  json: 114,
2992
3000
  float4: 700,
2993
3001
  float8: 701,
@@ -3307,6 +3315,7 @@ function recordText(rec, ctx) {
3307
3315
  return `(${parts.join(",")})`;
3308
3316
  }
3309
3317
  function datumText(t, v, ctx) {
3318
+ if (t === "regclass") return v === 0 ? "-" : ctx.relationName?.(v) ?? String(v);
3310
3319
  if (t === "regnamespace") return namespaceText(v, ctx.namespaceName?.(v));
3311
3320
  if (v === null) throw pgError("internal", "datumText called with null");
3312
3321
  if (isArrayType(t)) return arrayText(v, ctx);
@@ -3317,6 +3326,7 @@ function datumText(t, v, ctx) {
3317
3326
  case "int2":
3318
3327
  case "int4":
3319
3328
  case "oid":
3329
+ case "xid":
3320
3330
  return String(v);
3321
3331
  case "int8":
3322
3332
  return String(v);
@@ -3381,6 +3391,12 @@ function datumText(t, v, ctx) {
3381
3391
  }
3382
3392
  var UTC_INPUT = { zoneOffsetForNaive: () => 0 };
3383
3393
  function datumFromText(t, text, ctx) {
3394
+ if (t === "regclass") {
3395
+ const parsed = parseRelationInput(text);
3396
+ if ("oid" in parsed) return parsed.oid;
3397
+ if (!ctx.relationOid) throw unsupported("regclass input without a catalog");
3398
+ return ctx.relationOid(parsed.parts);
3399
+ }
3384
3400
  if (t === "regnamespace") {
3385
3401
  const parsed = parseNamespaceInput(text);
3386
3402
  if ("oid" in parsed) return parsed.oid;
@@ -3402,6 +3418,7 @@ function datumFromText(t, text, ctx) {
3402
3418
  case "int8":
3403
3419
  return parseIntegerText(text, t);
3404
3420
  case "oid":
3421
+ case "xid":
3405
3422
  return parseOidText(text);
3406
3423
  case "float4":
3407
3424
  return Math.fround(parseFloatText(text, "float4"));
@@ -3558,6 +3575,8 @@ var TableData = class _TableData {
3558
3575
  schema;
3559
3576
  columns;
3560
3577
  rows;
3578
+ rowXmins = /* @__PURE__ */ new WeakMap();
3579
+ slabXmins = null;
3561
3580
  /** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
3562
3581
  slab = null;
3563
3582
  constraints;
@@ -3600,6 +3619,11 @@ var TableData = class _TableData {
3600
3619
  materializeSlab() {
3601
3620
  if (!this.slab) return;
3602
3621
  this.rows = this.slab.materialize();
3622
+ if (this.slabXmins)
3623
+ this.rows.forEach((row, index) => {
3624
+ this.rowXmins.set(row, this.slabXmins[index] ?? 2);
3625
+ });
3626
+ this.slabXmins = null;
3603
3627
  this.slab = null;
3604
3628
  this.indexStores = null;
3605
3629
  }
@@ -3633,6 +3657,10 @@ var TableData = class _TableData {
3633
3657
  } else {
3634
3658
  t.rows = this.rows.map((r) => r.slice());
3635
3659
  }
3660
+ t.rows.forEach((row, index) => {
3661
+ const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.rows[index]);
3662
+ if (xmin !== void 0) t.rowXmins.set(row, xmin);
3663
+ });
3636
3664
  t.unlogged = this.unlogged;
3637
3665
  t.constraints = this.constraints.map((c) => ({ ...c }));
3638
3666
  t.triggers = this.triggers.map((tr) => ({ ...tr }));
@@ -3718,6 +3746,14 @@ var DatabaseState = class _DatabaseState {
3718
3746
  clock;
3719
3747
  changes = 0;
3720
3748
  oidCounter = 16384;
3749
+ /** Local monotonic xid allocator; 2 denotes a row from a legacy snapshot without metadata. */
3750
+ xidCounter = 3;
3751
+ transactionXid = null;
3752
+ allocateXid() {
3753
+ if (this.xidCounter > 4294967295)
3754
+ throw pgError("program_limit_exceeded", "transaction ID space exhausted; xid wraparound is not modeled", "54000");
3755
+ return this.xidCounter++;
3756
+ }
3721
3757
  inTransaction = false;
3722
3758
  /** Transaction-only events: included in rollback clones, never in exported snapshots. */
3723
3759
  pendingTriggers = [];
@@ -3931,6 +3967,8 @@ var DatabaseState = class _DatabaseState {
3931
3967
  s.sequenceCurrval = new Map(this.sequenceCurrval);
3932
3968
  s.tableStats = new Map(this.tableStats);
3933
3969
  s.oidCounter = this.oidCounter;
3970
+ s.xidCounter = this.xidCounter;
3971
+ s.transactionXid = this.transactionXid;
3934
3972
  for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
3935
3973
  return s;
3936
3974
  }
@@ -3950,6 +3988,8 @@ var DatabaseState = class _DatabaseState {
3950
3988
  s.sequenceCurrval = new Map(this.sequenceCurrval);
3951
3989
  s.tableStats = new Map(this.tableStats);
3952
3990
  s.oidCounter = this.oidCounter;
3991
+ s.xidCounter = this.xidCounter;
3992
+ s.transactionXid = this.transactionXid;
3953
3993
  for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
3954
3994
  return s;
3955
3995
  }
@@ -4025,6 +4065,8 @@ var DatabaseState = class _DatabaseState {
4025
4065
  this.sequenceCurrval = other.sequenceCurrval;
4026
4066
  this.tableStats = other.tableStats;
4027
4067
  this.oidCounter = other.oidCounter;
4068
+ this.xidCounter = Math.max(this.xidCounter, other.xidCounter);
4069
+ this.transactionXid = other.transactionXid;
4028
4070
  }
4029
4071
  /** @internal Snapshot codec access to the oid allocator. */
4030
4072
  snapshotOidCounter() {
@@ -4104,6 +4146,11 @@ function validateZone(zone) {
4104
4146
  // src/expressions/context.ts
4105
4147
  var EngineCtx = class {
4106
4148
  state;
4149
+ writeXid = null;
4150
+ rowVersionXid() {
4151
+ if (this.state.inTransaction) return this.state.transactionXid ??= this.state.allocateXid();
4152
+ return this.writeXid ??= this.state.allocateXid();
4153
+ }
4107
4154
  /** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
4108
4155
  txNow;
4109
4156
  /** statement timestamp */
@@ -4118,6 +4165,23 @@ var EngineCtx = class {
4118
4165
  timezone() {
4119
4166
  return this.state.getSetting("timezone") ?? "UTC";
4120
4167
  }
4168
+ relationOid(parts) {
4169
+ const target = this.state.resolveRelationSchema(parts);
4170
+ const schema = target ? this.state.schemas.get(target.schema) : void 0;
4171
+ const relation = target ? schema?.sequences.get(target.name) ?? schema?.tables.get(target.name) ?? schema?.views.get(target.name) : void 0;
4172
+ if (!relation) throw pgError("undefined_table", `relation "${parts.join(".")}" does not exist`, "42P01");
4173
+ return relation.oid;
4174
+ }
4175
+ relationName(oid) {
4176
+ for (const schema of this.state.schemas.values()) {
4177
+ for (const relation of [...schema.tables.values(), ...schema.sequences.values(), ...schema.views.values()]) {
4178
+ if (relation.oid !== oid) continue;
4179
+ const visible = this.state.resolveRelationSchema([relation.name])?.schema === schema.name;
4180
+ return (visible ? [relation.name] : [schema.name, relation.name]).map(quoteIdentifier).join(".");
4181
+ }
4182
+ }
4183
+ return null;
4184
+ }
4121
4185
  namespaceOid(name) {
4122
4186
  const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
4123
4187
  if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
@@ -4418,7 +4482,7 @@ function castTo(env, value, target, opts = {}) {
4418
4482
  return tv(target, makeArray(toElem, items, arr.dims.slice(), arr.lbs.slice()));
4419
4483
  }
4420
4484
  if (from === "oid" && target === "regnamespace") return tv(target, v);
4421
- if (from === "regnamespace" && (target === "oid" || target === "int4" || target === "int8")) {
4485
+ if ((from === "regnamespace" || from === "regclass") && (target === "oid" || target === "int4" || target === "int8")) {
4422
4486
  return tv(target, target === "int8" ? BigInt(v) : v);
4423
4487
  }
4424
4488
  if ((from === "int4" || from === "int8" || from === "int2") && (target === "oid" || target === "regnamespace")) {
@@ -5119,6 +5183,8 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
5119
5183
  case "int2":
5120
5184
  case "int4":
5121
5185
  case "oid":
5186
+ case "regclass":
5187
+ case "xid":
5122
5188
  case "regnamespace":
5123
5189
  case "date":
5124
5190
  return expectNumber(a, t) - expectNumber(b, t);
@@ -5238,6 +5304,8 @@ function datumKey(t, v) {
5238
5304
  case "int2":
5239
5305
  case "int4":
5240
5306
  case "oid":
5307
+ case "regclass":
5308
+ case "xid":
5241
5309
  case "date":
5242
5310
  return `i${v}`;
5243
5311
  case "float4":
@@ -8146,7 +8214,7 @@ function setDatabaseCatalogContext(state, context) {
8146
8214
  var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
8147
8215
  function findSequenceForCall(ctx, name) {
8148
8216
  const parts = parseQualifiedName(name);
8149
- const seq = ctx.state.findSequence(parts);
8217
+ const seq = /^\d+$/.test(name) ? [...ctx.state.schemas.values()].flatMap((schema) => [...schema.sequences.values()]).find((sequence) => sequence.oid === Number(name)) : ctx.state.findSequence(parts);
8150
8218
  if (!seq) {
8151
8219
  throw pgError("undefined_table", `relation "${name}" does not exist`, "42P01");
8152
8220
  }
@@ -8370,14 +8438,16 @@ function getMiscFunctions() {
8370
8438
  "pg_get_serial_sequence",
8371
8439
  strict("text", (ctx, args) => {
8372
8440
  const tableName2 = argText(ctx, args[0]);
8373
- const column = argText(ctx, args[1]).toLowerCase();
8441
+ const column = argText(ctx, args[1]);
8374
8442
  const table = ctx.state.findTable(parseQualifiedName(tableName2));
8375
8443
  if (!table) throw pgError("undefined_table", `relation "${tableName2}" does not exist`, "42P01");
8376
8444
  const col = table.columns.find((c) => c.name === column);
8377
8445
  if (!col)
8378
8446
  throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
8379
- if (!col.identity) return tv("text", null);
8380
- return tv("text", col.identity.sequence.split(".").map(quoteIdent).join("."));
8447
+ const seq = [...ctx.state.schemas.get(table.schema)?.sequences.values() ?? []].find(
8448
+ (candidate) => candidate.ownedBy?.table === table.name && candidate.ownedBy.column === column
8449
+ );
8450
+ return tv("text", seq ? [seq.schema, seq.name].map(quoteIdent).join(".") : null);
8381
8451
  })
8382
8452
  );
8383
8453
  m.set("format_type", (ctx, args) => {
@@ -13321,7 +13391,7 @@ var RowScope = class {
13321
13391
  let count2 = 0;
13322
13392
  for (let i = 0; i < this.columns.length; i++) {
13323
13393
  const c = this.columns[i];
13324
- if (c.name === name2 && !c.hidden) {
13394
+ if (c.name === name2 && (!c.hidden || c.system)) {
13325
13395
  count2++;
13326
13396
  if (count2 > 1) {
13327
13397
  throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
@@ -13359,7 +13429,7 @@ var RowScope = class {
13359
13429
  const names = [];
13360
13430
  for (let i = 0; i < this.columns.length; i++) {
13361
13431
  const c = this.columns[i];
13362
- if (c.table === rangeVar) {
13432
+ if (c.table === rangeVar && !c.system) {
13363
13433
  types.push(c.type);
13364
13434
  values.push(this.row[i] ?? null);
13365
13435
  names.push(c.name);
@@ -13802,7 +13872,7 @@ function tryIndexedFromItem(env, item, where) {
13802
13872
  if (!table) return null;
13803
13873
  const alias = item.alias ?? item.name[item.name.length - 1];
13804
13874
  table.materializeSlab();
13805
- return tryIndexedTableRows(env, table, alias, where);
13875
+ return tryIndexedTableRows(env, table, alias, where)?.map((row) => [...row, table.rowXmins.get(row) ?? 2]) ?? null;
13806
13876
  }
13807
13877
  function joinKeyFromRow(row, colIdxs, srcTypes, unifiedTypes, ctx) {
13808
13878
  const parts = [];
@@ -16292,6 +16362,7 @@ var Parser = class {
16292
16362
  let sqlBody = null;
16293
16363
  let volatility = null;
16294
16364
  let strict2 = false;
16365
+ const settings = {};
16295
16366
  for (; ; ) {
16296
16367
  if (this.eatKw("language")) {
16297
16368
  language = this.peek().type === "string" ? this.next().value : this.ident(true);
@@ -16349,8 +16420,23 @@ var Parser = class {
16349
16420
  continue;
16350
16421
  }
16351
16422
  if (this.eatKw("set")) {
16352
- this.ident(true);
16353
- if (this.eatOp("=") || this.eatKw("to")) this.next();
16423
+ const key = this.ident(true).toLowerCase();
16424
+ if (this.eatKw("from")) {
16425
+ this.expectKw("current");
16426
+ settings[key] = "__from_current__";
16427
+ } else {
16428
+ if (!this.eatOp("=")) this.expectKw("to");
16429
+ const values = [];
16430
+ do {
16431
+ const value = this.next();
16432
+ if (!["string", "ident", "quoted_ident", "number"].includes(value.type))
16433
+ this.errorAt(value, "expected setting value");
16434
+ values.push(
16435
+ key === "search_path" && /[^a-z0-9_]/.test(value.value) ? `"${value.value.replaceAll('"', '""')}"` : value.value
16436
+ );
16437
+ } while (this.eatPunct(","));
16438
+ settings[key] = values.join(", ");
16439
+ }
16354
16440
  continue;
16355
16441
  }
16356
16442
  if (this.eatKw("window")) throw unsupported("window functions via CREATE FUNCTION");
@@ -16430,7 +16516,8 @@ var Parser = class {
16430
16516
  body,
16431
16517
  sqlBody,
16432
16518
  volatility,
16433
- strict: strict2
16519
+ strict: strict2,
16520
+ settings
16434
16521
  };
16435
16522
  }
16436
16523
  parseCreateTrigger(orReplace, constraint) {
@@ -16539,8 +16626,8 @@ var Parser = class {
16539
16626
  type: "alter_sequence",
16540
16627
  name,
16541
16628
  ifExists,
16542
- options: { ownedBy: void 0 },
16543
- ...{ renameTo: to }
16629
+ options: {},
16630
+ renameTo: to
16544
16631
  };
16545
16632
  }
16546
16633
  if (this.atKw("set") && (this.atKw("logged", 1) || this.atKw("unlogged", 1))) {
@@ -19116,7 +19203,20 @@ function runFunctionBody(env, fn, args) {
19116
19203
  }
19117
19204
  return last;
19118
19205
  }
19206
+ function withFunctionSettings(env, fn, run) {
19207
+ const state = env.ctx.state;
19208
+ const saved = new Map(state.localSettings);
19209
+ for (const [name, value] of Object.entries(fn.settings ?? {})) state.localSettings.set(name, value);
19210
+ try {
19211
+ return run();
19212
+ } finally {
19213
+ state.localSettings = saved;
19214
+ }
19215
+ }
19119
19216
  function callSqlFunctionScalar(env, fn, args) {
19217
+ return withFunctionSettings(env, fn, () => callSqlFunctionScalarBody(env, fn, args));
19218
+ }
19219
+ function callSqlFunctionScalarBody(env, fn, args) {
19120
19220
  const retT = fn.returns ?? "text";
19121
19221
  if (fn.language === "plpgsql") {
19122
19222
  return callPlpgsqlScalar(env, fn, args);
@@ -19146,6 +19246,9 @@ function callSqlFunctionScalar(env, fn, args) {
19146
19246
  return castTo(env.ctx, tv(rawT, raw), retT, {});
19147
19247
  }
19148
19248
  function callSqlFunctionSet(env, fn, args) {
19249
+ return withFunctionSettings(env, fn, () => callSqlFunctionSetBody(env, fn, args));
19250
+ }
19251
+ function callSqlFunctionSetBody(env, fn, args) {
19149
19252
  if (fn.language === "plpgsql") {
19150
19253
  return callPlpgsqlSet(env, fn, args);
19151
19254
  }
@@ -19300,15 +19403,17 @@ function executeRecursiveCte(env, cte, query) {
19300
19403
  return rel3;
19301
19404
  }
19302
19405
  function renameWithAliases(rel3, label, colAliases, what) {
19303
- if (colAliases && colAliases.length > rel3.columns.length) {
19406
+ const visibleWidth = rel3.columns.filter((column) => !column.system).length;
19407
+ if (colAliases && colAliases.length > visibleWidth) {
19304
19408
  throw pgError(
19305
19409
  "invalid_column_reference",
19306
- `table "${what}" has ${rel3.columns.length} columns available but ${colAliases.length} columns specified`,
19410
+ `table "${what}" has ${visibleWidth} columns available but ${colAliases.length} columns specified`,
19307
19411
  "42P10"
19308
19412
  );
19309
19413
  }
19310
19414
  const columns = rel3.columns.map((c, i) => ({
19311
- name: colAliases?.[i] ?? c.name,
19415
+ ...c,
19416
+ name: c.system ? c.name : colAliases?.[i] ?? c.name,
19312
19417
  type: c.type === UNKNOWN ? "text" : c.type,
19313
19418
  table: label
19314
19419
  }));
@@ -19329,8 +19434,11 @@ function materializeItem(env, item, scope) {
19329
19434
  if (table) {
19330
19435
  table.materializeSlab();
19331
19436
  const rel3 = {
19332
- columns: table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
19333
- rows: table.rows
19437
+ columns: [
19438
+ ...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
19439
+ { name: "xmin", type: "xid", table: label, hidden: true, system: true }
19440
+ ],
19441
+ rows: table.rows.map((row) => [...row, table.rowXmins.get(row) ?? 2])
19334
19442
  };
19335
19443
  return { rel: renameWithAliases(rel3, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
19336
19444
  }
@@ -19960,7 +20068,7 @@ function resolveColIdx(columns, parts) {
19960
20068
  let found = -1;
19961
20069
  for (let i = 0; i < columns.length; i++) {
19962
20070
  const c = columns[i];
19963
- if (!c.hidden && c.name === name2) {
20071
+ if ((!c.hidden || c.system) && c.name === name2) {
19964
20072
  if (found !== -1) return null;
19965
20073
  found = i;
19966
20074
  }
@@ -20544,7 +20652,7 @@ function expandTargets(core, columns) {
20544
20652
  let any = false;
20545
20653
  for (let i = 0; i < columns.length; i++) {
20546
20654
  const c = columns[i];
20547
- if (c.table === label) {
20655
+ if (c.table === label && !c.system) {
20548
20656
  any = true;
20549
20657
  items.push({ name: c.name, kind: "col", colIdx: i, expr: null, hidden: false });
20550
20658
  }
@@ -21149,6 +21257,7 @@ var TransactionManager = class {
21149
21257
  this.base = null;
21150
21258
  this.savepoints = [];
21151
21259
  this.state.inTransaction = false;
21260
+ this.state.transactionXid = null;
21152
21261
  this.state.localSettings.clear();
21153
21262
  this.state.pendingTriggers = [];
21154
21263
  this.state.constraintModes.clear();
@@ -21161,6 +21270,7 @@ var TransactionManager = class {
21161
21270
  this.base = null;
21162
21271
  this.savepoints = [];
21163
21272
  this.state.inTransaction = false;
21273
+ this.state.transactionXid = null;
21164
21274
  this.state.localSettings.clear();
21165
21275
  this.state.pendingTriggers = [];
21166
21276
  this.state.constraintModes.clear();
@@ -21195,6 +21305,7 @@ var TransactionManager = class {
21195
21305
  this.base = null;
21196
21306
  this.savepoints = [];
21197
21307
  this.state.inTransaction = false;
21308
+ this.state.transactionXid = null;
21198
21309
  this.freezeDepth = 0;
21199
21310
  }
21200
21311
  };
@@ -21398,6 +21509,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
21398
21509
  const updated = existing.slice();
21399
21510
  applyUpdateSets(env, table, sets, scope, updated);
21400
21511
  computeGeneratedColumns(env, table, updated);
21512
+ table.rowXmins.set(updated, env.ctx.rowVersionXid());
21401
21513
  rows[existingIdx] = updated;
21402
21514
  indexUpdateRow(env, table, existingIdx, existing, updated);
21403
21515
  checkNotNull(env, table, updated);
@@ -21483,6 +21595,7 @@ function executeInsert(env0, stmt) {
21483
21595
  checkChecks(env, table, newRow);
21484
21596
  checkUnique(env, table, newRow, rows.length);
21485
21597
  checkForeignKeys(env, table, newRow);
21598
+ table.rowXmins.set(newRow, env.ctx.rowVersionXid());
21486
21599
  rows.push(newRow);
21487
21600
  indexInsertRow(env, table, rows.length - 1, newRow);
21488
21601
  insertedCount++;
@@ -21600,6 +21713,7 @@ function executeUpdate(env0, stmt) {
21600
21713
  if (fired.row === null) continue;
21601
21714
  const finalRow = fired.row;
21602
21715
  computeGeneratedColumns(env, table, finalRow);
21716
+ table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
21603
21717
  rows[ri] = finalRow;
21604
21718
  try {
21605
21719
  checkNotNull(env, table, finalRow);
@@ -21719,6 +21833,7 @@ function handleReferencedDelete(env, table, row, depth) {
21719
21833
  for (const c of con.columns) {
21720
21834
  newRow[child.columnIndex(c)] = null;
21721
21835
  }
21836
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
21722
21837
  childRows[i] = newRow;
21723
21838
  checkNotNull(env, child, newRow);
21724
21839
  checkChecks(env, child, newRow);
@@ -21732,6 +21847,7 @@ function handleReferencedDelete(env, table, row, depth) {
21732
21847
  const ci = child.columnIndex(c);
21733
21848
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
21734
21849
  }
21850
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
21735
21851
  childRows[i] = newRow;
21736
21852
  checkNotNull(env, child, newRow);
21737
21853
  checkChecks(env, child, newRow);
@@ -21769,6 +21885,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
21769
21885
  const refIdx = table.columnIndex(con.refColumns[c]);
21770
21886
  newRow[localIdx] = newRows[r][refIdx] ?? null;
21771
21887
  }
21888
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
21772
21889
  childRows[i] = newRow;
21773
21890
  checkChecks(env, child, newRow);
21774
21891
  }
@@ -21778,6 +21895,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
21778
21895
  for (const i of idxs) {
21779
21896
  const newRow = childRows[i].slice();
21780
21897
  for (const c of con.columns) newRow[child.columnIndex(c)] = null;
21898
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
21781
21899
  childRows[i] = newRow;
21782
21900
  checkNotNull(env, child, newRow);
21783
21901
  }
@@ -21790,6 +21908,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
21790
21908
  const ci = child.columnIndex(c);
21791
21909
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
21792
21910
  }
21911
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
21793
21912
  childRows[i] = newRow;
21794
21913
  checkForeignKeys(env, child, newRow);
21795
21914
  }
@@ -24837,13 +24956,63 @@ function executeCreateSequence(env, stmt) {
24837
24956
  schema.sequences.set(name, seq);
24838
24957
  return commandResult("CREATE SEQUENCE", 0);
24839
24958
  }
24959
+ function renameSequenceReferences(env, seq, newName) {
24960
+ const state = env.ctx.state;
24961
+ const matches2 = (value) => {
24962
+ try {
24963
+ const input = parseRelationInput(value);
24964
+ if ("oid" in input) return input.oid === seq.oid;
24965
+ return state.findSequence(input.parts)?.oid === seq.oid;
24966
+ } catch {
24967
+ return false;
24968
+ }
24969
+ };
24970
+ const rewrite = (value) => {
24971
+ if (Array.isArray(value)) return value.map(rewrite);
24972
+ if (value === null || typeof value !== "object") return value;
24973
+ const node = value;
24974
+ const updated = Object.fromEntries(Object.entries(node).map(([key, child]) => [key, rewrite(child)]));
24975
+ const rewriteLiteral = (literal2) => {
24976
+ if (literal2 && typeof literal2 === "object" && "type" in literal2 && literal2.type === "string_lit" && "value" in literal2 && typeof literal2.value === "string" && matches2(literal2.value)) {
24977
+ return { ...literal2, value: [seq.schema, newName].map(quoteIdent).join(".") };
24978
+ }
24979
+ return literal2;
24980
+ };
24981
+ if (node.type === "func" && Array.isArray(node.name) && ["nextval", "currval", "setval"].includes(String(node.name.at(-1))) && Array.isArray(updated.args))
24982
+ updated.args[0] = rewriteLiteral(updated.args[0]);
24983
+ 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")
24984
+ updated.expr = rewriteLiteral(updated.expr);
24985
+ return updated;
24986
+ };
24987
+ for (const schema of state.schemas.values()) {
24988
+ for (const table of [...schema.tables.values()]) {
24989
+ const writable = state.ensureWritableTable(table);
24990
+ for (const column of writable.columns) {
24991
+ if (column.defaultExpr) column.defaultExpr = rewrite(column.defaultExpr);
24992
+ if (column.identity?.sequence === `${seq.schema}.${seq.name}`)
24993
+ column.identity = { ...column.identity, sequence: `${seq.schema}.${newName}` };
24994
+ }
24995
+ }
24996
+ }
24997
+ }
24840
24998
  function executeAlterSequence(env, stmt) {
24841
24999
  const state = env.ctx.state;
24842
- const seq = state.findSequence(stmt.name);
24843
- if (!seq) {
25000
+ const foundSequence = state.findSequence(stmt.name);
25001
+ if (!foundSequence) {
24844
25002
  if (stmt.ifExists) return commandResult("ALTER SEQUENCE", 0);
24845
25003
  throw pgError("undefined_table", `relation "${stmt.name.join(".")}" does not exist`, "42P01");
24846
25004
  }
25005
+ const seq = state.ensureWritableSequence(foundSequence);
25006
+ if (stmt.renameTo) {
25007
+ const schema = state.getSchema(seq.schema);
25008
+ if (schema.hasRelation(stmt.renameTo))
25009
+ throw pgError("duplicate_table", `relation "${stmt.renameTo}" already exists`, "42P07");
25010
+ renameSequenceReferences(env, seq, stmt.renameTo);
25011
+ schema.sequences.delete(seq.name);
25012
+ seq.name = stmt.renameTo;
25013
+ schema.sequences.set(seq.name, seq);
25014
+ return commandResult("ALTER SEQUENCE", 0);
25015
+ }
24847
25016
  const o = stmt.options;
24848
25017
  if (o.logged !== void 0) {
24849
25018
  setSequenceLogged(state, seq, o.logged);
@@ -24901,7 +25070,7 @@ function buildColumn(env, schema, tableName2, def, out, taken) {
24901
25070
  col.defaultExpr = {
24902
25071
  type: "func",
24903
25072
  name: ["nextval"],
24904
- args: [{ type: "string_lit", value: `${schema.name}.${seqName}` }]
25073
+ args: [{ type: "string_lit", value: [schema.name, seqName].map(quoteIdent).join(".") }]
24905
25074
  };
24906
25075
  }
24907
25076
  for (const c of def.constraints) {
@@ -25154,7 +25323,11 @@ function executeCreateTableAs(env, stmt) {
25154
25323
  const table = new TableData(schema.name, name, columns, state.nextOid(), stmt.temp);
25155
25324
  table.unlogged = stmt.unlogged === true;
25156
25325
  if (stmt.withData) {
25157
- for (const row of rel3.rows) table.mutableRows().push(row.slice());
25326
+ for (const row of rel3.rows) {
25327
+ const stored = row.slice();
25328
+ table.rowXmins.set(stored, env.ctx.rowVersionXid());
25329
+ table.mutableRows().push(stored);
25330
+ }
25158
25331
  }
25159
25332
  schema.tables.set(name, table);
25160
25333
  const count = stmt.withData ? table.rowCount() : 0;
@@ -25423,6 +25596,12 @@ function executeCreateFunction(env, stmt) {
25423
25596
  language: lang,
25424
25597
  body,
25425
25598
  rawBody: stmt.body,
25599
+ settings: Object.fromEntries(
25600
+ Object.entries(stmt.settings ?? {}).map(([key, value]) => [
25601
+ key,
25602
+ value === "__from_current__" ? state.getSetting(key) ?? "" : value
25603
+ ])
25604
+ ),
25426
25605
  strict: stmt.strict,
25427
25606
  oid: state.nextOid()
25428
25607
  };
@@ -25607,6 +25786,7 @@ function executeAlterTable(env, stmt) {
25607
25786
  }
25608
25787
  const next = row.slice();
25609
25788
  next[idx] = nv;
25789
+ table.rowXmins.set(next, table.rowXmins.get(rows[i]) ?? 2);
25610
25790
  rows[i] = next;
25611
25791
  }
25612
25792
  col.type = resolved.column;
@@ -25708,6 +25888,11 @@ function executeAlterTable(env, stmt) {
25708
25888
  );
25709
25889
  }
25710
25890
  table.columns[idx].name = action.to;
25891
+ for (const seq of [...schema.sequences.values()]) {
25892
+ if (seq.ownedBy?.table === table.name && seq.ownedBy.column === action.from) {
25893
+ state.ensureWritableSequence(seq).ownedBy = { table: table.name, column: action.to };
25894
+ }
25895
+ }
25711
25896
  for (const con of table.constraints) {
25712
25897
  if (con.kind === "primary_key" || con.kind === "unique" || con.kind === "foreign_key") {
25713
25898
  con.columns = con.columns.map((c) => c === action.from ? action.to : c);
@@ -25744,6 +25929,11 @@ function executeAlterTable(env, stmt) {
25744
25929
  throw pgError("duplicate_table", `relation "${action.to}" already exists`, "42P07");
25745
25930
  }
25746
25931
  const oldName = table.name;
25932
+ for (const seq of [...schema.sequences.values()]) {
25933
+ if (seq.ownedBy?.table === oldName) {
25934
+ state.ensureWritableSequence(seq).ownedBy = { ...seq.ownedBy, table: action.to };
25935
+ }
25936
+ }
25747
25937
  schema.tables.delete(table.name);
25748
25938
  table.name = action.to;
25749
25939
  schema.tables.set(action.to, table);
@@ -27617,6 +27807,7 @@ function encodeDatabaseState(state, runtime) {
27617
27807
  writeBjv(
27618
27808
  w,
27619
27809
  {
27810
+ xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
27620
27811
  name: table.name,
27621
27812
  schema: table.schema,
27622
27813
  columns: table.columns,
@@ -27714,8 +27905,14 @@ function decodeInner(snapshot, prng, clock) {
27714
27905
  table.constraints = meta.constraints;
27715
27906
  table.triggers = meta.triggers;
27716
27907
  table.unlogged = meta.unlogged === true;
27908
+ table.slabXmins = meta.xmins ?? null;
27909
+ state.xidCounter = Math.max(
27910
+ state.xidCounter,
27911
+ (meta.xmins ?? []).reduce((max, xid) => Math.max(max, xid + 1), 3)
27912
+ );
27717
27913
  if (meta.stats) state.tableStats.set(table.oid, meta.stats);
27718
27914
  const rowCount = readVarintU32(r);
27915
+ if (meta.xmins && meta.xmins.length !== rowCount) throw snapshotError();
27719
27916
  const slabColumns = [];
27720
27917
  for (let c = 0; c < meta.columns.length; c++)
27721
27918
  slabColumns.push(readPackedColumn(r, rowCount, intern, meta.columns[c].type.id));
@@ -28159,6 +28356,8 @@ function validateTableMetaBjv(value) {
28159
28356
  if (!isRecord(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
28160
28357
  if (!Array.isArray(value.columns)) throw snapshotError();
28161
28358
  for (const col of value.columns) validateColumnMeta(col);
28359
+ if (value.xmins !== void 0 && (!Array.isArray(value.xmins) || value.xmins.some((xid) => !Number.isInteger(xid) || xid < 2 || xid > 4294967295)))
28360
+ throw snapshotError();
28162
28361
  }
28163
28362
  function validateViewMetaBjv(value) {
28164
28363
  if (!isRecord(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
@@ -28252,6 +28451,7 @@ function forceSchemaIntern(pool, state, schemas) {
28252
28451
  pool.forceId(table.name);
28253
28452
  pool.forceId(table.schema);
28254
28453
  forceBjvStrings(pool, {
28454
+ xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
28255
28455
  name: table.name,
28256
28456
  schema: table.schema,
28257
28457
  columns: table.columns,
@@ -29882,7 +30082,7 @@ var Connection = class {
29882
30082
  if (stmt?.type !== "transaction") throw pgError2("syntax", "invalid transaction command", "42601");
29883
30083
  switch (stmt.action) {
29884
30084
  case "begin":
29885
- this.transaction ??= { statements: [], savepoints: [] };
30085
+ this.transaction ??= { statements: [], savepoints: [], xid: this.database.state.allocateXid() };
29886
30086
  return command("BEGIN");
29887
30087
  case "commit": {
29888
30088
  const transaction = this.transaction;
@@ -29891,6 +30091,7 @@ var Connection = class {
29891
30091
  this.inSession(
29892
30092
  this.database,
29893
30093
  () => this.database.transaction(() => {
30094
+ this.database.state.transactionXid = transaction.xid;
29894
30095
  for (const logged of transaction.statements) this.replay(this.database, logged);
29895
30096
  })
29896
30097
  );
@@ -29941,6 +30142,7 @@ var Connection = class {
29941
30142
  workspace.state.settings = new Map(this.settings);
29942
30143
  workspace.state.settingDefaults = this.settingDefaults;
29943
30144
  workspace.transactions.begin();
30145
+ workspace.state.transactionXid = this.transaction?.xid ?? null;
29944
30146
  for (const logged of this.transaction?.statements ?? []) {
29945
30147
  this.replay(workspace, logged);
29946
30148
  }