@crvouga/mockingbird-service-postgres 3.5.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/dist/server.js CHANGED
@@ -257,6 +257,13 @@ function isPostgresError(err) {
257
257
  return typeof sqlState === "string" && /^[0-9A-Z]{5}$/.test(sqlState);
258
258
  }
259
259
 
260
+ // src/storage/guc.ts
261
+ function validateStorageSetting(name, value) {
262
+ if (name === "default_table_access_method" && value !== "heap" || name === "default_tablespace" && value !== "" && value !== "pg_default") {
263
+ throw pgError("invalid_parameter_value", `invalid value for parameter "${name}": "${value}"`, "22023");
264
+ }
265
+ }
266
+
260
267
  // src/runtime/prng.ts
261
268
  var Prng = class _Prng {
262
269
  state;
@@ -2796,6 +2803,12 @@ var invalidName = () => {
2796
2803
  throw pgError("syntax", "invalid name syntax", "42602");
2797
2804
  };
2798
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) {
2799
2812
  if (text === "-") return { oid: 0 };
2800
2813
  if (/^\d+$/.test(text)) return { oid: parseOidText(text) };
2801
2814
  const names = [];
@@ -2831,8 +2844,8 @@ function parseNamespaceInput(text) {
2831
2844
  skipSpace();
2832
2845
  if (at === text.length) invalidName();
2833
2846
  }
2834
- if (names.length !== 1) invalidName();
2835
- return { name: names[0] };
2847
+ if (names.length === 0 || names.length > 3) invalidName();
2848
+ return { parts: names };
2836
2849
  }
2837
2850
  function namespaceText(oid, name) {
2838
2851
  if (oid === 0) return "-";
@@ -2905,6 +2918,7 @@ var TYPE_ALIASES = {
2905
2918
  regtype: "regtype",
2906
2919
  regproc: "regproc",
2907
2920
  regnamespace: "regnamespace",
2921
+ xid: "xid",
2908
2922
  oid: "oid",
2909
2923
  void: "void",
2910
2924
  record: "record",
@@ -2981,6 +2995,7 @@ var TYPE_OIDS = {
2981
2995
  regproc: 24,
2982
2996
  text: 25,
2983
2997
  oid: 26,
2998
+ xid: 28,
2984
2999
  json: 114,
2985
3000
  float4: 700,
2986
3001
  float8: 701,
@@ -3300,6 +3315,7 @@ function recordText(rec, ctx) {
3300
3315
  return `(${parts.join(",")})`;
3301
3316
  }
3302
3317
  function datumText(t, v, ctx) {
3318
+ if (t === "regclass") return v === 0 ? "-" : ctx.relationName?.(v) ?? String(v);
3303
3319
  if (t === "regnamespace") return namespaceText(v, ctx.namespaceName?.(v));
3304
3320
  if (v === null) throw pgError("internal", "datumText called with null");
3305
3321
  if (isArrayType(t)) return arrayText(v, ctx);
@@ -3310,6 +3326,7 @@ function datumText(t, v, ctx) {
3310
3326
  case "int2":
3311
3327
  case "int4":
3312
3328
  case "oid":
3329
+ case "xid":
3313
3330
  return String(v);
3314
3331
  case "int8":
3315
3332
  return String(v);
@@ -3374,6 +3391,12 @@ function datumText(t, v, ctx) {
3374
3391
  }
3375
3392
  var UTC_INPUT = { zoneOffsetForNaive: () => 0 };
3376
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
+ }
3377
3400
  if (t === "regnamespace") {
3378
3401
  const parsed = parseNamespaceInput(text);
3379
3402
  if ("oid" in parsed) return parsed.oid;
@@ -3395,6 +3418,7 @@ function datumFromText(t, text, ctx) {
3395
3418
  case "int8":
3396
3419
  return parseIntegerText(text, t);
3397
3420
  case "oid":
3421
+ case "xid":
3398
3422
  return parseOidText(text);
3399
3423
  case "float4":
3400
3424
  return Math.fround(parseFloatText(text, "float4"));
@@ -3551,6 +3575,8 @@ var TableData = class _TableData {
3551
3575
  schema;
3552
3576
  columns;
3553
3577
  rows;
3578
+ rowXmins = /* @__PURE__ */ new WeakMap();
3579
+ slabXmins = null;
3554
3580
  /** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
3555
3581
  slab = null;
3556
3582
  constraints;
@@ -3593,6 +3619,11 @@ var TableData = class _TableData {
3593
3619
  materializeSlab() {
3594
3620
  if (!this.slab) return;
3595
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;
3596
3627
  this.slab = null;
3597
3628
  this.indexStores = null;
3598
3629
  }
@@ -3626,6 +3657,10 @@ var TableData = class _TableData {
3626
3657
  } else {
3627
3658
  t.rows = this.rows.map((r) => r.slice());
3628
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
+ });
3629
3664
  t.unlogged = this.unlogged;
3630
3665
  t.constraints = this.constraints.map((c) => ({ ...c }));
3631
3666
  t.triggers = this.triggers.map((tr) => ({ ...tr }));
@@ -3711,7 +3746,18 @@ var DatabaseState = class _DatabaseState {
3711
3746
  clock;
3712
3747
  changes = 0;
3713
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
+ }
3714
3757
  inTransaction = false;
3758
+ /** Transaction-only events: included in rollback clones, never in exported snapshots. */
3759
+ pendingTriggers = [];
3760
+ constraintModes = /* @__PURE__ */ new Map();
3715
3761
  /** most recent sequence touched by nextval/setval, for lastval() */
3716
3762
  lastSequence = null;
3717
3763
  /** Session currval per sequence; absent entry means currval is undefined. */
@@ -3754,6 +3800,8 @@ var DatabaseState = class _DatabaseState {
3754
3800
  this.settings.set("row_security", "on");
3755
3801
  this.settings.set("array_nulls", "on");
3756
3802
  this.settings.set("backslash_quote", "safe_encoding");
3803
+ this.settings.set("default_tablespace", "");
3804
+ this.settings.set("default_table_access_method", "heap");
3757
3805
  }
3758
3806
  nextOid() {
3759
3807
  return this.oidCounter++;
@@ -3913,10 +3961,14 @@ var DatabaseState = class _DatabaseState {
3913
3961
  s.prepared = new Map(this.prepared);
3914
3962
  s.changes = this.changes;
3915
3963
  s.inTransaction = this.inTransaction;
3964
+ s.pendingTriggers = this.pendingTriggers.slice();
3965
+ s.constraintModes = new Map(this.constraintModes);
3916
3966
  s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
3917
3967
  s.sequenceCurrval = new Map(this.sequenceCurrval);
3918
3968
  s.tableStats = new Map(this.tableStats);
3919
3969
  s.oidCounter = this.oidCounter;
3970
+ s.xidCounter = this.xidCounter;
3971
+ s.transactionXid = this.transactionXid;
3920
3972
  for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
3921
3973
  return s;
3922
3974
  }
@@ -3930,10 +3982,14 @@ var DatabaseState = class _DatabaseState {
3930
3982
  s.prepared = new Map(this.prepared);
3931
3983
  s.changes = this.changes;
3932
3984
  s.inTransaction = this.inTransaction;
3985
+ s.pendingTriggers = this.pendingTriggers.slice();
3986
+ s.constraintModes = new Map(this.constraintModes);
3933
3987
  s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
3934
3988
  s.sequenceCurrval = new Map(this.sequenceCurrval);
3935
3989
  s.tableStats = new Map(this.tableStats);
3936
3990
  s.oidCounter = this.oidCounter;
3991
+ s.xidCounter = this.xidCounter;
3992
+ s.transactionXid = this.transactionXid;
3937
3993
  for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
3938
3994
  return s;
3939
3995
  }
@@ -4002,11 +4058,15 @@ var DatabaseState = class _DatabaseState {
4002
4058
  this.settings = other.settings;
4003
4059
  this.localSettings = other.localSettings;
4004
4060
  this.prepared = other.prepared;
4061
+ this.pendingTriggers = other.pendingTriggers.slice();
4062
+ this.constraintModes = new Map(other.constraintModes);
4005
4063
  this.changes = other.changes;
4006
4064
  this.lastSequence = other.lastSequence;
4007
4065
  this.sequenceCurrval = other.sequenceCurrval;
4008
4066
  this.tableStats = other.tableStats;
4009
4067
  this.oidCounter = other.oidCounter;
4068
+ this.xidCounter = Math.max(this.xidCounter, other.xidCounter);
4069
+ this.transactionXid = other.transactionXid;
4010
4070
  }
4011
4071
  /** @internal Snapshot codec access to the oid allocator. */
4012
4072
  snapshotOidCounter() {
@@ -4018,91 +4078,215 @@ var DatabaseState = class _DatabaseState {
4018
4078
  }
4019
4079
  };
4020
4080
 
4021
- // src/transactions/manager.ts
4022
- var TransactionManager = class {
4023
- constructor(state) {
4024
- this.state = state;
4081
+ // src/types/timezone.ts
4082
+ var intlCache = /* @__PURE__ */ new Map();
4083
+ function intlFor(zone) {
4084
+ const cached = intlCache.get(zone);
4085
+ if (cached) return cached;
4086
+ try {
4087
+ const fmt = new Intl.DateTimeFormat("en-US", {
4088
+ timeZone: zone,
4089
+ timeZoneName: "longOffset",
4090
+ year: "numeric"
4091
+ });
4092
+ intlCache.set(zone, fmt);
4093
+ return fmt;
4094
+ } catch {
4095
+ return null;
4096
+ }
4097
+ }
4098
+ function parseFixedOffset(zone) {
4099
+ const m = /^([+-]?)(\d{1,2})(?::(\d{2}))?(?::(\d{2}))?$/.exec(zone.trim());
4100
+ if (!m) return null;
4101
+ const sign = m[1] === "-" ? -1 : 1;
4102
+ return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60 + Number(m[4] ?? 0));
4103
+ }
4104
+ function parsePosixOffset(zone) {
4105
+ const m = /^(?:utc|gmt)([+-])(\d{1,2})(?::(\d{2}))?$/i.exec(zone.trim());
4106
+ if (!m) return null;
4107
+ const sign = m[1] === "-" ? 1 : -1;
4108
+ return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60);
4109
+ }
4110
+ function pgMicrosToUnixMs(utcMicros) {
4111
+ return Number((utcMicros - UNIX_EPOCH_MICROS_FROM_PG) / 1000n);
4112
+ }
4113
+ function zoneOffsetAtUtc(zone, utcMicros) {
4114
+ const z = zone.trim();
4115
+ const lower = z.toLowerCase();
4116
+ if (lower === "utc" || lower === "gmt" || lower === "z" || lower === "zulu" || lower === "universal") return 0;
4117
+ const posix = parsePosixOffset(z);
4118
+ if (posix !== null) return posix;
4119
+ const fixed = parseFixedOffset(z);
4120
+ if (fixed !== null) return fixed;
4121
+ const fmt = intlFor(z);
4122
+ if (fmt) {
4123
+ const ms = clampDateMs(pgMicrosToUnixMs(utcMicros));
4124
+ const parts = fmt.formatToParts(new Date(ms));
4125
+ const tzName = parts.find((p) => p.type === "timeZoneName")?.value ?? "GMT";
4126
+ const m = /GMT([+-])(\d{2}):(\d{2})(?::(\d{2}))?/.exec(tzName);
4127
+ if (!m) return 0;
4128
+ const sign = m[1] === "-" ? -1 : 1;
4129
+ return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60 + Number(m[4] ?? 0));
4025
4130
  }
4131
+ throw pgError("invalid_parameter_value", `time zone "${zone}" not recognized`);
4132
+ }
4133
+ function clampDateMs(ms) {
4134
+ const MAX = 864e13;
4135
+ return Math.max(-MAX, Math.min(MAX, ms));
4136
+ }
4137
+ function zoneOffsetForNaive(zone, naiveMicros) {
4138
+ const first = zoneOffsetAtUtc(zone, naiveMicros);
4139
+ const second = zoneOffsetAtUtc(zone, naiveMicros - BigInt(first) * 1000000n);
4140
+ return second;
4141
+ }
4142
+ function validateZone(zone) {
4143
+ zoneOffsetAtUtc(zone, 0n);
4144
+ }
4145
+
4146
+ // src/expressions/context.ts
4147
+ var EngineCtx = class {
4026
4148
  state;
4027
- base = null;
4028
- savepoints = [];
4029
- freezeDepth = 0;
4030
- get inTransaction() {
4031
- return this.base !== null;
4149
+ writeXid = null;
4150
+ rowVersionXid() {
4151
+ if (this.state.inTransaction) return this.state.transactionXid ??= this.state.allocateXid();
4152
+ return this.writeXid ??= this.state.allocateXid();
4032
4153
  }
4033
- takeSnapshot() {
4034
- this.state.freezeShared();
4035
- this.freezeDepth++;
4036
- return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
4154
+ /** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
4155
+ txNow;
4156
+ /** statement timestamp */
4157
+ stmtNow;
4158
+ constructor(state, txNow) {
4159
+ this.state = state;
4160
+ const nowMs = state.clock().getTime();
4161
+ const nowMicros = BigInt(Math.round(nowMs)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG;
4162
+ this.txNow = txNow ?? nowMicros;
4163
+ this.stmtNow = nowMicros;
4037
4164
  }
4038
- restore(snap) {
4039
- this.state.restoreFrom(snap.state);
4040
- this.state.prng.setState(snap.prngState);
4165
+ timezone() {
4166
+ return this.state.getSetting("timezone") ?? "UTC";
4041
4167
  }
4042
- thawOnce() {
4043
- if (this.freezeDepth > 0) {
4044
- this.state.thawShared();
4045
- this.freezeDepth--;
4046
- }
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;
4047
4174
  }
4048
- begin() {
4049
- if (this.base !== null) {
4050
- return;
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
+ }
4051
4182
  }
4052
- this.base = this.takeSnapshot();
4053
- this.state.inTransaction = true;
4054
- assert(this.freezeDepth === 1, "BEGIN freeze depth");
4183
+ return null;
4055
4184
  }
4056
- commit() {
4057
- this.base = null;
4058
- this.savepoints = [];
4059
- this.state.inTransaction = false;
4060
- this.state.localSettings.clear();
4061
- while (this.freezeDepth > 0) this.thawOnce();
4185
+ namespaceOid(name) {
4186
+ const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
4187
+ if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
4188
+ return oid;
4062
4189
  }
4063
- rollback() {
4064
- if (this.base !== null) {
4065
- this.restore(this.base);
4190
+ namespaceName(oid) {
4191
+ const builtin = builtinNamespaceName(oid);
4192
+ if (builtin !== void 0) return builtin;
4193
+ for (const schema of this.state.schemas.values()) {
4194
+ if (schema.oid === oid) return schema.name;
4066
4195
  }
4067
- this.base = null;
4068
- this.savepoints = [];
4069
- this.state.inTransaction = false;
4070
- this.state.localSettings.clear();
4071
- while (this.freezeDepth > 0) this.thawOnce();
4196
+ return null;
4072
4197
  }
4073
- savepoint(name) {
4074
- if (this.base === null) {
4075
- throw pgError("transaction_state", "SAVEPOINT can only be used in transaction blocks", "25P01");
4076
- }
4077
- this.savepoints.push({ name, snap: this.takeSnapshot() });
4198
+ zoneOffsetAt(utcMicros) {
4199
+ return zoneOffsetAtUtc(this.timezone(), utcMicros);
4078
4200
  }
4079
- releaseSavepoint(name) {
4080
- const idx = this.findSavepoint(name);
4081
- this.savepoints.splice(idx);
4201
+ zoneOffsetForNaive(naiveMicros) {
4202
+ return zoneOffsetForNaive(this.timezone(), naiveMicros);
4082
4203
  }
4083
- rollbackToSavepoint(name) {
4084
- const idx = this.findSavepoint(name);
4085
- const sp = this.savepoints[idx];
4086
- this.restore(sp.snap);
4087
- this.savepoints.splice(idx + 1);
4204
+ enumLabels(enumType) {
4205
+ if (!isEnumType(enumType)) return null;
4206
+ const e = this.state.findEnumByKey(enumType.slice(5));
4207
+ return e?.labels ?? null;
4088
4208
  }
4089
- findSavepoint(name) {
4090
- if (this.base === null) {
4091
- throw pgError("transaction_state", `SAVEPOINT can only be used in transaction blocks`, "25P01");
4092
- }
4093
- for (let i = this.savepoints.length - 1; i >= 0; i--) {
4094
- if (this.savepoints[i].name === name) return i;
4095
- }
4096
- throw pgError("invalid_savepoint_specification", `savepoint "${name}" does not exist`, "3B001");
4209
+ enumHasLabel(enumType, label) {
4210
+ const labels = this.enumLabels(enumType);
4211
+ return labels === null ? true : labels.includes(label);
4097
4212
  }
4098
- reset() {
4099
- this.base = null;
4100
- this.savepoints = [];
4101
- this.state.inTransaction = false;
4102
- this.freezeDepth = 0;
4213
+ enumOrder(enumType, label) {
4214
+ const labels = this.enumLabels(enumType);
4215
+ if (!labels) return 0;
4216
+ const idx = labels.indexOf(label);
4217
+ return idx === -1 ? labels.length : idx;
4218
+ }
4219
+ requireEnum(enumType) {
4220
+ const labels = this.enumLabels(enumType);
4221
+ if (!labels) throw pgError("undefined_object", `type "${enumType.slice(5)}" does not exist`);
4222
+ return labels;
4103
4223
  }
4104
4224
  };
4105
4225
 
4226
+ // src/api/bind.ts
4227
+ var INT4_MIN2 = -2147483648;
4228
+ var INT4_MAX2 = 2147483647;
4229
+ function bindValueToTyped(value, index) {
4230
+ if (value === null || value === void 0) return tv(UNKNOWN, null);
4231
+ switch (typeof value) {
4232
+ case "boolean":
4233
+ return tv("bool", value);
4234
+ case "number":
4235
+ if (Number.isInteger(value) && value >= INT4_MIN2 && value <= INT4_MAX2) {
4236
+ return tv("int4", value);
4237
+ }
4238
+ if (Number.isInteger(value) && Number.isSafeInteger(value)) {
4239
+ return tv("int8", BigInt(value));
4240
+ }
4241
+ return tv("float8", value);
4242
+ case "bigint":
4243
+ if (value < -9223372036854775808n || value > 9223372036854775807n) {
4244
+ throw pgError("numeric_value_out_of_range", `bigint parameter $${index + 1} out of int8 range`, "22003");
4245
+ }
4246
+ return tv("int8", value);
4247
+ case "string":
4248
+ return tv(UNKNOWN, value);
4249
+ case "object": {
4250
+ if (value instanceof Uint8Array) return tv("bytea", value);
4251
+ if (value instanceof Date) {
4252
+ const ms = value.getTime();
4253
+ if (Number.isNaN(ms)) {
4254
+ throw pgError("invalid_datetime", `invalid Date parameter $${index + 1}`, "22008");
4255
+ }
4256
+ return tv("timestamptz", BigInt(Math.round(ms)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG);
4257
+ }
4258
+ break;
4259
+ }
4260
+ default:
4261
+ break;
4262
+ }
4263
+ throw pgError("misuse", `unsupported parameter type for $${index + 1}: ${typeof value}`, "XX000");
4264
+ }
4265
+ function datumToJs(t, v, ctx, int8 = "bigint") {
4266
+ if (v === null) return null;
4267
+ switch (t) {
4268
+ case "bool":
4269
+ return v;
4270
+ case "int2":
4271
+ case "int4":
4272
+ case "oid":
4273
+ return typeof v === "bigint" ? Number(v) : v;
4274
+ case "int8": {
4275
+ const n = typeof v === "bigint" ? v : BigInt(v);
4276
+ if (int8 === "string") return n.toString();
4277
+ if (int8 === "number") return Number(n);
4278
+ return n;
4279
+ }
4280
+ case "float4":
4281
+ case "float8":
4282
+ return v;
4283
+ case "bytea":
4284
+ return v;
4285
+ default:
4286
+ return datumText(t === UNKNOWN ? "text" : t, v, ctx);
4287
+ }
4288
+ }
4289
+
4106
4290
  // src/types/cast.ts
4107
4291
  var UTC_CAST_ENV = {
4108
4292
  zoneOffsetAt: () => 0,
@@ -4298,7 +4482,7 @@ function castTo(env, value, target, opts = {}) {
4298
4482
  return tv(target, makeArray(toElem, items, arr.dims.slice(), arr.lbs.slice()));
4299
4483
  }
4300
4484
  if (from === "oid" && target === "regnamespace") return tv(target, v);
4301
- if (from === "regnamespace" && (target === "oid" || target === "int4" || target === "int8")) {
4485
+ if ((from === "regnamespace" || from === "regclass") && (target === "oid" || target === "int4" || target === "int8")) {
4302
4486
  return tv(target, target === "int8" ? BigInt(v) : v);
4303
4487
  }
4304
4488
  if ((from === "int4" || from === "int8" || from === "int2") && (target === "oid" || target === "regnamespace")) {
@@ -4579,259 +4763,6 @@ function unifyTypes(a, b) {
4579
4763
  return null;
4580
4764
  }
4581
4765
 
4582
- // src/types/resolve.ts
4583
- var SERIALS = {
4584
- smallserial: "int2",
4585
- serial2: "int2",
4586
- serial: "int4",
4587
- serial4: "int4",
4588
- bigserial: "int8",
4589
- serial8: "int8"
4590
- };
4591
- function modOf(t, mods) {
4592
- if (mods.length === 0) return null;
4593
- if (t === "numeric") return { a: mods[0], b: mods[1] ?? 0 };
4594
- return { a: mods[0] };
4595
- }
4596
- function resolveTypeName(state, tn) {
4597
- const joined = tn.parts.join(".");
4598
- const bare = tn.parts.length === 1 ? tn.parts[0] : tn.parts.length === 2 && tn.parts[0] === "pg_catalog" ? tn.parts[1] : null;
4599
- if (bare !== null) {
4600
- const serial = SERIALS[bare];
4601
- if (serial !== void 0 && tn.arrayDims === 0) {
4602
- return { column: { id: serial, mod: null }, domain: null, serial };
4603
- }
4604
- const builtin = normalizeTypeName(bare);
4605
- if (builtin !== null) {
4606
- const id = tn.arrayDims > 0 ? arrayTypeOf(builtin) : builtin;
4607
- return { column: { id, mod: modOf(builtin, tn.mods) }, domain: null, serial: null };
4608
- }
4609
- }
4610
- const enumData = state.findEnum(tn.parts);
4611
- if (enumData) {
4612
- const elem = `enum:${enumData.schema}.${enumData.name}`;
4613
- const id = tn.arrayDims > 0 ? arrayTypeOf(elem) : elem;
4614
- return { column: { id, mod: null }, domain: null, serial: null };
4615
- }
4616
- const domainData = state.findDomain(tn.parts);
4617
- if (domainData) {
4618
- if (tn.arrayDims > 0) {
4619
- const id = arrayTypeOf(domainData.baseType.id);
4620
- return { column: { id, mod: domainData.baseType.mod }, domain: null, serial: null };
4621
- }
4622
- return {
4623
- column: domainData.baseType,
4624
- domain: `${domainData.schema}.${domainData.name}`,
4625
- serial: null
4626
- };
4627
- }
4628
- throw pgError("undefined_object", `type "${joined}" does not exist`);
4629
- }
4630
-
4631
- // src/executor/relation.ts
4632
- var RowScope = class {
4633
- constructor(columns, row, parent = null, rangeVars = /* @__PURE__ */ new Set()) {
4634
- this.columns = columns;
4635
- this.row = row;
4636
- this.parent = parent;
4637
- this.rangeVars = rangeVars;
4638
- }
4639
- columns;
4640
- row;
4641
- parent;
4642
- rangeVars;
4643
- /** Resolve a (possibly qualified) column reference. undefined = not found. */
4644
- lookup(parts) {
4645
- if (parts.length === 1) {
4646
- const name2 = parts[0];
4647
- let found2;
4648
- let count2 = 0;
4649
- for (let i = 0; i < this.columns.length; i++) {
4650
- const c = this.columns[i];
4651
- if (c.name === name2 && !c.hidden) {
4652
- count2++;
4653
- if (count2 > 1) {
4654
- throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
4655
- }
4656
- found2 = tv(c.type, this.row[i] ?? null);
4657
- }
4658
- }
4659
- if (found2 !== void 0) return found2;
4660
- if (this.rangeVars.has(name2)) {
4661
- return this.wholeRow(name2);
4662
- }
4663
- return this.parent?.lookup(parts);
4664
- }
4665
- const table = parts[parts.length - 2];
4666
- const name = parts[parts.length - 1];
4667
- let found;
4668
- let count = 0;
4669
- for (let i = 0; i < this.columns.length; i++) {
4670
- const c = this.columns[i];
4671
- if (c.table === table && c.name === name) {
4672
- count++;
4673
- if (count > 1) {
4674
- throw pgError("ambiguous_column", `column reference "${name}" is ambiguous`);
4675
- }
4676
- found = tv(c.type, this.row[i] ?? null);
4677
- }
4678
- }
4679
- if (found !== void 0) return found;
4680
- return this.parent?.lookup(parts);
4681
- }
4682
- /** Build a record value from all columns belonging to a range variable. */
4683
- wholeRow(rangeVar) {
4684
- const types = [];
4685
- const values = [];
4686
- const names = [];
4687
- for (let i = 0; i < this.columns.length; i++) {
4688
- const c = this.columns[i];
4689
- if (c.table === rangeVar) {
4690
- types.push(c.type);
4691
- values.push(this.row[i] ?? null);
4692
- names.push(c.name);
4693
- }
4694
- }
4695
- if (types.length === 0) return void 0;
4696
- return tv("record", { kind: "pgrecord", types, values, names });
4697
- }
4698
- hasRangeVar(name) {
4699
- if (this.rangeVars.has(name)) return true;
4700
- return this.parent?.hasRangeVar(name) ?? false;
4701
- }
4702
- };
4703
- function childEnv(env, outer) {
4704
- return {
4705
- ctx: env.ctx,
4706
- params: env.params,
4707
- ctes: env.ctes,
4708
- outer,
4709
- allowUnpopulatedMatviews: env.allowUnpopulatedMatviews
4710
- };
4711
- }
4712
- function relationResult(rel3, command2) {
4713
- const visible = rel3.columns.map((c, i) => ({ i, c })).filter(({ c }) => !c.hidden);
4714
- return {
4715
- columns: visible.map(({ c }) => ({ name: c.name, type: c.type })),
4716
- rows: rel3.rows.map((r) => visible.map(({ i }) => r[i] ?? null)),
4717
- command: command2,
4718
- rowCount: rel3.rows.length
4719
- };
4720
- }
4721
- function commandResult(command2, rowCount) {
4722
- return { columns: [], rows: [], command: command2, rowCount };
4723
- }
4724
- function inferColumnName(e) {
4725
- switch (e.type) {
4726
- case "colref":
4727
- return e.parts[e.parts.length - 1];
4728
- case "func":
4729
- return e.name[e.name.length - 1];
4730
- case "cast": {
4731
- const inner = inferColumnName(e.expr);
4732
- if (inner !== "?column?") return inner;
4733
- return e.target.parts[e.target.parts.length - 1];
4734
- }
4735
- case "collate":
4736
- return inferColumnName(e.expr);
4737
- case "case":
4738
- return "case";
4739
- case "array_ctor":
4740
- case "array_query":
4741
- return "array";
4742
- case "row":
4743
- return "row";
4744
- case "subquery_expr":
4745
- return e.kind === "exists" ? "exists" : "?column?";
4746
- case "bool_lit":
4747
- return "bool";
4748
- case "extract":
4749
- return "extract";
4750
- case "position":
4751
- return "position";
4752
- case "substring_sql":
4753
- return "substring";
4754
- case "overlay":
4755
- return "overlay";
4756
- case "trim":
4757
- return e.side === "leading" ? "ltrim" : e.side === "trailing" ? "rtrim" : "btrim";
4758
- case "field_select":
4759
- return e.field === "*" ? "?column?" : e.field;
4760
- case "at_time_zone":
4761
- return "timezone";
4762
- case "grouping_func":
4763
- return "grouping";
4764
- case "subscript":
4765
- return inferColumnName(e.base);
4766
- default:
4767
- return "?column?";
4768
- }
4769
- }
4770
-
4771
- // src/api/bind.ts
4772
- var INT4_MIN2 = -2147483648;
4773
- var INT4_MAX2 = 2147483647;
4774
- function bindValueToTyped(value, index) {
4775
- if (value === null || value === void 0) return tv(UNKNOWN, null);
4776
- switch (typeof value) {
4777
- case "boolean":
4778
- return tv("bool", value);
4779
- case "number":
4780
- if (Number.isInteger(value) && value >= INT4_MIN2 && value <= INT4_MAX2) {
4781
- return tv("int4", value);
4782
- }
4783
- if (Number.isInteger(value) && Number.isSafeInteger(value)) {
4784
- return tv("int8", BigInt(value));
4785
- }
4786
- return tv("float8", value);
4787
- case "bigint":
4788
- if (value < -9223372036854775808n || value > 9223372036854775807n) {
4789
- throw pgError("numeric_value_out_of_range", `bigint parameter $${index + 1} out of int8 range`, "22003");
4790
- }
4791
- return tv("int8", value);
4792
- case "string":
4793
- return tv(UNKNOWN, value);
4794
- case "object": {
4795
- if (value instanceof Uint8Array) return tv("bytea", value);
4796
- if (value instanceof Date) {
4797
- const ms = value.getTime();
4798
- if (Number.isNaN(ms)) {
4799
- throw pgError("invalid_datetime", `invalid Date parameter $${index + 1}`, "22008");
4800
- }
4801
- return tv("timestamptz", BigInt(Math.round(ms)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG);
4802
- }
4803
- break;
4804
- }
4805
- default:
4806
- break;
4807
- }
4808
- throw pgError("misuse", `unsupported parameter type for $${index + 1}: ${typeof value}`, "XX000");
4809
- }
4810
- function datumToJs(t, v, ctx, int8 = "bigint") {
4811
- if (v === null) return null;
4812
- switch (t) {
4813
- case "bool":
4814
- return v;
4815
- case "int2":
4816
- case "int4":
4817
- case "oid":
4818
- return typeof v === "bigint" ? Number(v) : v;
4819
- case "int8": {
4820
- const n = typeof v === "bigint" ? v : BigInt(v);
4821
- if (int8 === "string") return n.toString();
4822
- if (int8 === "number") return Number(n);
4823
- return n;
4824
- }
4825
- case "float4":
4826
- case "float8":
4827
- return v;
4828
- case "bytea":
4829
- return v;
4830
- default:
4831
- return datumText(t === UNKNOWN ? "text" : t, v, ctx);
4832
- }
4833
- }
4834
-
4835
4766
  // src/functions/datetime-fns.ts
4836
4767
  function extractDatePart(ctx, field0, src0, asNumeric) {
4837
4768
  const field = field0.toLowerCase();
@@ -5252,6 +5183,8 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
5252
5183
  case "int2":
5253
5184
  case "int4":
5254
5185
  case "oid":
5186
+ case "regclass":
5187
+ case "xid":
5255
5188
  case "regnamespace":
5256
5189
  case "date":
5257
5190
  return expectNumber(a, t) - expectNumber(b, t);
@@ -5371,6 +5304,8 @@ function datumKey(t, v) {
5371
5304
  case "int2":
5372
5305
  case "int4":
5373
5306
  case "oid":
5307
+ case "regclass":
5308
+ case "xid":
5374
5309
  case "date":
5375
5310
  return `i${v}`;
5376
5311
  case "float4":
@@ -5746,71 +5681,6 @@ function getArrayFunctions() {
5746
5681
  return m;
5747
5682
  }
5748
5683
 
5749
- // src/types/timezone.ts
5750
- var intlCache = /* @__PURE__ */ new Map();
5751
- function intlFor(zone) {
5752
- const cached = intlCache.get(zone);
5753
- if (cached) return cached;
5754
- try {
5755
- const fmt = new Intl.DateTimeFormat("en-US", {
5756
- timeZone: zone,
5757
- timeZoneName: "longOffset",
5758
- year: "numeric"
5759
- });
5760
- intlCache.set(zone, fmt);
5761
- return fmt;
5762
- } catch {
5763
- return null;
5764
- }
5765
- }
5766
- function parseFixedOffset(zone) {
5767
- const m = /^([+-]?)(\d{1,2})(?::(\d{2}))?(?::(\d{2}))?$/.exec(zone.trim());
5768
- if (!m) return null;
5769
- const sign = m[1] === "-" ? -1 : 1;
5770
- return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60 + Number(m[4] ?? 0));
5771
- }
5772
- function parsePosixOffset(zone) {
5773
- const m = /^(?:utc|gmt)([+-])(\d{1,2})(?::(\d{2}))?$/i.exec(zone.trim());
5774
- if (!m) return null;
5775
- const sign = m[1] === "-" ? 1 : -1;
5776
- return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60);
5777
- }
5778
- function pgMicrosToUnixMs(utcMicros) {
5779
- return Number((utcMicros - UNIX_EPOCH_MICROS_FROM_PG) / 1000n);
5780
- }
5781
- function zoneOffsetAtUtc(zone, utcMicros) {
5782
- const z = zone.trim();
5783
- const lower = z.toLowerCase();
5784
- if (lower === "utc" || lower === "gmt" || lower === "z" || lower === "zulu" || lower === "universal") return 0;
5785
- const posix = parsePosixOffset(z);
5786
- if (posix !== null) return posix;
5787
- const fixed = parseFixedOffset(z);
5788
- if (fixed !== null) return fixed;
5789
- const fmt = intlFor(z);
5790
- if (fmt) {
5791
- const ms = clampDateMs(pgMicrosToUnixMs(utcMicros));
5792
- const parts = fmt.formatToParts(new Date(ms));
5793
- const tzName = parts.find((p) => p.type === "timeZoneName")?.value ?? "GMT";
5794
- const m = /GMT([+-])(\d{2}):(\d{2})(?::(\d{2}))?/.exec(tzName);
5795
- if (!m) return 0;
5796
- const sign = m[1] === "-" ? -1 : 1;
5797
- return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60 + Number(m[4] ?? 0));
5798
- }
5799
- throw pgError("invalid_parameter_value", `time zone "${zone}" not recognized`);
5800
- }
5801
- function clampDateMs(ms) {
5802
- const MAX = 864e13;
5803
- return Math.max(-MAX, Math.min(MAX, ms));
5804
- }
5805
- function zoneOffsetForNaive(zone, naiveMicros) {
5806
- const first = zoneOffsetAtUtc(zone, naiveMicros);
5807
- const second = zoneOffsetAtUtc(zone, naiveMicros - BigInt(first) * 1000000n);
5808
- return second;
5809
- }
5810
- function validateZone(zone) {
5811
- zoneOffsetAtUtc(zone, 0n);
5812
- }
5813
-
5814
5684
  // src/functions/datetime-registry.ts
5815
5685
  function getDatetimeFunctions() {
5816
5686
  const m = /* @__PURE__ */ new Map();
@@ -7410,6 +7280,28 @@ function exactDegTan(x) {
7410
7280
  return Math.tan(x * Math.PI / 180);
7411
7281
  }
7412
7282
 
7283
+ // src/storage/indexable-relation.ts
7284
+ function materializedTable(view) {
7285
+ const table = new TableData(
7286
+ view.schema,
7287
+ view.name,
7288
+ (view.matColumns ?? []).map((c) => ({
7289
+ name: c.name,
7290
+ type: { id: c.type, mod: null },
7291
+ notNull: false,
7292
+ defaultExpr: null,
7293
+ identity: null,
7294
+ generated: null,
7295
+ collate: null,
7296
+ domain: null
7297
+ })),
7298
+ view.oid,
7299
+ view.temp
7300
+ );
7301
+ table.rows = view.matRows ?? [];
7302
+ return table;
7303
+ }
7304
+
7413
7305
  // src/schema/index-catalog.ts
7414
7306
  var isKeyConstraint = (constraint) => constraint.kind === "primary_key" || constraint.kind === "unique";
7415
7307
  var ACCESS_METHODS = /* @__PURE__ */ new Map([
@@ -7438,6 +7330,8 @@ function syncIndexCatalog(state) {
7438
7330
  const tables = /* @__PURE__ */ new Map();
7439
7331
  for (const schema of state.schemas.values()) {
7440
7332
  for (const table of schema.tables.values()) tables.set(table.oid, { schema, table });
7333
+ for (const view of schema.views.values())
7334
+ if (view.materialized) tables.set(view.oid, { schema, table: materializedTable(view) });
7441
7335
  }
7442
7336
  const backing = /* @__PURE__ */ new Map();
7443
7337
  for (const { table } of tables.values()) {
@@ -7635,6 +7529,55 @@ function deparseExpr(e) {
7635
7529
  }
7636
7530
  }
7637
7531
 
7532
+ // src/types/resolve.ts
7533
+ var SERIALS = {
7534
+ smallserial: "int2",
7535
+ serial2: "int2",
7536
+ serial: "int4",
7537
+ serial4: "int4",
7538
+ bigserial: "int8",
7539
+ serial8: "int8"
7540
+ };
7541
+ function modOf(t, mods) {
7542
+ if (mods.length === 0) return null;
7543
+ if (t === "numeric") return { a: mods[0], b: mods[1] ?? 0 };
7544
+ return { a: mods[0] };
7545
+ }
7546
+ function resolveTypeName(state, tn) {
7547
+ const joined = tn.parts.join(".");
7548
+ const bare = tn.parts.length === 1 ? tn.parts[0] : tn.parts.length === 2 && tn.parts[0] === "pg_catalog" ? tn.parts[1] : null;
7549
+ if (bare !== null) {
7550
+ const serial = SERIALS[bare];
7551
+ if (serial !== void 0 && tn.arrayDims === 0) {
7552
+ return { column: { id: serial, mod: null }, domain: null, serial };
7553
+ }
7554
+ const builtin = normalizeTypeName(bare);
7555
+ if (builtin !== null) {
7556
+ const id = tn.arrayDims > 0 ? arrayTypeOf(builtin) : builtin;
7557
+ return { column: { id, mod: modOf(builtin, tn.mods) }, domain: null, serial: null };
7558
+ }
7559
+ }
7560
+ const enumData = state.findEnum(tn.parts);
7561
+ if (enumData) {
7562
+ const elem = `enum:${enumData.schema}.${enumData.name}`;
7563
+ const id = tn.arrayDims > 0 ? arrayTypeOf(elem) : elem;
7564
+ return { column: { id, mod: null }, domain: null, serial: null };
7565
+ }
7566
+ const domainData = state.findDomain(tn.parts);
7567
+ if (domainData) {
7568
+ if (tn.arrayDims > 0) {
7569
+ const id = arrayTypeOf(domainData.baseType.id);
7570
+ return { column: { id, mod: domainData.baseType.mod }, domain: null, serial: null };
7571
+ }
7572
+ return {
7573
+ column: domainData.baseType,
7574
+ domain: `${domainData.schema}.${domainData.name}`,
7575
+ serial: null
7576
+ };
7577
+ }
7578
+ throw pgError("undefined_object", `type "${joined}" does not exist`);
7579
+ }
7580
+
7638
7581
  // src/sql/ruleutils.ts
7639
7582
  var BOOL = "bool";
7640
7583
  var TEXT = "text";
@@ -8271,7 +8214,7 @@ function setDatabaseCatalogContext(state, context) {
8271
8214
  var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
8272
8215
  function findSequenceForCall(ctx, name) {
8273
8216
  const parts = parseQualifiedName(name);
8274
- 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);
8275
8218
  if (!seq) {
8276
8219
  throw pgError("undefined_table", `relation "${name}" does not exist`, "42P01");
8277
8220
  }
@@ -8432,7 +8375,11 @@ function getMiscFunctions() {
8432
8375
  }
8433
8376
  const name = argText(ctx, args[0]).toLowerCase();
8434
8377
  const value = args[1].v === null ? "" : argText(ctx, args[1]);
8435
- ctx.state.settings.set(name, value);
8378
+ if (!ctx.state.settings.has(name) && !name.includes("."))
8379
+ throw pgError("undefined_object", `unrecognized configuration parameter "${name}"`, "42704");
8380
+ validateStorageSetting(name, value);
8381
+ const local = args[2]?.v === true;
8382
+ if (!local || ctx.state.inTransaction) (local ? ctx.state.localSettings : ctx.state.settings).set(name, value);
8436
8383
  return tv("text", value);
8437
8384
  });
8438
8385
  m.set(
@@ -8491,17 +8438,16 @@ function getMiscFunctions() {
8491
8438
  "pg_get_serial_sequence",
8492
8439
  strict("text", (ctx, args) => {
8493
8440
  const tableName2 = argText(ctx, args[0]);
8494
- const column = argText(ctx, args[1]).toLowerCase();
8441
+ const column = argText(ctx, args[1]);
8495
8442
  const table = ctx.state.findTable(parseQualifiedName(tableName2));
8496
8443
  if (!table) throw pgError("undefined_table", `relation "${tableName2}" does not exist`, "42P01");
8497
8444
  const col = table.columns.find((c) => c.name === column);
8498
8445
  if (!col)
8499
8446
  throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
8500
- if (!col.identity) return tv("text", null);
8501
- return tv(
8502
- "text",
8503
- 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
8504
8449
  );
8450
+ return tv("text", seq ? [seq.schema, seq.name].map(quoteIdent).join(".") : null);
8505
8451
  })
8506
8452
  );
8507
8453
  m.set("format_type", (ctx, args) => {
@@ -13425,6 +13371,146 @@ function isSrfName(name) {
13425
13371
  return SRFS.has(name);
13426
13372
  }
13427
13373
 
13374
+ // src/executor/relation.ts
13375
+ var RowScope = class {
13376
+ constructor(columns, row, parent = null, rangeVars = /* @__PURE__ */ new Set()) {
13377
+ this.columns = columns;
13378
+ this.row = row;
13379
+ this.parent = parent;
13380
+ this.rangeVars = rangeVars;
13381
+ }
13382
+ columns;
13383
+ row;
13384
+ parent;
13385
+ rangeVars;
13386
+ /** Resolve a (possibly qualified) column reference. undefined = not found. */
13387
+ lookup(parts) {
13388
+ if (parts.length === 1) {
13389
+ const name2 = parts[0];
13390
+ let found2;
13391
+ let count2 = 0;
13392
+ for (let i = 0; i < this.columns.length; i++) {
13393
+ const c = this.columns[i];
13394
+ if (c.name === name2 && (!c.hidden || c.system)) {
13395
+ count2++;
13396
+ if (count2 > 1) {
13397
+ throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
13398
+ }
13399
+ found2 = tv(c.type, this.row[i] ?? null);
13400
+ }
13401
+ }
13402
+ if (found2 !== void 0) return found2;
13403
+ if (this.rangeVars.has(name2)) {
13404
+ return this.wholeRow(name2);
13405
+ }
13406
+ return this.parent?.lookup(parts);
13407
+ }
13408
+ const table = parts[parts.length - 2];
13409
+ const name = parts[parts.length - 1];
13410
+ let found;
13411
+ let count = 0;
13412
+ for (let i = 0; i < this.columns.length; i++) {
13413
+ const c = this.columns[i];
13414
+ if (c.table === table && c.name === name) {
13415
+ count++;
13416
+ if (count > 1) {
13417
+ throw pgError("ambiguous_column", `column reference "${name}" is ambiguous`);
13418
+ }
13419
+ found = tv(c.type, this.row[i] ?? null);
13420
+ }
13421
+ }
13422
+ if (found !== void 0) return found;
13423
+ return this.parent?.lookup(parts);
13424
+ }
13425
+ /** Build a record value from all columns belonging to a range variable. */
13426
+ wholeRow(rangeVar) {
13427
+ const types = [];
13428
+ const values = [];
13429
+ const names = [];
13430
+ for (let i = 0; i < this.columns.length; i++) {
13431
+ const c = this.columns[i];
13432
+ if (c.table === rangeVar && !c.system) {
13433
+ types.push(c.type);
13434
+ values.push(this.row[i] ?? null);
13435
+ names.push(c.name);
13436
+ }
13437
+ }
13438
+ if (types.length === 0) return void 0;
13439
+ return tv("record", { kind: "pgrecord", types, values, names });
13440
+ }
13441
+ hasRangeVar(name) {
13442
+ if (this.rangeVars.has(name)) return true;
13443
+ return this.parent?.hasRangeVar(name) ?? false;
13444
+ }
13445
+ };
13446
+ function childEnv(env, outer) {
13447
+ return {
13448
+ ctx: env.ctx,
13449
+ params: env.params,
13450
+ ctes: env.ctes,
13451
+ outer,
13452
+ allowUnpopulatedMatviews: env.allowUnpopulatedMatviews
13453
+ };
13454
+ }
13455
+ function relationResult(rel3, command2) {
13456
+ const visible = rel3.columns.map((c, i) => ({ i, c })).filter(({ c }) => !c.hidden);
13457
+ return {
13458
+ columns: visible.map(({ c }) => ({ name: c.name, type: c.type })),
13459
+ rows: rel3.rows.map((r) => visible.map(({ i }) => r[i] ?? null)),
13460
+ command: command2,
13461
+ rowCount: rel3.rows.length
13462
+ };
13463
+ }
13464
+ function commandResult(command2, rowCount) {
13465
+ return { columns: [], rows: [], command: command2, rowCount };
13466
+ }
13467
+ function inferColumnName(e) {
13468
+ switch (e.type) {
13469
+ case "colref":
13470
+ return e.parts[e.parts.length - 1];
13471
+ case "func":
13472
+ return e.name[e.name.length - 1];
13473
+ case "cast": {
13474
+ const inner = inferColumnName(e.expr);
13475
+ if (inner !== "?column?") return inner;
13476
+ return e.target.parts[e.target.parts.length - 1];
13477
+ }
13478
+ case "collate":
13479
+ return inferColumnName(e.expr);
13480
+ case "case":
13481
+ return "case";
13482
+ case "array_ctor":
13483
+ case "array_query":
13484
+ return "array";
13485
+ case "row":
13486
+ return "row";
13487
+ case "subquery_expr":
13488
+ return e.kind === "exists" ? "exists" : "?column?";
13489
+ case "bool_lit":
13490
+ return "bool";
13491
+ case "extract":
13492
+ return "extract";
13493
+ case "position":
13494
+ return "position";
13495
+ case "substring_sql":
13496
+ return "substring";
13497
+ case "overlay":
13498
+ return "overlay";
13499
+ case "trim":
13500
+ return e.side === "leading" ? "ltrim" : e.side === "trailing" ? "rtrim" : "btrim";
13501
+ case "field_select":
13502
+ return e.field === "*" ? "?column?" : e.field;
13503
+ case "at_time_zone":
13504
+ return "timezone";
13505
+ case "grouping_func":
13506
+ return "grouping";
13507
+ case "subscript":
13508
+ return inferColumnName(e.base);
13509
+ default:
13510
+ return "?column?";
13511
+ }
13512
+ }
13513
+
13428
13514
  // src/indexes/index.ts
13429
13515
  var IndexStore = class _IndexStore {
13430
13516
  name;
@@ -13487,53 +13573,228 @@ function ensureIndexStores(env, table) {
13487
13573
  const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
13488
13574
  if (key !== null) store.insert(key, i);
13489
13575
  }
13490
- stores.set(spec.name, store);
13491
- }
13492
- const schema = env.ctx.state.schemas.get(table.schema);
13493
- if (schema) {
13494
- for (const idx of schema.indexes.values()) {
13495
- if (idx.table !== table.name || idx.unique) continue;
13496
- stores.set(idx.name, new IndexStore(idx.name, false));
13576
+ stores.set(spec.name, store);
13577
+ }
13578
+ const schema = env.ctx.state.schemas.get(table.schema);
13579
+ if (schema) {
13580
+ for (const idx of schema.indexes.values()) {
13581
+ if (idx.table !== table.name || idx.unique) continue;
13582
+ stores.set(idx.name, new IndexStore(idx.name, false));
13583
+ }
13584
+ }
13585
+ table.indexStores = stores;
13586
+ return stores;
13587
+ }
13588
+ function indexStoreFor(env, table, spec) {
13589
+ const stores = ensureIndexStores(env, table);
13590
+ let store = stores.get(spec.name);
13591
+ if (!store) {
13592
+ store = new IndexStore(spec.name, true);
13593
+ for (let i = 0; i < table.rowCount(); i++) {
13594
+ const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
13595
+ if (key !== null) store.insert(key, i);
13596
+ }
13597
+ stores.set(spec.name, store);
13598
+ }
13599
+ return store;
13600
+ }
13601
+ function indexInsertRow(env, table, rowIdx, row) {
13602
+ for (const spec of uniqueSpecsFor(env, table)) {
13603
+ const key = uniqueKeyOf(env, table, spec, row);
13604
+ if (key === null) continue;
13605
+ indexStoreFor(env, table, spec).insert(key, rowIdx);
13606
+ }
13607
+ }
13608
+ function indexRemoveRow(env, table, rowIdx, row) {
13609
+ if (!table.indexStores) return;
13610
+ for (const spec of uniqueSpecsFor(env, table)) {
13611
+ const key = uniqueKeyOf(env, table, spec, row);
13612
+ if (key === null) continue;
13613
+ table.indexStores.get(spec.name)?.remove(key, rowIdx);
13614
+ }
13615
+ }
13616
+ function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
13617
+ indexRemoveRow(env, table, rowIdx, oldRow);
13618
+ indexInsertRow(env, table, rowIdx, newRow);
13619
+ }
13620
+ function rebuildTableIndexes(env, table) {
13621
+ table.indexStores = null;
13622
+ ensureIndexStores(env, table);
13623
+ }
13624
+
13625
+ // src/constraints/enforce.ts
13626
+ function tableScope(table, row) {
13627
+ const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
13628
+ return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
13629
+ }
13630
+ function checkNotNull(env, table, row) {
13631
+ void env;
13632
+ for (let i = 0; i < table.columns.length; i++) {
13633
+ const c = table.columns[i];
13634
+ if (c.notNull && (row[i] ?? null) === null) {
13635
+ throw pgError(
13636
+ "not_null_violation",
13637
+ `null value in column "${c.name}" of relation "${table.name}" violates not-null constraint`,
13638
+ "23502"
13639
+ );
13640
+ }
13641
+ }
13642
+ }
13643
+ function checkChecks(env, table, row) {
13644
+ for (const con of table.constraints) {
13645
+ if (con.kind !== "check") continue;
13646
+ const scope = makeEvalScope(env, tableScope(table, row));
13647
+ const v = evalExpr(env.ctx, scope, con.expr);
13648
+ if (v.v === null) continue;
13649
+ const b = castTo(env.ctx, v, "bool", {});
13650
+ if (b.v !== true) {
13651
+ throw pgError(
13652
+ "check_violation",
13653
+ `new row for relation "${table.name}" violates check constraint "${con.name}"`,
13654
+ "23514"
13655
+ );
13656
+ }
13657
+ }
13658
+ }
13659
+ function uniqueSpecsFor(env, table) {
13660
+ const specs = [];
13661
+ for (const con of table.constraints) {
13662
+ if (con.kind !== "primary_key" && con.kind !== "unique") continue;
13663
+ specs.push({
13664
+ name: con.name,
13665
+ keys: con.columns.map((c) => ({ colIdx: table.columnIndex(c), expr: null })),
13666
+ columnNames: con.columns,
13667
+ nullsNotDistinct: con.kind === "unique" ? con.nullsNotDistinct : false,
13668
+ where: null,
13669
+ isPrimary: con.kind === "primary_key"
13670
+ });
13671
+ }
13672
+ const schema = env.ctx.state.schemas.get(table.schema);
13673
+ if (schema) {
13674
+ for (const idx of schema.indexes.values()) {
13675
+ if (idx.table !== table.name || !idx.unique || idx.isConstraint || idx.valid === false) continue;
13676
+ specs.push(uniqueSpecOfIndex(table, idx));
13677
+ }
13678
+ }
13679
+ return specs;
13680
+ }
13681
+ function uniqueSpecOfIndex(table, idx) {
13682
+ return {
13683
+ name: idx.name,
13684
+ keys: idx.columns.map((c) => ({
13685
+ colIdx: c.column !== null ? table.columnIndex(c.column) : -1,
13686
+ expr: c.expr
13687
+ })),
13688
+ columnNames: idx.columns.map((c) => c.column ?? "expr"),
13689
+ nullsNotDistinct: idx.nullsNotDistinct,
13690
+ where: idx.where,
13691
+ isPrimary: false
13692
+ };
13693
+ }
13694
+ function uniqueKeyOf(env, table, spec, row) {
13695
+ if (spec.where) {
13696
+ const scope = makeEvalScope(env, tableScope(table, row));
13697
+ const v = evalExpr(env.ctx, scope, spec.where);
13698
+ if (v.v !== true) return null;
13699
+ }
13700
+ const parts = [];
13701
+ let hasNull = false;
13702
+ for (const k of spec.keys) {
13703
+ let value;
13704
+ let type;
13705
+ if (k.expr) {
13706
+ const scope = makeEvalScope(env, tableScope(table, row));
13707
+ const v = evalExpr(env.ctx, scope, k.expr);
13708
+ value = v.v;
13709
+ type = v.t === "unknown" ? "text" : v.t;
13710
+ } else {
13711
+ value = row[k.colIdx] ?? null;
13712
+ type = table.columns[k.colIdx].type.id;
13713
+ }
13714
+ if (value === null) {
13715
+ hasNull = true;
13716
+ parts.push("\0N");
13717
+ } else {
13718
+ parts.push(datumKey(type, value));
13719
+ }
13720
+ }
13721
+ if (hasNull && !spec.nullsNotDistinct) return null;
13722
+ return parts.join("");
13723
+ }
13724
+ function checkUnique(env, table, row, selfIdx) {
13725
+ for (const spec of uniqueSpecsFor(env, table)) {
13726
+ const key = uniqueKeyOf(env, table, spec, row);
13727
+ if (key === null) continue;
13728
+ indexStoreFor(env, table, spec).checkUnique(key, selfIdx);
13729
+ }
13730
+ }
13731
+ function findConflict(env, table, spec, row) {
13732
+ const key = uniqueKeyOf(env, table, spec, row);
13733
+ if (key === null) return null;
13734
+ const hits = indexStoreFor(env, table, spec).lookup(key);
13735
+ return hits.length > 0 ? hits[0] : null;
13736
+ }
13737
+ function checkForeignKeys(env, table, row) {
13738
+ const state = env.ctx.state;
13739
+ for (const con of table.constraints) {
13740
+ if (con.kind !== "foreign_key") continue;
13741
+ const values = con.columns.map((c) => row[table.columnIndex(c)] ?? null);
13742
+ const nulls = values.filter((v) => v === null).length;
13743
+ if (con.match === "simple" && nulls > 0) continue;
13744
+ if (con.match === "full") {
13745
+ if (nulls === values.length) continue;
13746
+ if (nulls > 0) {
13747
+ throw pgError(
13748
+ "constraint_foreign_key",
13749
+ `insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
13750
+ "23503"
13751
+ );
13752
+ }
13753
+ }
13754
+ const refTable = state.schemas.get(con.refSchema)?.tables.get(con.refTable);
13755
+ if (!refTable) {
13756
+ throw pgError("undefined_table", `relation "${con.refSchema}.${con.refTable}" does not exist`, "42P01");
13757
+ }
13758
+ const refIdxs = con.refColumns.map((c) => refTable.columnIndex(c));
13759
+ const keyTypes = con.refColumns.map((_c, i) => refTable.columns[refIdxs[i]].type.id);
13760
+ const wanted = values.map((v, i) => {
13761
+ const localT = table.columns[table.columnIndex(con.columns[i])].type.id;
13762
+ const cast = castTo(env.ctx, tv(localT, v), keyTypes[i], {});
13763
+ return cast.v === null ? "\0N" : datumKey(keyTypes[i], cast.v);
13764
+ }).join("");
13765
+ let found = false;
13766
+ for (let i = 0; i < refTable.rowCount(); i++) {
13767
+ const r = refTable.rowAt(i);
13768
+ const key = refIdxs.map((ri, j) => {
13769
+ const v = r[ri] ?? null;
13770
+ return v === null ? "\0N" : datumKey(keyTypes[j], v);
13771
+ }).join("");
13772
+ if (key === wanted) {
13773
+ found = true;
13774
+ break;
13775
+ }
13776
+ }
13777
+ if (!found) {
13778
+ throw pgError(
13779
+ "constraint_foreign_key",
13780
+ `insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
13781
+ "23503"
13782
+ );
13497
13783
  }
13498
13784
  }
13499
- table.indexStores = stores;
13500
- return stores;
13501
13785
  }
13502
- function indexStoreFor(env, table, spec) {
13503
- const stores = ensureIndexStores(env, table);
13504
- let store = stores.get(spec.name);
13505
- if (!store) {
13506
- store = new IndexStore(spec.name, true);
13507
- for (let i = 0; i < table.rowCount(); i++) {
13508
- const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
13509
- if (key !== null) store.insert(key, i);
13786
+ function referencingConstraints(env, table) {
13787
+ const out = [];
13788
+ for (const schema of env.ctx.state.schemas.values()) {
13789
+ for (const t of schema.tables.values()) {
13790
+ for (const con of t.constraints) {
13791
+ if (con.kind === "foreign_key" && con.refSchema === table.schema && con.refTable === table.name) {
13792
+ out.push({ table: t, constraint: con });
13793
+ }
13794
+ }
13510
13795
  }
13511
- stores.set(spec.name, store);
13512
- }
13513
- return store;
13514
- }
13515
- function indexInsertRow(env, table, rowIdx, row) {
13516
- for (const spec of uniqueSpecsFor(env, table)) {
13517
- const key = uniqueKeyOf(env, table, spec, row);
13518
- if (key === null) continue;
13519
- indexStoreFor(env, table, spec).insert(key, rowIdx);
13520
- }
13521
- }
13522
- function indexRemoveRow(env, table, rowIdx, row) {
13523
- if (!table.indexStores) return;
13524
- for (const spec of uniqueSpecsFor(env, table)) {
13525
- const key = uniqueKeyOf(env, table, spec, row);
13526
- if (key === null) continue;
13527
- table.indexStores.get(spec.name)?.remove(key, rowIdx);
13528
13796
  }
13529
- }
13530
- function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
13531
- indexRemoveRow(env, table, rowIdx, oldRow);
13532
- indexInsertRow(env, table, rowIdx, newRow);
13533
- }
13534
- function rebuildTableIndexes(env, table) {
13535
- table.indexStores = null;
13536
- ensureIndexStores(env, table);
13797
+ return out;
13537
13798
  }
13538
13799
 
13539
13800
  // src/planner/access.ts
@@ -13611,7 +13872,7 @@ function tryIndexedFromItem(env, item, where) {
13611
13872
  if (!table) return null;
13612
13873
  const alias = item.alias ?? item.name[item.name.length - 1];
13613
13874
  table.materializeSlab();
13614
- return tryIndexedTableRows(env, table, alias, where);
13875
+ return tryIndexedTableRows(env, table, alias, where)?.map((row) => [...row, table.rowXmins.get(row) ?? 2]) ?? null;
13615
13876
  }
13616
13877
  function joinKeyFromRow(row, colIdxs, srcTypes, unifiedTypes, ctx) {
13617
13878
  const parts = [];
@@ -15419,10 +15680,9 @@ var Parser = class {
15419
15680
  return this.parseCreateFunction(orReplace);
15420
15681
  }
15421
15682
  if (this.atKw("trigger") || this.atKw("constraint") && this.atKw("trigger", 1)) {
15422
- if (this.eatKw("constraint")) {
15423
- }
15683
+ const constraint = this.eatKw("constraint");
15424
15684
  this.expectKw("trigger");
15425
- return this.parseCreateTrigger(orReplace);
15685
+ return this.parseCreateTrigger(orReplace, constraint);
15426
15686
  }
15427
15687
  if (this.atKw("extension")) {
15428
15688
  this.pos++;
@@ -16102,6 +16362,7 @@ var Parser = class {
16102
16362
  let sqlBody = null;
16103
16363
  let volatility = null;
16104
16364
  let strict2 = false;
16365
+ const settings = {};
16105
16366
  for (; ; ) {
16106
16367
  if (this.eatKw("language")) {
16107
16368
  language = this.peek().type === "string" ? this.next().value : this.ident(true);
@@ -16159,8 +16420,23 @@ var Parser = class {
16159
16420
  continue;
16160
16421
  }
16161
16422
  if (this.eatKw("set")) {
16162
- this.ident(true);
16163
- 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
+ }
16164
16440
  continue;
16165
16441
  }
16166
16442
  if (this.eatKw("window")) throw unsupported("window functions via CREATE FUNCTION");
@@ -16240,10 +16516,11 @@ var Parser = class {
16240
16516
  body,
16241
16517
  sqlBody,
16242
16518
  volatility,
16243
- strict: strict2
16519
+ strict: strict2,
16520
+ settings
16244
16521
  };
16245
16522
  }
16246
- parseCreateTrigger(orReplace) {
16523
+ parseCreateTrigger(orReplace, constraint) {
16247
16524
  const name = this.ident();
16248
16525
  let timing;
16249
16526
  if (this.eatKw("before")) timing = "before";
@@ -16273,9 +16550,18 @@ var Parser = class {
16273
16550
  this.expectKw("on");
16274
16551
  const table = this.qualifiedName();
16275
16552
  if (this.eatKw("referencing")) throw unsupported("trigger transition tables");
16276
- while (this.atKw("not") || this.atKw("deferrable") || this.atKw("initially")) {
16277
- this.pos++;
16278
- }
16553
+ let deferrable = false;
16554
+ let initiallyDeferred = false;
16555
+ if (this.eatKw("not")) this.expectKw("deferrable");
16556
+ else if (this.eatKw("deferrable")) deferrable = true;
16557
+ if (this.eatKw("initially")) {
16558
+ if (this.eatKw("deferred")) initiallyDeferred = true;
16559
+ else this.expectKw("immediate");
16560
+ }
16561
+ if ((deferrable || initiallyDeferred) && !constraint)
16562
+ this.errorAt(this.peek(), "only constraint triggers can be deferred");
16563
+ if (initiallyDeferred && !deferrable)
16564
+ this.errorAt(this.peek(), "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
16279
16565
  let forEachRow = false;
16280
16566
  if (this.eatKw("for")) {
16281
16567
  this.eatKw("each");
@@ -16300,7 +16586,21 @@ var Parser = class {
16300
16586
  } while (this.eatPunct(","));
16301
16587
  }
16302
16588
  this.expectPunct(")");
16303
- return { type: "create_trigger", orReplace, name, timing, events, table, forEachRow, when, funcName, funcArgs };
16589
+ return {
16590
+ type: "create_trigger",
16591
+ constraint,
16592
+ deferrable,
16593
+ initiallyDeferred,
16594
+ orReplace,
16595
+ name,
16596
+ timing,
16597
+ events,
16598
+ table,
16599
+ forEachRow,
16600
+ when,
16601
+ funcName,
16602
+ funcArgs
16603
+ };
16304
16604
  }
16305
16605
  // --- ALTER --------------------------------------------------------------------
16306
16606
  parseAlter() {
@@ -16326,8 +16626,8 @@ var Parser = class {
16326
16626
  type: "alter_sequence",
16327
16627
  name,
16328
16628
  ifExists,
16329
- options: { ownedBy: void 0 },
16330
- ...{ renameTo: to }
16629
+ options: {},
16630
+ renameTo: to
16331
16631
  };
16332
16632
  }
16333
16633
  if (this.atKw("set") && (this.atKw("logged", 1) || this.atKw("unlogged", 1))) {
@@ -16645,9 +16945,15 @@ var Parser = class {
16645
16945
  this.skipToStatementEnd();
16646
16946
  return { type: "no_op", what: "SET TRANSACTION" };
16647
16947
  }
16648
- if (this.atKw("constraints")) {
16649
- this.skipToStatementEnd();
16650
- return { type: "no_op", what: "SET CONSTRAINTS" };
16948
+ if (this.eatKw("constraints")) {
16949
+ const names = this.eatKw("all") ? null : [];
16950
+ if (names)
16951
+ do {
16952
+ names.push(this.qualifiedName());
16953
+ } while (this.eatPunct(","));
16954
+ const deferred = this.eatKw("deferred");
16955
+ if (!deferred) this.expectKw("immediate");
16956
+ return { type: "set_constraints", names, deferred };
16651
16957
  }
16652
16958
  if (this.atKw("role") || this.atKw("session", 0) && this.atKw("authorization", 1)) {
16653
16959
  this.skipToStatementEnd();
@@ -18897,7 +19203,20 @@ function runFunctionBody(env, fn, args) {
18897
19203
  }
18898
19204
  return last;
18899
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
+ }
18900
19216
  function callSqlFunctionScalar(env, fn, args) {
19217
+ return withFunctionSettings(env, fn, () => callSqlFunctionScalarBody(env, fn, args));
19218
+ }
19219
+ function callSqlFunctionScalarBody(env, fn, args) {
18901
19220
  const retT = fn.returns ?? "text";
18902
19221
  if (fn.language === "plpgsql") {
18903
19222
  return callPlpgsqlScalar(env, fn, args);
@@ -18927,6 +19246,9 @@ function callSqlFunctionScalar(env, fn, args) {
18927
19246
  return castTo(env.ctx, tv(rawT, raw), retT, {});
18928
19247
  }
18929
19248
  function callSqlFunctionSet(env, fn, args) {
19249
+ return withFunctionSettings(env, fn, () => callSqlFunctionSetBody(env, fn, args));
19250
+ }
19251
+ function callSqlFunctionSetBody(env, fn, args) {
18930
19252
  if (fn.language === "plpgsql") {
18931
19253
  return callPlpgsqlSet(env, fn, args);
18932
19254
  }
@@ -19022,12 +19344,12 @@ function executeRecursiveCte(env, cte, query) {
19022
19344
  table: null
19023
19345
  }));
19024
19346
  const seen = /* @__PURE__ */ new Set();
19025
- const keyOf = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(columns[i].type, v)).join("");
19347
+ const keyOf2 = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(columns[i].type, v)).join("");
19026
19348
  let result = [];
19027
19349
  let working = [];
19028
19350
  for (const row of base.rows) {
19029
19351
  if (!body.all) {
19030
- const k = keyOf(row);
19352
+ const k = keyOf2(row);
19031
19353
  if (seen.has(k)) continue;
19032
19354
  seen.add(k);
19033
19355
  }
@@ -19060,7 +19382,7 @@ function executeRecursiveCte(env, cte, query) {
19060
19382
  return castTo(env.ctx, tv(srcT === UNKNOWN ? "text" : srcT, v), columns[i].type, {}).v;
19061
19383
  });
19062
19384
  if (!body.all) {
19063
- const k = keyOf(row);
19385
+ const k = keyOf2(row);
19064
19386
  if (seen.has(k)) continue;
19065
19387
  seen.add(k);
19066
19388
  }
@@ -19081,15 +19403,17 @@ function executeRecursiveCte(env, cte, query) {
19081
19403
  return rel3;
19082
19404
  }
19083
19405
  function renameWithAliases(rel3, label, colAliases, what) {
19084
- if (colAliases && colAliases.length > rel3.columns.length) {
19406
+ const visibleWidth = rel3.columns.filter((column) => !column.system).length;
19407
+ if (colAliases && colAliases.length > visibleWidth) {
19085
19408
  throw pgError(
19086
19409
  "invalid_column_reference",
19087
- `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`,
19088
19411
  "42P10"
19089
19412
  );
19090
19413
  }
19091
19414
  const columns = rel3.columns.map((c, i) => ({
19092
- name: colAliases?.[i] ?? c.name,
19415
+ ...c,
19416
+ name: c.system ? c.name : colAliases?.[i] ?? c.name,
19093
19417
  type: c.type === UNKNOWN ? "text" : c.type,
19094
19418
  table: label
19095
19419
  }));
@@ -19110,8 +19434,11 @@ function materializeItem(env, item, scope) {
19110
19434
  if (table) {
19111
19435
  table.materializeSlab();
19112
19436
  const rel3 = {
19113
- columns: table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
19114
- 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])
19115
19442
  };
19116
19443
  return { rel: renameWithAliases(rel3, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
19117
19444
  }
@@ -19741,7 +20068,7 @@ function resolveColIdx(columns, parts) {
19741
20068
  let found = -1;
19742
20069
  for (let i = 0; i < columns.length; i++) {
19743
20070
  const c = columns[i];
19744
- if (!c.hidden && c.name === name2) {
20071
+ if ((!c.hidden || c.system) && c.name === name2) {
19745
20072
  if (found !== -1) return null;
19746
20073
  found = i;
19747
20074
  }
@@ -20240,7 +20567,7 @@ function setOpRelation(env, op) {
20240
20567
  );
20241
20568
  const lrows = normalize2(left);
20242
20569
  const rrows = normalize2(right);
20243
- const keyOf = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(types[i], v)).join("");
20570
+ const keyOf2 = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(types[i], v)).join("");
20244
20571
  let rows;
20245
20572
  switch (op.op) {
20246
20573
  case "union": {
@@ -20248,7 +20575,7 @@ function setOpRelation(env, op) {
20248
20575
  if (!op.all) {
20249
20576
  const seen = /* @__PURE__ */ new Set();
20250
20577
  rows = rows.filter((r) => {
20251
- const k = keyOf(r);
20578
+ const k = keyOf2(r);
20252
20579
  if (seen.has(k)) return false;
20253
20580
  seen.add(k);
20254
20581
  return true;
@@ -20259,13 +20586,13 @@ function setOpRelation(env, op) {
20259
20586
  case "intersect": {
20260
20587
  const rightCounts = /* @__PURE__ */ new Map();
20261
20588
  for (const r of rrows) {
20262
- const k = keyOf(r);
20589
+ const k = keyOf2(r);
20263
20590
  rightCounts.set(k, (rightCounts.get(k) ?? 0) + 1);
20264
20591
  }
20265
20592
  rows = [];
20266
20593
  const emitted = /* @__PURE__ */ new Set();
20267
20594
  for (const r of lrows) {
20268
- const k = keyOf(r);
20595
+ const k = keyOf2(r);
20269
20596
  const avail = rightCounts.get(k) ?? 0;
20270
20597
  if (avail <= 0) continue;
20271
20598
  if (op.all) {
@@ -20281,13 +20608,13 @@ function setOpRelation(env, op) {
20281
20608
  case "except": {
20282
20609
  const rightCounts = /* @__PURE__ */ new Map();
20283
20610
  for (const r of rrows) {
20284
- const k = keyOf(r);
20611
+ const k = keyOf2(r);
20285
20612
  rightCounts.set(k, (rightCounts.get(k) ?? 0) + 1);
20286
20613
  }
20287
20614
  rows = [];
20288
20615
  const emitted = /* @__PURE__ */ new Set();
20289
20616
  for (const r of lrows) {
20290
- const k = keyOf(r);
20617
+ const k = keyOf2(r);
20291
20618
  if (op.all) {
20292
20619
  const avail = rightCounts.get(k) ?? 0;
20293
20620
  if (avail > 0) {
@@ -20325,7 +20652,7 @@ function expandTargets(core, columns) {
20325
20652
  let any = false;
20326
20653
  for (let i = 0; i < columns.length; i++) {
20327
20654
  const c = columns[i];
20328
- if (c.table === label) {
20655
+ if (c.table === label && !c.system) {
20329
20656
  any = true;
20330
20657
  items.push({ name: c.name, kind: "col", colIdx: i, expr: null, hidden: false });
20331
20658
  }
@@ -20763,179 +21090,26 @@ function executeSelectStmt(env0, stmt) {
20763
21090
  return applyLimitOffset(env, rel3, stmt.limit, stmt.offset);
20764
21091
  }
20765
21092
 
20766
- // src/constraints/enforce.ts
20767
- function tableScope(table, row) {
20768
- const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
20769
- return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
20770
- }
20771
- function checkNotNull(env, table, row) {
20772
- void env;
20773
- for (let i = 0; i < table.columns.length; i++) {
20774
- const c = table.columns[i];
20775
- if (c.notNull && (row[i] ?? null) === null) {
20776
- throw pgError(
20777
- "not_null_violation",
20778
- `null value in column "${c.name}" of relation "${table.name}" violates not-null constraint`,
20779
- "23502"
20780
- );
20781
- }
20782
- }
20783
- }
20784
- function checkChecks(env, table, row) {
20785
- for (const con of table.constraints) {
20786
- if (con.kind !== "check") continue;
20787
- const scope = makeEvalScope(env, tableScope(table, row));
20788
- const v = evalExpr(env.ctx, scope, con.expr);
20789
- if (v.v === null) continue;
20790
- const b = castTo(env.ctx, v, "bool", {});
20791
- if (b.v !== true) {
20792
- throw pgError(
20793
- "check_violation",
20794
- `new row for relation "${table.name}" violates check constraint "${con.name}"`,
20795
- "23514"
20796
- );
20797
- }
20798
- }
20799
- }
20800
- function uniqueSpecsFor(env, table) {
20801
- const specs = [];
20802
- for (const con of table.constraints) {
20803
- if (con.kind !== "primary_key" && con.kind !== "unique") continue;
20804
- specs.push({
20805
- name: con.name,
20806
- keys: con.columns.map((c) => ({ colIdx: table.columnIndex(c), expr: null })),
20807
- columnNames: con.columns,
20808
- nullsNotDistinct: con.kind === "unique" ? con.nullsNotDistinct : false,
20809
- where: null,
20810
- isPrimary: con.kind === "primary_key"
20811
- });
20812
- }
20813
- const schema = env.ctx.state.schemas.get(table.schema);
20814
- if (schema) {
20815
- for (const idx of schema.indexes.values()) {
20816
- if (idx.table !== table.name || !idx.unique || idx.isConstraint || idx.valid === false) continue;
20817
- specs.push(uniqueSpecOfIndex(table, idx));
20818
- }
20819
- }
20820
- return specs;
20821
- }
20822
- function uniqueSpecOfIndex(table, idx) {
20823
- return {
20824
- name: idx.name,
20825
- keys: idx.columns.map((c) => ({
20826
- colIdx: c.column !== null ? table.columnIndex(c.column) : -1,
20827
- expr: c.expr
20828
- })),
20829
- columnNames: idx.columns.map((c) => c.column ?? "expr"),
20830
- nullsNotDistinct: idx.nullsNotDistinct,
20831
- where: idx.where,
20832
- isPrimary: false
20833
- };
20834
- }
20835
- function uniqueKeyOf(env, table, spec, row) {
20836
- if (spec.where) {
20837
- const scope = makeEvalScope(env, tableScope(table, row));
20838
- const v = evalExpr(env.ctx, scope, spec.where);
20839
- if (v.v !== true) return null;
20840
- }
20841
- const parts = [];
20842
- let hasNull = false;
20843
- for (const k of spec.keys) {
20844
- let value;
20845
- let type;
20846
- if (k.expr) {
20847
- const scope = makeEvalScope(env, tableScope(table, row));
20848
- const v = evalExpr(env.ctx, scope, k.expr);
20849
- value = v.v;
20850
- type = v.t === "unknown" ? "text" : v.t;
20851
- } else {
20852
- value = row[k.colIdx] ?? null;
20853
- type = table.columns[k.colIdx].type.id;
20854
- }
20855
- if (value === null) {
20856
- hasNull = true;
20857
- parts.push("\0N");
20858
- } else {
20859
- parts.push(datumKey(type, value));
20860
- }
20861
- }
20862
- if (hasNull && !spec.nullsNotDistinct) return null;
20863
- return parts.join("");
20864
- }
20865
- function checkUnique(env, table, row, selfIdx) {
20866
- for (const spec of uniqueSpecsFor(env, table)) {
20867
- const key = uniqueKeyOf(env, table, spec, row);
20868
- if (key === null) continue;
20869
- indexStoreFor(env, table, spec).checkUnique(key, selfIdx);
20870
- }
20871
- }
20872
- function findConflict(env, table, spec, row) {
20873
- const key = uniqueKeyOf(env, table, spec, row);
20874
- if (key === null) return null;
20875
- const hits = indexStoreFor(env, table, spec).lookup(key);
20876
- return hits.length > 0 ? hits[0] : null;
20877
- }
20878
- function checkForeignKeys(env, table, row) {
20879
- const state = env.ctx.state;
20880
- for (const con of table.constraints) {
20881
- if (con.kind !== "foreign_key") continue;
20882
- const values = con.columns.map((c) => row[table.columnIndex(c)] ?? null);
20883
- const nulls = values.filter((v) => v === null).length;
20884
- if (con.match === "simple" && nulls > 0) continue;
20885
- if (con.match === "full") {
20886
- if (nulls === values.length) continue;
20887
- if (nulls > 0) {
20888
- throw pgError(
20889
- "constraint_foreign_key",
20890
- `insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
20891
- "23503"
20892
- );
20893
- }
20894
- }
20895
- const refTable = state.schemas.get(con.refSchema)?.tables.get(con.refTable);
20896
- if (!refTable) {
20897
- throw pgError("undefined_table", `relation "${con.refSchema}.${con.refTable}" does not exist`, "42P01");
20898
- }
20899
- const refIdxs = con.refColumns.map((c) => refTable.columnIndex(c));
20900
- const keyTypes = con.refColumns.map((_c, i) => refTable.columns[refIdxs[i]].type.id);
20901
- const wanted = values.map((v, i) => {
20902
- const localT = table.columns[table.columnIndex(con.columns[i])].type.id;
20903
- const cast = castTo(env.ctx, tv(localT, v), keyTypes[i], {});
20904
- return cast.v === null ? "\0N" : datumKey(keyTypes[i], cast.v);
20905
- }).join("");
20906
- let found = false;
20907
- for (let i = 0; i < refTable.rowCount(); i++) {
20908
- const r = refTable.rowAt(i);
20909
- const key = refIdxs.map((ri, j) => {
20910
- const v = r[ri] ?? null;
20911
- return v === null ? "\0N" : datumKey(keyTypes[j], v);
20912
- }).join("");
20913
- if (key === wanted) {
20914
- found = true;
20915
- break;
20916
- }
20917
- }
20918
- if (!found) {
20919
- throw pgError(
20920
- "constraint_foreign_key",
20921
- `insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
20922
- "23503"
20923
- );
21093
+ // src/executor/triggers-scope.ts
21094
+ function triggerScope(table, newRow, oldRow) {
21095
+ const cols = [];
21096
+ const row = [];
21097
+ const rangeVars = /* @__PURE__ */ new Set();
21098
+ if (newRow) {
21099
+ rangeVars.add("new");
21100
+ for (let i = 0; i < table.columns.length; i++) {
21101
+ cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "new" });
21102
+ row.push(newRow[i] ?? null);
20924
21103
  }
20925
21104
  }
20926
- }
20927
- function referencingConstraints(env, table) {
20928
- const out = [];
20929
- for (const schema of env.ctx.state.schemas.values()) {
20930
- for (const t of schema.tables.values()) {
20931
- for (const con of t.constraints) {
20932
- if (con.kind === "foreign_key" && con.refSchema === table.schema && con.refTable === table.name) {
20933
- out.push({ table: t, constraint: con });
20934
- }
20935
- }
21105
+ if (oldRow) {
21106
+ rangeVars.add("old");
21107
+ for (let i = 0; i < table.columns.length; i++) {
21108
+ cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "old" });
21109
+ row.push(oldRow[i] ?? null);
20936
21110
  }
20937
21111
  }
20938
- return out;
21112
+ return new RowScope(cols, row, null, rangeVars);
20939
21113
  }
20940
21114
 
20941
21115
  // src/executor/triggers.ts
@@ -20951,6 +21125,18 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
20951
21125
  for (const t of table.triggers) {
20952
21126
  if (t.timing !== timing || !matches(t, event) || !t.forEachRow) continue;
20953
21127
  if (!executor) throw unsupported(`trigger "${t.name}" execution`);
21128
+ if (t.constraint && timing === "after") {
21129
+ if (t.when && !evalPredicate(env, triggerScope(table, newRow, oldRow), t.when)) continue;
21130
+ env.ctx.state.pendingTriggers.push({
21131
+ schema: table.schema,
21132
+ table: table.name,
21133
+ trigger: t.name,
21134
+ event,
21135
+ oldRow: oldRow?.slice() ?? null,
21136
+ newRow: newRow?.slice() ?? null
21137
+ });
21138
+ continue;
21139
+ }
20954
21140
  const result = executor(env, table, t, event, oldRow, timing === "before" ? row : newRow);
20955
21141
  if (timing === "before") {
20956
21142
  if (result === null) return { row: null };
@@ -20959,6 +21145,170 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
20959
21145
  }
20960
21146
  return { row };
20961
21147
  }
21148
+ var keyOf = (schema, name) => JSON.stringify([schema, name]);
21149
+ function flushConstraintTriggers(state, all = false) {
21150
+ const env = { ctx: new EngineCtx(state), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
21151
+ for (let i = 0; i < state.pendingTriggers.length; ) {
21152
+ const pending = state.pendingTriggers[i];
21153
+ const table = state.schemas.get(pending.schema)?.tables.get(pending.table);
21154
+ const trigger = table?.triggers.find((t) => t.name === pending.trigger);
21155
+ if (!table || !trigger) {
21156
+ state.pendingTriggers.splice(i, 1);
21157
+ continue;
21158
+ }
21159
+ const deferred = trigger.deferrable && (state.constraintModes.get(keyOf(table.schema, trigger.name)) ?? trigger.initiallyDeferred);
21160
+ if (!all && state.inTransaction && deferred) {
21161
+ i++;
21162
+ continue;
21163
+ }
21164
+ if (!executor) throw unsupported(`trigger "${trigger.name}" execution`);
21165
+ state.pendingTriggers.splice(i, 1);
21166
+ const changes = state.changes;
21167
+ try {
21168
+ executor(env, table, { ...trigger, when: null }, pending.event, pending.oldRow, pending.newRow);
21169
+ } catch (error) {
21170
+ state.pendingTriggers.splice(i, 0, pending);
21171
+ throw error;
21172
+ } finally {
21173
+ state.changes = changes;
21174
+ }
21175
+ }
21176
+ }
21177
+ function setConstraints(state, stmt) {
21178
+ if (!state.inTransaction) return;
21179
+ const matches2 = [];
21180
+ if (stmt.names) {
21181
+ for (const name of stmt.names) {
21182
+ const schemas = name.length > 1 ? [name[name.length - 2]] : state.effectiveSearchPath();
21183
+ let found = false;
21184
+ for (const schema of schemas) {
21185
+ const items = [...state.schemas.get(schema)?.tables.values() ?? []].flatMap(
21186
+ (table) => table.triggers.filter((t) => t.constraint && t.name === name[name.length - 1])
21187
+ );
21188
+ if (items.length) {
21189
+ for (const trigger of items) matches2.push({ schema, trigger });
21190
+ found = true;
21191
+ break;
21192
+ }
21193
+ }
21194
+ if (!found) throw pgError("undefined_object", `constraint "${name.join(".")}" does not exist`, "42704");
21195
+ }
21196
+ } else {
21197
+ for (const schema of state.schemas.values())
21198
+ for (const table of schema.tables.values())
21199
+ for (const trigger of table.triggers)
21200
+ if (trigger.constraint && trigger.deferrable) matches2.push({ schema: schema.name, trigger });
21201
+ }
21202
+ for (const { trigger } of matches2)
21203
+ if (stmt.deferred && !trigger.deferrable)
21204
+ throw pgError("misuse", `constraint "${trigger.name}" is not deferrable`, "55000");
21205
+ const previous = new Map(state.constraintModes);
21206
+ for (const { schema, trigger } of matches2) state.constraintModes.set(keyOf(schema, trigger.name), stmt.deferred);
21207
+ try {
21208
+ if (!stmt.deferred) flushConstraintTriggers(state);
21209
+ } catch (error) {
21210
+ state.constraintModes = previous;
21211
+ throw error;
21212
+ }
21213
+ }
21214
+
21215
+ // src/transactions/manager.ts
21216
+ var TransactionManager = class {
21217
+ constructor(state) {
21218
+ this.state = state;
21219
+ }
21220
+ state;
21221
+ base = null;
21222
+ savepoints = [];
21223
+ freezeDepth = 0;
21224
+ get inTransaction() {
21225
+ return this.base !== null;
21226
+ }
21227
+ takeSnapshot() {
21228
+ this.state.freezeShared();
21229
+ this.freezeDepth++;
21230
+ return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
21231
+ }
21232
+ restore(snap) {
21233
+ this.state.restoreFrom(snap.state);
21234
+ this.state.prng.setState(snap.prngState);
21235
+ }
21236
+ thawOnce() {
21237
+ if (this.freezeDepth > 0) {
21238
+ this.state.thawShared();
21239
+ this.freezeDepth--;
21240
+ }
21241
+ }
21242
+ begin() {
21243
+ if (this.base !== null) {
21244
+ return;
21245
+ }
21246
+ this.base = this.takeSnapshot();
21247
+ this.state.inTransaction = true;
21248
+ assert(this.freezeDepth === 1, "BEGIN freeze depth");
21249
+ }
21250
+ commit() {
21251
+ try {
21252
+ flushConstraintTriggers(this.state, true);
21253
+ } catch (error) {
21254
+ this.rollback();
21255
+ throw error;
21256
+ }
21257
+ this.base = null;
21258
+ this.savepoints = [];
21259
+ this.state.inTransaction = false;
21260
+ this.state.transactionXid = null;
21261
+ this.state.localSettings.clear();
21262
+ this.state.pendingTriggers = [];
21263
+ this.state.constraintModes.clear();
21264
+ while (this.freezeDepth > 0) this.thawOnce();
21265
+ }
21266
+ rollback() {
21267
+ if (this.base !== null) {
21268
+ this.restore(this.base);
21269
+ }
21270
+ this.base = null;
21271
+ this.savepoints = [];
21272
+ this.state.inTransaction = false;
21273
+ this.state.transactionXid = null;
21274
+ this.state.localSettings.clear();
21275
+ this.state.pendingTriggers = [];
21276
+ this.state.constraintModes.clear();
21277
+ while (this.freezeDepth > 0) this.thawOnce();
21278
+ }
21279
+ savepoint(name) {
21280
+ if (this.base === null) {
21281
+ throw pgError("transaction_state", "SAVEPOINT can only be used in transaction blocks", "25P01");
21282
+ }
21283
+ this.savepoints.push({ name, snap: this.takeSnapshot() });
21284
+ }
21285
+ releaseSavepoint(name) {
21286
+ const idx = this.findSavepoint(name);
21287
+ this.savepoints.splice(idx);
21288
+ }
21289
+ rollbackToSavepoint(name) {
21290
+ const idx = this.findSavepoint(name);
21291
+ const sp = this.savepoints[idx];
21292
+ this.restore(sp.snap);
21293
+ this.savepoints.splice(idx + 1);
21294
+ }
21295
+ findSavepoint(name) {
21296
+ if (this.base === null) {
21297
+ throw pgError("transaction_state", `SAVEPOINT can only be used in transaction blocks`, "25P01");
21298
+ }
21299
+ for (let i = this.savepoints.length - 1; i >= 0; i--) {
21300
+ if (this.savepoints[i].name === name) return i;
21301
+ }
21302
+ throw pgError("invalid_savepoint_specification", `savepoint "${name}" does not exist`, "3B001");
21303
+ }
21304
+ reset() {
21305
+ this.base = null;
21306
+ this.savepoints = [];
21307
+ this.state.inTransaction = false;
21308
+ this.state.transactionXid = null;
21309
+ this.freezeDepth = 0;
21310
+ }
21311
+ };
20962
21312
 
20963
21313
  // src/executor/dml.ts
20964
21314
  function withStatementRollback(env, fn) {
@@ -21159,6 +21509,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
21159
21509
  const updated = existing.slice();
21160
21510
  applyUpdateSets(env, table, sets, scope, updated);
21161
21511
  computeGeneratedColumns(env, table, updated);
21512
+ table.rowXmins.set(updated, env.ctx.rowVersionXid());
21162
21513
  rows[existingIdx] = updated;
21163
21514
  indexUpdateRow(env, table, existingIdx, existing, updated);
21164
21515
  checkNotNull(env, table, updated);
@@ -21244,6 +21595,7 @@ function executeInsert(env0, stmt) {
21244
21595
  checkChecks(env, table, newRow);
21245
21596
  checkUnique(env, table, newRow, rows.length);
21246
21597
  checkForeignKeys(env, table, newRow);
21598
+ table.rowXmins.set(newRow, env.ctx.rowVersionXid());
21247
21599
  rows.push(newRow);
21248
21600
  indexInsertRow(env, table, rows.length - 1, newRow);
21249
21601
  insertedCount++;
@@ -21361,6 +21713,7 @@ function executeUpdate(env0, stmt) {
21361
21713
  if (fired.row === null) continue;
21362
21714
  const finalRow = fired.row;
21363
21715
  computeGeneratedColumns(env, table, finalRow);
21716
+ table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
21364
21717
  rows[ri] = finalRow;
21365
21718
  try {
21366
21719
  checkNotNull(env, table, finalRow);
@@ -21480,6 +21833,7 @@ function handleReferencedDelete(env, table, row, depth) {
21480
21833
  for (const c of con.columns) {
21481
21834
  newRow[child.columnIndex(c)] = null;
21482
21835
  }
21836
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
21483
21837
  childRows[i] = newRow;
21484
21838
  checkNotNull(env, child, newRow);
21485
21839
  checkChecks(env, child, newRow);
@@ -21493,6 +21847,7 @@ function handleReferencedDelete(env, table, row, depth) {
21493
21847
  const ci = child.columnIndex(c);
21494
21848
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
21495
21849
  }
21850
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
21496
21851
  childRows[i] = newRow;
21497
21852
  checkNotNull(env, child, newRow);
21498
21853
  checkChecks(env, child, newRow);
@@ -21530,6 +21885,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
21530
21885
  const refIdx = table.columnIndex(con.refColumns[c]);
21531
21886
  newRow[localIdx] = newRows[r][refIdx] ?? null;
21532
21887
  }
21888
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
21533
21889
  childRows[i] = newRow;
21534
21890
  checkChecks(env, child, newRow);
21535
21891
  }
@@ -21539,6 +21895,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
21539
21895
  for (const i of idxs) {
21540
21896
  const newRow = childRows[i].slice();
21541
21897
  for (const c of con.columns) newRow[child.columnIndex(c)] = null;
21898
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
21542
21899
  childRows[i] = newRow;
21543
21900
  checkNotNull(env, child, newRow);
21544
21901
  }
@@ -21551,6 +21908,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
21551
21908
  const ci = child.columnIndex(c);
21552
21909
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
21553
21910
  }
21911
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
21554
21912
  childRows[i] = newRow;
21555
21913
  checkForeignKeys(env, child, newRow);
21556
21914
  }
@@ -21648,6 +22006,7 @@ function executeSet(env, stmt) {
21648
22006
  else target.delete(name);
21649
22007
  return commandResult("SET", 0);
21650
22008
  }
22009
+ validateStorageSetting(name, stmt.value);
21651
22010
  target.set(name, stmt.value);
21652
22011
  return commandResult("SET", 0);
21653
22012
  }
@@ -21953,64 +22312,6 @@ function executeCopyFromData(env, stmt, data) {
21953
22312
  };
21954
22313
  }
21955
22314
 
21956
- // src/expressions/context.ts
21957
- var EngineCtx = class {
21958
- state;
21959
- /** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
21960
- txNow;
21961
- /** statement timestamp */
21962
- stmtNow;
21963
- constructor(state, txNow) {
21964
- this.state = state;
21965
- const nowMs = state.clock().getTime();
21966
- const nowMicros = BigInt(Math.round(nowMs)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG;
21967
- this.txNow = txNow ?? nowMicros;
21968
- this.stmtNow = nowMicros;
21969
- }
21970
- timezone() {
21971
- return this.state.getSetting("timezone") ?? "UTC";
21972
- }
21973
- namespaceOid(name) {
21974
- const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
21975
- if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
21976
- return oid;
21977
- }
21978
- namespaceName(oid) {
21979
- const builtin = builtinNamespaceName(oid);
21980
- if (builtin !== void 0) return builtin;
21981
- for (const schema of this.state.schemas.values()) {
21982
- if (schema.oid === oid) return schema.name;
21983
- }
21984
- return null;
21985
- }
21986
- zoneOffsetAt(utcMicros) {
21987
- return zoneOffsetAtUtc(this.timezone(), utcMicros);
21988
- }
21989
- zoneOffsetForNaive(naiveMicros) {
21990
- return zoneOffsetForNaive(this.timezone(), naiveMicros);
21991
- }
21992
- enumLabels(enumType) {
21993
- if (!isEnumType(enumType)) return null;
21994
- const e = this.state.findEnumByKey(enumType.slice(5));
21995
- return e?.labels ?? null;
21996
- }
21997
- enumHasLabel(enumType, label) {
21998
- const labels = this.enumLabels(enumType);
21999
- return labels === null ? true : labels.includes(label);
22000
- }
22001
- enumOrder(enumType, label) {
22002
- const labels = this.enumLabels(enumType);
22003
- if (!labels) return 0;
22004
- const idx = labels.indexOf(label);
22005
- return idx === -1 ? labels.length : idx;
22006
- }
22007
- requireEnum(enumType) {
22008
- const labels = this.enumLabels(enumType);
22009
- if (!labels) throw pgError("undefined_object", `type "${enumType.slice(5)}" does not exist`);
22010
- return labels;
22011
- }
22012
- };
22013
-
22014
22315
  // src/runtime/clock.ts
22015
22316
  var DEFAULT_NOW = /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z");
22016
22317
  function fixedClock(instant = DEFAULT_NOW) {
@@ -22978,7 +23279,7 @@ function pgClass(ctx) {
22978
23279
  v.materialized ? "m" : "v",
22979
23280
  v.columns?.length ?? 0,
22980
23281
  v.matRows?.length ?? 0,
22981
- false,
23282
+ v.materialized && [...schemaData.indexes.values()].some((i) => i.tableOid === v.oid),
22982
23283
  !v.materialized || v.matRows !== null,
22983
23284
  relPersistence(v)
22984
23285
  );
@@ -23244,7 +23545,7 @@ function pgIndex(ctx) {
23244
23545
  const valid = i.valid !== false;
23245
23546
  rows.push([
23246
23547
  i.oid ?? 0,
23247
- table?.oid ?? 0,
23548
+ table?.oid ?? i.tableOid ?? 0,
23248
23549
  indexAttributeCount(i),
23249
23550
  i.columns.length,
23250
23551
  i.unique,
@@ -23416,7 +23717,7 @@ function pgStatUserIndexes(ctx) {
23416
23717
  for (const index of schema.indexes.values()) {
23417
23718
  const table = schema.tables.get(index.table);
23418
23719
  rows.push([
23419
- table?.oid ?? 0,
23720
+ table?.oid ?? index.tableOid ?? 0,
23420
23721
  index.oid ?? 0,
23421
23722
  schema.name,
23422
23723
  index.table,
@@ -24011,26 +24312,6 @@ function runTriggerBody(env, table, stmts, vars) {
24011
24312
  }
24012
24313
  }
24013
24314
  }
24014
- function triggerScope(table, newRow, oldRow) {
24015
- const cols = [];
24016
- const row = [];
24017
- const rangeVars = /* @__PURE__ */ new Set();
24018
- if (newRow) {
24019
- rangeVars.add("new");
24020
- for (let i = 0; i < table.columns.length; i++) {
24021
- cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "new" });
24022
- row.push(newRow[i] ?? null);
24023
- }
24024
- }
24025
- if (oldRow) {
24026
- rangeVars.add("old");
24027
- for (let i = 0; i < table.columns.length; i++) {
24028
- cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "old" });
24029
- row.push(oldRow[i] ?? null);
24030
- }
24031
- }
24032
- return new RowScope(cols, row, null, rangeVars);
24033
- }
24034
24315
  function executeTrigger(env, table, trigger, _event, oldRow, newRow) {
24035
24316
  const state = env.ctx.state;
24036
24317
  if (trigger.when !== null && !evalPredicate(env, triggerScope(table, newRow, oldRow), trigger.when)) {
@@ -24675,13 +24956,63 @@ function executeCreateSequence(env, stmt) {
24675
24956
  schema.sequences.set(name, seq);
24676
24957
  return commandResult("CREATE SEQUENCE", 0);
24677
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
+ }
24678
24998
  function executeAlterSequence(env, stmt) {
24679
24999
  const state = env.ctx.state;
24680
- const seq = state.findSequence(stmt.name);
24681
- if (!seq) {
25000
+ const foundSequence = state.findSequence(stmt.name);
25001
+ if (!foundSequence) {
24682
25002
  if (stmt.ifExists) return commandResult("ALTER SEQUENCE", 0);
24683
25003
  throw pgError("undefined_table", `relation "${stmt.name.join(".")}" does not exist`, "42P01");
24684
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
+ }
24685
25016
  const o = stmt.options;
24686
25017
  if (o.logged !== void 0) {
24687
25018
  setSequenceLogged(state, seq, o.logged);
@@ -24739,7 +25070,7 @@ function buildColumn(env, schema, tableName2, def, out, taken) {
24739
25070
  col.defaultExpr = {
24740
25071
  type: "func",
24741
25072
  name: ["nextval"],
24742
- args: [{ type: "string_lit", value: `${schema.name}.${seqName}` }]
25073
+ args: [{ type: "string_lit", value: [schema.name, seqName].map(quoteIdent).join(".") }]
24743
25074
  };
24744
25075
  }
24745
25076
  for (const c of def.constraints) {
@@ -24992,7 +25323,11 @@ function executeCreateTableAs(env, stmt) {
24992
25323
  const table = new TableData(schema.name, name, columns, state.nextOid(), stmt.temp);
24993
25324
  table.unlogged = stmt.unlogged === true;
24994
25325
  if (stmt.withData) {
24995
- 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
+ }
24996
25331
  }
24997
25332
  schema.tables.set(name, table);
24998
25333
  const count = stmt.withData ? table.rowCount() : 0;
@@ -25000,7 +25335,8 @@ function executeCreateTableAs(env, stmt) {
25000
25335
  }
25001
25336
  function executeCreateIndex(env, stmt) {
25002
25337
  const state = env.ctx.state;
25003
- const table = state.findTable(stmt.table);
25338
+ const view = state.findView(stmt.table);
25339
+ const table = state.findTable(stmt.table) ?? (view?.materialized ? materializedTable(view) : void 0);
25004
25340
  if (!table) {
25005
25341
  throw pgError("undefined_table", `relation "${stmt.table.join(".")}" does not exist`, "42P01");
25006
25342
  }
@@ -25112,13 +25448,22 @@ function executeRefreshMatView(env, stmt) {
25112
25448
  if (!found?.materialized) {
25113
25449
  throw pgError("undefined_table", `materialized view "${stmt.name.join(".")}" does not exist`, "42P01");
25114
25450
  }
25451
+ const rel3 = executeSelectStmt(matviewQueryEnv(env, !stmt.withData), found.query);
25452
+ const next = {
25453
+ ...found,
25454
+ matColumns: rel3.columns.map((c, i) => ({
25455
+ name: found.columns?.[i] ?? c.name,
25456
+ type: c.type === UNKNOWN ? "text" : c.type
25457
+ })),
25458
+ matRows: stmt.withData ? rel3.rows : null
25459
+ };
25460
+ const table = materializedTable(next);
25461
+ for (const index of env.ctx.state.getSchema(found.schema).indexes.values()) {
25462
+ if (index.tableOid === found.oid && index.valid !== false) assertUniqueIndexBuildable(env, table, index);
25463
+ }
25115
25464
  const view = env.ctx.state.ensureWritableView(found);
25116
- const rel3 = executeSelectStmt(matviewQueryEnv(env, !stmt.withData), view.query);
25117
- view.matColumns = rel3.columns.map((c, i) => ({
25118
- name: view.columns?.[i] ?? c.name,
25119
- type: c.type === UNKNOWN ? "text" : c.type
25120
- }));
25121
- view.matRows = stmt.withData ? rel3.rows : null;
25465
+ view.matColumns = next.matColumns;
25466
+ view.matRows = next.matRows;
25122
25467
  return commandResult("REFRESH MATERIALIZED VIEW", 0);
25123
25468
  }
25124
25469
  function executeCreateSchema(env, stmt) {
@@ -25251,6 +25596,12 @@ function executeCreateFunction(env, stmt) {
25251
25596
  language: lang,
25252
25597
  body,
25253
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
+ ),
25254
25605
  strict: stmt.strict,
25255
25606
  oid: state.nextOid()
25256
25607
  };
@@ -25260,6 +25611,8 @@ function executeCreateFunction(env, stmt) {
25260
25611
  return commandResult("CREATE FUNCTION", 0);
25261
25612
  }
25262
25613
  function executeCreateTrigger(env, stmt) {
25614
+ if (stmt.constraint && (stmt.timing !== "after" || !stmt.forEachRow))
25615
+ throw pgError("syntax", "constraint triggers must be AFTER ROW triggers", "42601");
25263
25616
  const state = env.ctx.state;
25264
25617
  const found = state.findTable(stmt.table);
25265
25618
  if (!found) {
@@ -25278,6 +25631,9 @@ function executeCreateTrigger(env, stmt) {
25278
25631
  }
25279
25632
  const meta = {
25280
25633
  name: stmt.name,
25634
+ constraint: stmt.constraint,
25635
+ deferrable: stmt.deferrable,
25636
+ initiallyDeferred: stmt.initiallyDeferred,
25281
25637
  timing: stmt.timing,
25282
25638
  events: stmt.events,
25283
25639
  forEachRow: stmt.forEachRow,
@@ -25430,6 +25786,7 @@ function executeAlterTable(env, stmt) {
25430
25786
  }
25431
25787
  const next = row.slice();
25432
25788
  next[idx] = nv;
25789
+ table.rowXmins.set(next, table.rowXmins.get(rows[i]) ?? 2);
25433
25790
  rows[i] = next;
25434
25791
  }
25435
25792
  col.type = resolved.column;
@@ -25531,6 +25888,11 @@ function executeAlterTable(env, stmt) {
25531
25888
  );
25532
25889
  }
25533
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
+ }
25534
25896
  for (const con of table.constraints) {
25535
25897
  if (con.kind === "primary_key" || con.kind === "unique" || con.kind === "foreign_key") {
25536
25898
  con.columns = con.columns.map((c) => c === action.from ? action.to : c);
@@ -25567,6 +25929,11 @@ function executeAlterTable(env, stmt) {
25567
25929
  throw pgError("duplicate_table", `relation "${action.to}" already exists`, "42P07");
25568
25930
  }
25569
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
+ }
25570
25937
  schema.tables.delete(table.name);
25571
25938
  table.name = action.to;
25572
25939
  schema.tables.set(action.to, table);
@@ -26046,7 +26413,16 @@ function alterTableIsSelfContained(stmt) {
26046
26413
  return stmt.actions.length === 1 && action !== void 0 && SELF_CONTAINED_ALTER_ACTIONS.has(action.kind);
26047
26414
  }
26048
26415
  function executeStatement(env, stmt) {
26049
- if (!RESHAPES_TABLES.has(stmt.type)) return dispatchStatement(env, stmt);
26416
+ if (!RESHAPES_TABLES.has(stmt.type)) {
26417
+ if ((stmt.type === "insert" || stmt.type === "update" || stmt.type === "delete") && (env.ctx.state.pendingTriggers.length > 0 || env.ctx.state.findTable(stmt.table)?.triggers.some((t) => t.constraint))) {
26418
+ return withStatementRollback(env, () => {
26419
+ const result = dispatchStatement(env, stmt);
26420
+ flushConstraintTriggers(env.ctx.state);
26421
+ return result;
26422
+ });
26423
+ }
26424
+ return dispatchStatement(env, stmt);
26425
+ }
26050
26426
  try {
26051
26427
  return dispatchStatement(env, stmt);
26052
26428
  } finally {
@@ -26105,6 +26481,9 @@ function dispatchStatement(env, stmt) {
26105
26481
  return executeRefreshMatView(env, stmt);
26106
26482
  case "transaction":
26107
26483
  return executeTransaction(env, stmt);
26484
+ case "set_constraints":
26485
+ setConstraints(env.ctx.state, stmt);
26486
+ return commandResult("SET CONSTRAINTS", 0);
26108
26487
  case "set":
26109
26488
  return executeSet(env, stmt);
26110
26489
  case "show":
@@ -27428,6 +27807,7 @@ function encodeDatabaseState(state, runtime) {
27428
27807
  writeBjv(
27429
27808
  w,
27430
27809
  {
27810
+ xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
27431
27811
  name: table.name,
27432
27812
  schema: table.schema,
27433
27813
  columns: table.columns,
@@ -27525,8 +27905,14 @@ function decodeInner(snapshot, prng, clock) {
27525
27905
  table.constraints = meta.constraints;
27526
27906
  table.triggers = meta.triggers;
27527
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
+ );
27528
27913
  if (meta.stats) state.tableStats.set(table.oid, meta.stats);
27529
27914
  const rowCount = readVarintU32(r);
27915
+ if (meta.xmins && meta.xmins.length !== rowCount) throw snapshotError();
27530
27916
  const slabColumns = [];
27531
27917
  for (let c = 0; c < meta.columns.length; c++)
27532
27918
  slabColumns.push(readPackedColumn(r, rowCount, intern, meta.columns[c].type.id));
@@ -27970,6 +28356,8 @@ function validateTableMetaBjv(value) {
27970
28356
  if (!isRecord(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
27971
28357
  if (!Array.isArray(value.columns)) throw snapshotError();
27972
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();
27973
28361
  }
27974
28362
  function validateViewMetaBjv(value) {
27975
28363
  if (!isRecord(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
@@ -28063,6 +28451,7 @@ function forceSchemaIntern(pool, state, schemas) {
28063
28451
  pool.forceId(table.name);
28064
28452
  pool.forceId(table.schema);
28065
28453
  forceBjvStrings(pool, {
28454
+ xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
28066
28455
  name: table.name,
28067
28456
  schema: table.schema,
28068
28457
  columns: table.columns,
@@ -28543,11 +28932,13 @@ var ScramServer = class {
28543
28932
  var splitStatements = (script) => {
28544
28933
  const out = [];
28545
28934
  let start2 = 0;
28935
+ let hasSql = false;
28546
28936
  let i = 0;
28547
28937
  const n = script.length;
28548
28938
  const push = (end) => {
28549
28939
  const text = script.slice(start2, end).trim();
28550
- if (text.length > 0) out.push(text);
28940
+ if (hasSql) out.push(text);
28941
+ hasSql = false;
28551
28942
  };
28552
28943
  while (i < n) {
28553
28944
  const c = script[i];
@@ -28569,9 +28960,11 @@ var splitStatements = (script) => {
28569
28960
  i += 2;
28570
28961
  } else i++;
28571
28962
  }
28963
+ if (depth > 0) hasSql = true;
28572
28964
  continue;
28573
28965
  }
28574
28966
  if (c === "'" || c === '"') {
28967
+ hasSql = true;
28575
28968
  const escaped = c === "'" && /[eE]/.test(script[i - 1] ?? "") && !/[\w$]/.test(script[i - 2] ?? "");
28576
28969
  i++;
28577
28970
  while (i < n) {
@@ -28594,6 +28987,7 @@ var splitStatements = (script) => {
28594
28987
  if (c === "$") {
28595
28988
  const m = /^\$([A-Za-z_][A-Za-z0-9_]*)?\$/.exec(script.slice(i, i + 64));
28596
28989
  if (m) {
28990
+ hasSql = true;
28597
28991
  const tag = m[0];
28598
28992
  const end = script.indexOf(tag, i + tag.length);
28599
28993
  i = end === -1 ? n : end + tag.length;
@@ -28604,6 +28998,7 @@ var splitStatements = (script) => {
28604
28998
  push(i);
28605
28999
  start2 = i + 1;
28606
29000
  }
29001
+ if (c !== ";" && !/\s/.test(c)) hasSql = true;
28607
29002
  i++;
28608
29003
  }
28609
29004
  push(n);
@@ -29036,7 +29431,16 @@ var binaryValue = (type, text) => {
29036
29431
  }
29037
29432
  };
29038
29433
  var binaryEncodable = (type) => TEXT_TYPES2.has(type) || ["bool", "int2", "int4", "oid", "int8", "float4", "float8", "bytea", "uuid"].includes(type);
29039
- var mutatesDatabase = (sql) => parse(sql).some((stmt) => !["select", "show", "explain", "transaction", "no_op"].includes(stmt.type));
29434
+ var setsSessionConfig = (node) => {
29435
+ if (Array.isArray(node)) return node.some(setsSessionConfig);
29436
+ if (typeof node !== "object" || node === null) return false;
29437
+ const call = node;
29438
+ if (call.type === "func" && call.name?.at(-1) === "set_config") return true;
29439
+ return Object.values(node).some(setsSessionConfig);
29440
+ };
29441
+ var mutatesDatabase = (sql) => parse(sql).some(
29442
+ (stmt) => !["select", "show", "explain", "transaction", "no_op"].includes(stmt.type) || stmt.type === "select" && setsSessionConfig(stmt)
29443
+ );
29040
29444
  var NEVER_WRITES = /* @__PURE__ */ new Set(["show", "set", "reset", "transaction", "no_op", "prepare", "deallocate"]);
29041
29445
  var WRITE_NODES = /* @__PURE__ */ new Set(["insert", "update", "delete"]);
29042
29446
  var containsWrite = (db, node) => {
@@ -29661,6 +30065,7 @@ var Connection = class {
29661
30065
  }
29662
30066
  return outcome;
29663
30067
  } finally {
30068
+ workspace?.transactions.rollback();
29664
30069
  workspace?.close();
29665
30070
  }
29666
30071
  }
@@ -29677,7 +30082,7 @@ var Connection = class {
29677
30082
  if (stmt?.type !== "transaction") throw pgError2("syntax", "invalid transaction command", "42601");
29678
30083
  switch (stmt.action) {
29679
30084
  case "begin":
29680
- this.transaction ??= { statements: [], savepoints: [] };
30085
+ this.transaction ??= { statements: [], savepoints: [], xid: this.database.state.allocateXid() };
29681
30086
  return command("BEGIN");
29682
30087
  case "commit": {
29683
30088
  const transaction = this.transaction;
@@ -29686,6 +30091,7 @@ var Connection = class {
29686
30091
  this.inSession(
29687
30092
  this.database,
29688
30093
  () => this.database.transaction(() => {
30094
+ this.database.state.transactionXid = transaction.xid;
29689
30095
  for (const logged of transaction.statements) this.replay(this.database, logged);
29690
30096
  })
29691
30097
  );
@@ -29735,8 +30141,10 @@ var Connection = class {
29735
30141
  });
29736
30142
  workspace.state.settings = new Map(this.settings);
29737
30143
  workspace.state.settingDefaults = this.settingDefaults;
30144
+ workspace.transactions.begin();
30145
+ workspace.state.transactionXid = this.transaction?.xid ?? null;
29738
30146
  for (const logged of this.transaction?.statements ?? []) {
29739
- workspace.transaction(() => this.replay(workspace, logged));
30147
+ this.replay(workspace, logged);
29740
30148
  }
29741
30149
  return workspace;
29742
30150
  }