@crvouga/mockingbird-service-postgres 3.6.0 → 3.8.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/unstable.js CHANGED
@@ -1,3 +1,175 @@
1
+ // src/sql/keywords.ts
2
+ var QUOTED_KEYWORDS = /* @__PURE__ */ new Set([
3
+ "all",
4
+ "analyse",
5
+ "analyze",
6
+ "and",
7
+ "any",
8
+ "array",
9
+ "as",
10
+ "asc",
11
+ "asymmetric",
12
+ "authorization",
13
+ "between",
14
+ "bigint",
15
+ "binary",
16
+ "bit",
17
+ "boolean",
18
+ "both",
19
+ "case",
20
+ "cast",
21
+ "char",
22
+ "character",
23
+ "check",
24
+ "coalesce",
25
+ "collate",
26
+ "collation",
27
+ "column",
28
+ "concurrently",
29
+ "constraint",
30
+ "create",
31
+ "cross",
32
+ "current_catalog",
33
+ "current_date",
34
+ "current_role",
35
+ "current_schema",
36
+ "current_time",
37
+ "current_timestamp",
38
+ "current_user",
39
+ "dec",
40
+ "decimal",
41
+ "default",
42
+ "deferrable",
43
+ "desc",
44
+ "distinct",
45
+ "do",
46
+ "else",
47
+ "end",
48
+ "except",
49
+ "exists",
50
+ "extract",
51
+ "false",
52
+ "fetch",
53
+ "float",
54
+ "for",
55
+ "foreign",
56
+ "freeze",
57
+ "from",
58
+ "full",
59
+ "grant",
60
+ "greatest",
61
+ "group",
62
+ "grouping",
63
+ "having",
64
+ "ilike",
65
+ "in",
66
+ "initially",
67
+ "inner",
68
+ "inout",
69
+ "int",
70
+ "integer",
71
+ "intersect",
72
+ "interval",
73
+ "into",
74
+ "is",
75
+ "isnull",
76
+ "join",
77
+ "json",
78
+ "json_array",
79
+ "json_arrayagg",
80
+ "json_exists",
81
+ "json_object",
82
+ "json_objectagg",
83
+ "json_query",
84
+ "json_scalar",
85
+ "json_serialize",
86
+ "json_table",
87
+ "json_value",
88
+ "lateral",
89
+ "leading",
90
+ "least",
91
+ "left",
92
+ "like",
93
+ "limit",
94
+ "localtime",
95
+ "localtimestamp",
96
+ "merge_action",
97
+ "national",
98
+ "natural",
99
+ "nchar",
100
+ "none",
101
+ "normalize",
102
+ "not",
103
+ "notnull",
104
+ "null",
105
+ "nullif",
106
+ "numeric",
107
+ "offset",
108
+ "on",
109
+ "only",
110
+ "or",
111
+ "order",
112
+ "out",
113
+ "outer",
114
+ "overlaps",
115
+ "overlay",
116
+ "placing",
117
+ "position",
118
+ "precision",
119
+ "primary",
120
+ "real",
121
+ "references",
122
+ "returning",
123
+ "right",
124
+ "row",
125
+ "select",
126
+ "session_user",
127
+ "setof",
128
+ "similar",
129
+ "smallint",
130
+ "some",
131
+ "substring",
132
+ "symmetric",
133
+ "system_user",
134
+ "table",
135
+ "tablesample",
136
+ "then",
137
+ "time",
138
+ "timestamp",
139
+ "to",
140
+ "trailing",
141
+ "treat",
142
+ "trim",
143
+ "true",
144
+ "union",
145
+ "unique",
146
+ "user",
147
+ "using",
148
+ "values",
149
+ "varchar",
150
+ "variadic",
151
+ "verbose",
152
+ "when",
153
+ "where",
154
+ "window",
155
+ "with",
156
+ "xmlattributes",
157
+ "xmlconcat",
158
+ "xmlelement",
159
+ "xmlexists",
160
+ "xmlforest",
161
+ "xmlnamespaces",
162
+ "xmlparse",
163
+ "xmlpi",
164
+ "xmlroot",
165
+ "xmlserialize",
166
+ "xmltable"
167
+ ]);
168
+ function quoteIdentifier(name) {
169
+ if (/^[a-z_][a-z0-9_]*$/.test(name) && !QUOTED_KEYWORDS.has(name)) return name;
170
+ return `"${name.replaceAll('"', '""')}"`;
171
+ }
172
+
1
173
  // src/errors/error.ts
2
174
  var CATEGORY_TO_SQLSTATE = {
3
175
  syntax: "42601",
@@ -509,178 +681,6 @@ function timestampAddInterval(ts, iv) {
509
681
  return result;
510
682
  }
511
683
 
512
- // src/sql/keywords.ts
513
- var QUOTED_KEYWORDS = /* @__PURE__ */ new Set([
514
- "all",
515
- "analyse",
516
- "analyze",
517
- "and",
518
- "any",
519
- "array",
520
- "as",
521
- "asc",
522
- "asymmetric",
523
- "authorization",
524
- "between",
525
- "bigint",
526
- "binary",
527
- "bit",
528
- "boolean",
529
- "both",
530
- "case",
531
- "cast",
532
- "char",
533
- "character",
534
- "check",
535
- "coalesce",
536
- "collate",
537
- "collation",
538
- "column",
539
- "concurrently",
540
- "constraint",
541
- "create",
542
- "cross",
543
- "current_catalog",
544
- "current_date",
545
- "current_role",
546
- "current_schema",
547
- "current_time",
548
- "current_timestamp",
549
- "current_user",
550
- "dec",
551
- "decimal",
552
- "default",
553
- "deferrable",
554
- "desc",
555
- "distinct",
556
- "do",
557
- "else",
558
- "end",
559
- "except",
560
- "exists",
561
- "extract",
562
- "false",
563
- "fetch",
564
- "float",
565
- "for",
566
- "foreign",
567
- "freeze",
568
- "from",
569
- "full",
570
- "grant",
571
- "greatest",
572
- "group",
573
- "grouping",
574
- "having",
575
- "ilike",
576
- "in",
577
- "initially",
578
- "inner",
579
- "inout",
580
- "int",
581
- "integer",
582
- "intersect",
583
- "interval",
584
- "into",
585
- "is",
586
- "isnull",
587
- "join",
588
- "json",
589
- "json_array",
590
- "json_arrayagg",
591
- "json_exists",
592
- "json_object",
593
- "json_objectagg",
594
- "json_query",
595
- "json_scalar",
596
- "json_serialize",
597
- "json_table",
598
- "json_value",
599
- "lateral",
600
- "leading",
601
- "least",
602
- "left",
603
- "like",
604
- "limit",
605
- "localtime",
606
- "localtimestamp",
607
- "merge_action",
608
- "national",
609
- "natural",
610
- "nchar",
611
- "none",
612
- "normalize",
613
- "not",
614
- "notnull",
615
- "null",
616
- "nullif",
617
- "numeric",
618
- "offset",
619
- "on",
620
- "only",
621
- "or",
622
- "order",
623
- "out",
624
- "outer",
625
- "overlaps",
626
- "overlay",
627
- "placing",
628
- "position",
629
- "precision",
630
- "primary",
631
- "real",
632
- "references",
633
- "returning",
634
- "right",
635
- "row",
636
- "select",
637
- "session_user",
638
- "setof",
639
- "similar",
640
- "smallint",
641
- "some",
642
- "substring",
643
- "symmetric",
644
- "system_user",
645
- "table",
646
- "tablesample",
647
- "then",
648
- "time",
649
- "timestamp",
650
- "to",
651
- "trailing",
652
- "treat",
653
- "trim",
654
- "true",
655
- "union",
656
- "unique",
657
- "user",
658
- "using",
659
- "values",
660
- "varchar",
661
- "variadic",
662
- "verbose",
663
- "when",
664
- "where",
665
- "window",
666
- "with",
667
- "xmlattributes",
668
- "xmlconcat",
669
- "xmlelement",
670
- "xmlexists",
671
- "xmlforest",
672
- "xmlnamespaces",
673
- "xmlparse",
674
- "xmlpi",
675
- "xmlroot",
676
- "xmlserialize",
677
- "xmltable"
678
- ]);
679
- function quoteIdentifier(name) {
680
- if (/^[a-z_][a-z0-9_]*$/.test(name) && !QUOTED_KEYWORDS.has(name)) return name;
681
- return `"${name.replaceAll('"', '""')}"`;
682
- }
683
-
684
684
  // src/types/regnamespace.ts
685
685
  var BUILTIN_NAMESPACES = [
686
686
  ["pg_toast", 99],
@@ -710,6 +710,12 @@ var invalidName = () => {
710
710
  throw pgError("syntax", "invalid name syntax", "42602");
711
711
  };
712
712
  function parseNamespaceInput(text) {
713
+ const parsed = parseRelationInput(text);
714
+ if ("oid" in parsed) return parsed;
715
+ if (parsed.parts.length !== 1) invalidName();
716
+ return { name: parsed.parts[0] };
717
+ }
718
+ function parseRelationInput(text) {
713
719
  if (text === "-") return { oid: 0 };
714
720
  if (/^\d+$/.test(text)) return { oid: parseOidText(text) };
715
721
  const names = [];
@@ -745,8 +751,8 @@ function parseNamespaceInput(text) {
745
751
  skipSpace();
746
752
  if (at === text.length) invalidName();
747
753
  }
748
- if (names.length !== 1) invalidName();
749
- return { name: names[0] };
754
+ if (names.length === 0 || names.length > 3) invalidName();
755
+ return { parts: names };
750
756
  }
751
757
  function namespaceText(oid, name) {
752
758
  if (oid === 0) return "-";
@@ -2664,6 +2670,7 @@ var TYPE_ALIASES = {
2664
2670
  regtype: "regtype",
2665
2671
  regproc: "regproc",
2666
2672
  regnamespace: "regnamespace",
2673
+ xid: "xid",
2667
2674
  oid: "oid",
2668
2675
  void: "void",
2669
2676
  record: "record",
@@ -2740,6 +2747,7 @@ var TYPE_OIDS = {
2740
2747
  regproc: 24,
2741
2748
  text: 25,
2742
2749
  oid: 26,
2750
+ xid: 28,
2743
2751
  json: 114,
2744
2752
  float4: 700,
2745
2753
  float8: 701,
@@ -3058,6 +3066,7 @@ function recordText(rec, ctx) {
3058
3066
  return `(${parts.join(",")})`;
3059
3067
  }
3060
3068
  function datumText(t, v, ctx) {
3069
+ if (t === "regclass") return v === 0 ? "-" : ctx.relationName?.(v) ?? String(v);
3061
3070
  if (t === "regnamespace") return namespaceText(v, ctx.namespaceName?.(v));
3062
3071
  if (v === null) throw pgError("internal", "datumText called with null");
3063
3072
  if (isArrayType(t)) return arrayText(v, ctx);
@@ -3068,6 +3077,7 @@ function datumText(t, v, ctx) {
3068
3077
  case "int2":
3069
3078
  case "int4":
3070
3079
  case "oid":
3080
+ case "xid":
3071
3081
  return String(v);
3072
3082
  case "int8":
3073
3083
  return String(v);
@@ -3132,6 +3142,12 @@ function datumText(t, v, ctx) {
3132
3142
  }
3133
3143
  var UTC_INPUT = { zoneOffsetForNaive: () => 0 };
3134
3144
  function datumFromText(t, text, ctx) {
3145
+ if (t === "regclass") {
3146
+ const parsed = parseRelationInput(text);
3147
+ if ("oid" in parsed) return parsed.oid;
3148
+ if (!ctx.relationOid) throw unsupported("regclass input without a catalog");
3149
+ return ctx.relationOid(parsed.parts);
3150
+ }
3135
3151
  if (t === "regnamespace") {
3136
3152
  const parsed = parseNamespaceInput(text);
3137
3153
  if ("oid" in parsed) return parsed.oid;
@@ -3153,6 +3169,7 @@ function datumFromText(t, text, ctx) {
3153
3169
  case "int8":
3154
3170
  return parseIntegerText(text, t);
3155
3171
  case "oid":
3172
+ case "xid":
3156
3173
  return parseOidText(text);
3157
3174
  case "float4":
3158
3175
  return Math.fround(parseFloatText(text, "float4"));
@@ -3306,6 +3323,11 @@ function parseArrayText(t, text, ctx) {
3306
3323
  // src/expressions/context.ts
3307
3324
  var EngineCtx = class {
3308
3325
  state;
3326
+ writeXid = null;
3327
+ rowVersionXid() {
3328
+ if (this.state.inTransaction) return this.state.transactionXid ??= this.state.allocateXid();
3329
+ return this.writeXid ??= this.state.allocateXid();
3330
+ }
3309
3331
  /** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
3310
3332
  txNow;
3311
3333
  /** statement timestamp */
@@ -3320,6 +3342,23 @@ var EngineCtx = class {
3320
3342
  timezone() {
3321
3343
  return this.state.getSetting("timezone") ?? "UTC";
3322
3344
  }
3345
+ relationOid(parts) {
3346
+ const target = this.state.resolveRelationSchema(parts);
3347
+ const schema = target ? this.state.schemas.get(target.schema) : void 0;
3348
+ const relation = target ? schema?.sequences.get(target.name) ?? schema?.tables.get(target.name) ?? schema?.views.get(target.name) : void 0;
3349
+ if (!relation) throw pgError("undefined_table", `relation "${parts.join(".")}" does not exist`, "42P01");
3350
+ return relation.oid;
3351
+ }
3352
+ relationName(oid) {
3353
+ for (const schema of this.state.schemas.values()) {
3354
+ for (const relation of [...schema.tables.values(), ...schema.sequences.values(), ...schema.views.values()]) {
3355
+ if (relation.oid !== oid) continue;
3356
+ const visible = this.state.resolveRelationSchema([relation.name])?.schema === schema.name;
3357
+ return (visible ? [relation.name] : [schema.name, relation.name]).map(quoteIdentifier).join(".");
3358
+ }
3359
+ }
3360
+ return null;
3361
+ }
3323
3362
  namespaceOid(name) {
3324
3363
  const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
3325
3364
  if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
@@ -3620,7 +3659,7 @@ function castTo(env, value, target, opts = {}) {
3620
3659
  return tv(target, makeArray(toElem, items, arr.dims.slice(), arr.lbs.slice()));
3621
3660
  }
3622
3661
  if (from === "oid" && target === "regnamespace") return tv(target, v);
3623
- if (from === "regnamespace" && (target === "oid" || target === "int4" || target === "int8")) {
3662
+ if ((from === "regnamespace" || from === "regclass") && (target === "oid" || target === "int4" || target === "int8")) {
3624
3663
  return tv(target, target === "int8" ? BigInt(v) : v);
3625
3664
  }
3626
3665
  if ((from === "int4" || from === "int8" || from === "int2") && (target === "oid" || target === "regnamespace")) {
@@ -4321,6 +4360,8 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
4321
4360
  case "int2":
4322
4361
  case "int4":
4323
4362
  case "oid":
4363
+ case "regclass":
4364
+ case "xid":
4324
4365
  case "regnamespace":
4325
4366
  case "date":
4326
4367
  return expectNumber(a, t) - expectNumber(b, t);
@@ -4440,6 +4481,8 @@ function datumKey(t, v) {
4440
4481
  case "int2":
4441
4482
  case "int4":
4442
4483
  case "oid":
4484
+ case "regclass":
4485
+ case "xid":
4443
4486
  case "date":
4444
4487
  return `i${v}`;
4445
4488
  case "float4":
@@ -6465,6 +6508,8 @@ var TableData = class _TableData {
6465
6508
  schema;
6466
6509
  columns;
6467
6510
  rows;
6511
+ rowXmins = /* @__PURE__ */ new WeakMap();
6512
+ slabXmins = null;
6468
6513
  /** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
6469
6514
  slab = null;
6470
6515
  constraints;
@@ -6507,6 +6552,11 @@ var TableData = class _TableData {
6507
6552
  materializeSlab() {
6508
6553
  if (!this.slab) return;
6509
6554
  this.rows = this.slab.materialize();
6555
+ if (this.slabXmins)
6556
+ this.rows.forEach((row, index) => {
6557
+ this.rowXmins.set(row, this.slabXmins[index] ?? 2);
6558
+ });
6559
+ this.slabXmins = null;
6510
6560
  this.slab = null;
6511
6561
  this.indexStores = null;
6512
6562
  }
@@ -6540,6 +6590,10 @@ var TableData = class _TableData {
6540
6590
  } else {
6541
6591
  t.rows = this.rows.map((r) => r.slice());
6542
6592
  }
6593
+ t.rows.forEach((row, index) => {
6594
+ const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.rows[index]);
6595
+ if (xmin !== void 0) t.rowXmins.set(row, xmin);
6596
+ });
6543
6597
  t.unlogged = this.unlogged;
6544
6598
  t.constraints = this.constraints.map((c) => ({ ...c }));
6545
6599
  t.triggers = this.triggers.map((tr) => ({ ...tr }));
@@ -6625,6 +6679,14 @@ var DatabaseState = class _DatabaseState {
6625
6679
  clock;
6626
6680
  changes = 0;
6627
6681
  oidCounter = 16384;
6682
+ /** Local monotonic xid allocator; 2 denotes a row from a legacy snapshot without metadata. */
6683
+ xidCounter = 3;
6684
+ transactionXid = null;
6685
+ allocateXid() {
6686
+ if (this.xidCounter > 4294967295)
6687
+ throw pgError("program_limit_exceeded", "transaction ID space exhausted; xid wraparound is not modeled", "54000");
6688
+ return this.xidCounter++;
6689
+ }
6628
6690
  inTransaction = false;
6629
6691
  /** Transaction-only events: included in rollback clones, never in exported snapshots. */
6630
6692
  pendingTriggers = [];
@@ -6838,6 +6900,8 @@ var DatabaseState = class _DatabaseState {
6838
6900
  s.sequenceCurrval = new Map(this.sequenceCurrval);
6839
6901
  s.tableStats = new Map(this.tableStats);
6840
6902
  s.oidCounter = this.oidCounter;
6903
+ s.xidCounter = this.xidCounter;
6904
+ s.transactionXid = this.transactionXid;
6841
6905
  for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
6842
6906
  return s;
6843
6907
  }
@@ -6857,6 +6921,8 @@ var DatabaseState = class _DatabaseState {
6857
6921
  s.sequenceCurrval = new Map(this.sequenceCurrval);
6858
6922
  s.tableStats = new Map(this.tableStats);
6859
6923
  s.oidCounter = this.oidCounter;
6924
+ s.xidCounter = this.xidCounter;
6925
+ s.transactionXid = this.transactionXid;
6860
6926
  for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
6861
6927
  return s;
6862
6928
  }
@@ -6932,6 +6998,8 @@ var DatabaseState = class _DatabaseState {
6932
6998
  this.sequenceCurrval = other.sequenceCurrval;
6933
6999
  this.tableStats = other.tableStats;
6934
7000
  this.oidCounter = other.oidCounter;
7001
+ this.xidCounter = Math.max(this.xidCounter, other.xidCounter);
7002
+ this.transactionXid = other.transactionXid;
6935
7003
  }
6936
7004
  /** @internal Snapshot codec access to the oid allocator. */
6937
7005
  snapshotOidCounter() {
@@ -7874,7 +7942,7 @@ function databaseCatalogContext(state) {
7874
7942
  var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
7875
7943
  function findSequenceForCall(ctx, name) {
7876
7944
  const parts = parseQualifiedName(name);
7877
- const seq = ctx.state.findSequence(parts);
7945
+ const seq = /^\d+$/.test(name) ? [...ctx.state.schemas.values()].flatMap((schema) => [...schema.sequences.values()]).find((sequence) => sequence.oid === Number(name)) : ctx.state.findSequence(parts);
7878
7946
  if (!seq) {
7879
7947
  throw pgError("undefined_table", `relation "${name}" does not exist`, "42P01");
7880
7948
  }
@@ -8098,14 +8166,16 @@ function getMiscFunctions() {
8098
8166
  "pg_get_serial_sequence",
8099
8167
  strict("text", (ctx, args) => {
8100
8168
  const tableName2 = argText(ctx, args[0]);
8101
- const column = argText(ctx, args[1]).toLowerCase();
8169
+ const column = argText(ctx, args[1]);
8102
8170
  const table = ctx.state.findTable(parseQualifiedName(tableName2));
8103
8171
  if (!table) throw pgError("undefined_table", `relation "${tableName2}" does not exist`, "42P01");
8104
8172
  const col = table.columns.find((c) => c.name === column);
8105
8173
  if (!col)
8106
8174
  throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
8107
- if (!col.identity) return tv("text", null);
8108
- return tv("text", col.identity.sequence.split(".").map(quoteIdent).join("."));
8175
+ const seq = [...ctx.state.schemas.get(table.schema)?.sequences.values() ?? []].find(
8176
+ (candidate) => candidate.ownedBy?.table === table.name && candidate.ownedBy.column === column
8177
+ );
8178
+ return tv("text", seq ? [seq.schema, seq.name].map(quoteIdent).join(".") : null);
8109
8179
  })
8110
8180
  );
8111
8181
  m.set("format_type", (ctx, args) => {
@@ -9623,7 +9693,7 @@ function evalTrgmWordSimilar(ctx, left, right) {
9623
9693
  const score = wordSimilarity(a.v, b.v);
9624
9694
  return tv("bool", score >= WORD_SIMILARITY_THRESHOLD);
9625
9695
  }
9626
- function assertGinTrgmIndex(state, table, stmt) {
9696
+ function assertGinTrgmIndex(state, table, stmt, expressionType) {
9627
9697
  const trgmCols = stmt.columns.filter((col2) => isGinTrgmOpclass(col2.opclass));
9628
9698
  if (trgmCols.length === 0) return;
9629
9699
  if (trgmCols.length !== stmt.columns.length || stmt.columns.length !== 1) {
@@ -9643,11 +9713,7 @@ function assertGinTrgmIndex(state, table, stmt) {
9643
9713
  if (stmt.unique) {
9644
9714
  throw pgError("feature_not_supported", `access method "gin" does not support unique indexes`, "0A000");
9645
9715
  }
9646
- if (col.expr.type !== "colref" || col.expr.parts.length !== 1) {
9647
- throw unsupported("expression gin_trgm_ops");
9648
- }
9649
- const index = table.columnIndex(col.expr.parts[0]);
9650
- const typeId = table.columns[index].type.id;
9716
+ const typeId = col.expr.type === "colref" && col.expr.parts.length === 1 ? table.columns[table.columnIndex(col.expr.parts[0])].type.id : expressionType(col.expr);
9651
9717
  if (!GIN_TRGM_TYPES.has(typeId)) {
9652
9718
  throw pgError(
9653
9719
  "datatype_mismatch",
@@ -13049,7 +13115,7 @@ var RowScope = class {
13049
13115
  let count2 = 0;
13050
13116
  for (let i = 0; i < this.columns.length; i++) {
13051
13117
  const c = this.columns[i];
13052
- if (c.name === name2 && !c.hidden) {
13118
+ if (c.name === name2 && (!c.hidden || c.system)) {
13053
13119
  count2++;
13054
13120
  if (count2 > 1) {
13055
13121
  throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
@@ -13087,7 +13153,7 @@ var RowScope = class {
13087
13153
  const names = [];
13088
13154
  for (let i = 0; i < this.columns.length; i++) {
13089
13155
  const c = this.columns[i];
13090
- if (c.table === rangeVar) {
13156
+ if (c.table === rangeVar && !c.system) {
13091
13157
  types.push(c.type);
13092
13158
  values.push(this.row[i] ?? null);
13093
13159
  names.push(c.name);
@@ -13285,6 +13351,17 @@ function tableScope(table, row) {
13285
13351
  const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
13286
13352
  return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
13287
13353
  }
13354
+ function expressionTypeOf(env, table, expr) {
13355
+ const scope = makeEvalScope(
13356
+ env,
13357
+ tableScope(
13358
+ table,
13359
+ table.columns.map(() => null)
13360
+ )
13361
+ );
13362
+ const v = evalExpr(env.ctx, scope, expr);
13363
+ return v.t === "unknown" ? "text" : v.t;
13364
+ }
13288
13365
  function checkNotNull(env, table, row) {
13289
13366
  void env;
13290
13367
  for (let i = 0; i < table.columns.length; i++) {
@@ -13530,7 +13607,7 @@ function tryIndexedFromItem(env, item, where) {
13530
13607
  if (!table) return null;
13531
13608
  const alias = item.alias ?? item.name[item.name.length - 1];
13532
13609
  table.materializeSlab();
13533
- return tryIndexedTableRows(env, table, alias, where);
13610
+ return tryIndexedTableRows(env, table, alias, where)?.map((row) => [...row, table.rowXmins.get(row) ?? 2]) ?? null;
13534
13611
  }
13535
13612
  function joinKeyFromRow(row, colIdxs, srcTypes, unifiedTypes, ctx) {
13536
13613
  const parts = [];
@@ -16020,6 +16097,7 @@ var Parser = class {
16020
16097
  let sqlBody = null;
16021
16098
  let volatility = null;
16022
16099
  let strict2 = false;
16100
+ const settings = {};
16023
16101
  for (; ; ) {
16024
16102
  if (this.eatKw("language")) {
16025
16103
  language = this.peek().type === "string" ? this.next().value : this.ident(true);
@@ -16077,8 +16155,23 @@ var Parser = class {
16077
16155
  continue;
16078
16156
  }
16079
16157
  if (this.eatKw("set")) {
16080
- this.ident(true);
16081
- if (this.eatOp("=") || this.eatKw("to")) this.next();
16158
+ const key = this.ident(true).toLowerCase();
16159
+ if (this.eatKw("from")) {
16160
+ this.expectKw("current");
16161
+ settings[key] = "__from_current__";
16162
+ } else {
16163
+ if (!this.eatOp("=")) this.expectKw("to");
16164
+ const values = [];
16165
+ do {
16166
+ const value = this.next();
16167
+ if (!["string", "ident", "quoted_ident", "number"].includes(value.type))
16168
+ this.errorAt(value, "expected setting value");
16169
+ values.push(
16170
+ key === "search_path" && /[^a-z0-9_]/.test(value.value) ? `"${value.value.replaceAll('"', '""')}"` : value.value
16171
+ );
16172
+ } while (this.eatPunct(","));
16173
+ settings[key] = values.join(", ");
16174
+ }
16082
16175
  continue;
16083
16176
  }
16084
16177
  if (this.eatKw("window")) throw unsupported("window functions via CREATE FUNCTION");
@@ -16158,7 +16251,8 @@ var Parser = class {
16158
16251
  body,
16159
16252
  sqlBody,
16160
16253
  volatility,
16161
- strict: strict2
16254
+ strict: strict2,
16255
+ settings
16162
16256
  };
16163
16257
  }
16164
16258
  parseCreateTrigger(orReplace, constraint) {
@@ -16190,7 +16284,6 @@ var Parser = class {
16190
16284
  } while (this.eatKw("or"));
16191
16285
  this.expectKw("on");
16192
16286
  const table = this.qualifiedName();
16193
- if (this.eatKw("referencing")) throw unsupported("trigger transition tables");
16194
16287
  let deferrable = false;
16195
16288
  let initiallyDeferred = false;
16196
16289
  if (this.eatKw("not")) this.expectKw("deferrable");
@@ -16203,6 +16296,23 @@ var Parser = class {
16203
16296
  this.errorAt(this.peek(), "only constraint triggers can be deferred");
16204
16297
  if (initiallyDeferred && !deferrable)
16205
16298
  this.errorAt(this.peek(), "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
16299
+ const transitions = [];
16300
+ if (!constraint && this.eatKw("referencing")) {
16301
+ do {
16302
+ const isNew = this.eatKw("new");
16303
+ if (!isNew) this.expectKw("old");
16304
+ if (this.eatKw("row")) {
16305
+ throw pgError(
16306
+ "feature_not_supported",
16307
+ "ROW variable naming in the REFERENCING clause is not supported",
16308
+ "0A000"
16309
+ );
16310
+ }
16311
+ this.expectKw("table");
16312
+ this.eatKw("as");
16313
+ transitions.push({ isNew, name: this.ident() });
16314
+ } while (this.atKw("new") || this.atKw("old"));
16315
+ }
16206
16316
  let forEachRow = false;
16207
16317
  if (this.eatKw("for")) {
16208
16318
  this.eatKw("each");
@@ -16240,7 +16350,8 @@ var Parser = class {
16240
16350
  forEachRow,
16241
16351
  when,
16242
16352
  funcName,
16243
- funcArgs
16353
+ funcArgs,
16354
+ ...transitions.length > 0 ? { transitions } : {}
16244
16355
  };
16245
16356
  }
16246
16357
  // --- ALTER --------------------------------------------------------------------
@@ -16267,8 +16378,8 @@ var Parser = class {
16267
16378
  type: "alter_sequence",
16268
16379
  name,
16269
16380
  ifExists,
16270
- options: { ownedBy: void 0 },
16271
- ...{ renameTo: to }
16381
+ options: {},
16382
+ renameTo: to
16272
16383
  };
16273
16384
  }
16274
16385
  if (this.atKw("set") && (this.atKw("logged", 1) || this.atKw("unlogged", 1))) {
@@ -18854,7 +18965,20 @@ function runFunctionBody(env, fn, args) {
18854
18965
  }
18855
18966
  return last;
18856
18967
  }
18968
+ function withFunctionSettings(env, fn, run) {
18969
+ const state = env.ctx.state;
18970
+ const saved = new Map(state.localSettings);
18971
+ for (const [name, value] of Object.entries(fn.settings ?? {})) state.localSettings.set(name, value);
18972
+ try {
18973
+ return run();
18974
+ } finally {
18975
+ state.localSettings = saved;
18976
+ }
18977
+ }
18857
18978
  function callSqlFunctionScalar(env, fn, args) {
18979
+ return withFunctionSettings(env, fn, () => callSqlFunctionScalarBody(env, fn, args));
18980
+ }
18981
+ function callSqlFunctionScalarBody(env, fn, args) {
18858
18982
  const retT = fn.returns ?? "text";
18859
18983
  if (fn.language === "plpgsql") {
18860
18984
  return callPlpgsqlScalar(env, fn, args);
@@ -18884,6 +19008,9 @@ function callSqlFunctionScalar(env, fn, args) {
18884
19008
  return castTo(env.ctx, tv(rawT, raw), retT, {});
18885
19009
  }
18886
19010
  function callSqlFunctionSet(env, fn, args) {
19011
+ return withFunctionSettings(env, fn, () => callSqlFunctionSetBody(env, fn, args));
19012
+ }
19013
+ function callSqlFunctionSetBody(env, fn, args) {
18887
19014
  if (fn.language === "plpgsql") {
18888
19015
  return callPlpgsqlSet(env, fn, args);
18889
19016
  }
@@ -19038,15 +19165,17 @@ function executeRecursiveCte(env, cte, query) {
19038
19165
  return rel3;
19039
19166
  }
19040
19167
  function renameWithAliases(rel3, label, colAliases, what) {
19041
- if (colAliases && colAliases.length > rel3.columns.length) {
19168
+ const visibleWidth = rel3.columns.filter((column) => !column.system).length;
19169
+ if (colAliases && colAliases.length > visibleWidth) {
19042
19170
  throw pgError(
19043
19171
  "invalid_column_reference",
19044
- `table "${what}" has ${rel3.columns.length} columns available but ${colAliases.length} columns specified`,
19172
+ `table "${what}" has ${visibleWidth} columns available but ${colAliases.length} columns specified`,
19045
19173
  "42P10"
19046
19174
  );
19047
19175
  }
19048
19176
  const columns = rel3.columns.map((c, i) => ({
19049
- name: colAliases?.[i] ?? c.name,
19177
+ ...c,
19178
+ name: c.system ? c.name : colAliases?.[i] ?? c.name,
19050
19179
  type: c.type === UNKNOWN ? "text" : c.type,
19051
19180
  table: label
19052
19181
  }));
@@ -19067,8 +19196,11 @@ function materializeItem(env, item, scope) {
19067
19196
  if (table) {
19068
19197
  table.materializeSlab();
19069
19198
  const rel3 = {
19070
- columns: table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
19071
- rows: table.rows
19199
+ columns: [
19200
+ ...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
19201
+ { name: "xmin", type: "xid", table: label, hidden: true, system: true }
19202
+ ],
19203
+ rows: table.rows.map((row) => [...row, table.rowXmins.get(row) ?? 2])
19072
19204
  };
19073
19205
  return { rel: renameWithAliases(rel3, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
19074
19206
  }
@@ -19698,7 +19830,7 @@ function resolveColIdx(columns, parts) {
19698
19830
  let found = -1;
19699
19831
  for (let i = 0; i < columns.length; i++) {
19700
19832
  const c = columns[i];
19701
- if (!c.hidden && c.name === name2) {
19833
+ if ((!c.hidden || c.system) && c.name === name2) {
19702
19834
  if (found !== -1) return null;
19703
19835
  found = i;
19704
19836
  }
@@ -20282,7 +20414,7 @@ function expandTargets(core, columns) {
20282
20414
  let any = false;
20283
20415
  for (let i = 0; i < columns.length; i++) {
20284
20416
  const c = columns[i];
20285
- if (c.table === label) {
20417
+ if (c.table === label && !c.system) {
20286
20418
  any = true;
20287
20419
  items.push({ name: c.name, kind: "col", colIdx: i, expr: null, hidden: false });
20288
20420
  }
@@ -20775,6 +20907,29 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
20775
20907
  }
20776
20908
  return { row };
20777
20909
  }
20910
+ function transitionRelation(table, name, rows) {
20911
+ return {
20912
+ columns: table.columns.map((c) => ({ name: c.name, type: c.type.id, table: name })),
20913
+ rows
20914
+ };
20915
+ }
20916
+ function fireStatementTriggers(env, table, timing, event, transitions) {
20917
+ const fired = table.triggers.filter((t) => !t.forEachRow && t.timing === timing && matches(t, event)).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
20918
+ for (const t of fired) {
20919
+ if (!executor) throw unsupported(`trigger "${t.name}" execution`);
20920
+ const ctes = /* @__PURE__ */ new Map();
20921
+ if (t.oldTable !== void 0)
20922
+ ctes.set(t.oldTable, transitionRelation(table, t.oldTable, transitions?.oldRows ?? []));
20923
+ if (t.newTable !== void 0)
20924
+ ctes.set(t.newTable, transitionRelation(table, t.newTable, transitions?.newRows ?? []));
20925
+ const changes = env.ctx.state.changes;
20926
+ try {
20927
+ executor({ ctx: env.ctx, params: null, ctes, outer: null }, table, t, event, null, null);
20928
+ } finally {
20929
+ env.ctx.state.changes = changes;
20930
+ }
20931
+ }
20932
+ }
20778
20933
  var keyOf = (schema, name) => JSON.stringify([schema, name]);
20779
20934
  function flushConstraintTriggers(state, all = false) {
20780
20935
  const env = { ctx: new EngineCtx(state), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
@@ -22317,7 +22472,7 @@ function pgTrigger(ctx) {
22317
22472
  let oid = 4e4;
22318
22473
  for (const t of allTables(ctx.state)) {
22319
22474
  for (const tr of t.triggers) {
22320
- rows.push([oid++, tr.name, t.oid, !tr.forEachRow]);
22475
+ rows.push([oid++, tr.name, t.oid, !tr.forEachRow, tr.oldTable ?? null, tr.newTable ?? null]);
22321
22476
  }
22322
22477
  }
22323
22478
  return rel2(
@@ -22325,7 +22480,9 @@ function pgTrigger(ctx) {
22325
22480
  ["oid", "oid"],
22326
22481
  ["tgname", "name"],
22327
22482
  ["tgrelid", "oid"],
22328
- ["tgisinternal", "bool"]
22483
+ ["tgisinternal", "bool"],
22484
+ ["tgoldtable", "name"],
22485
+ ["tgnewtable", "name"]
22329
22486
  ],
22330
22487
  rows,
22331
22488
  "pg_trigger"
@@ -23350,13 +23507,63 @@ function executeCreateSequence(env, stmt) {
23350
23507
  schema.sequences.set(name, seq);
23351
23508
  return commandResult("CREATE SEQUENCE", 0);
23352
23509
  }
23510
+ function renameSequenceReferences(env, seq, newName) {
23511
+ const state = env.ctx.state;
23512
+ const matches2 = (value) => {
23513
+ try {
23514
+ const input = parseRelationInput(value);
23515
+ if ("oid" in input) return input.oid === seq.oid;
23516
+ return state.findSequence(input.parts)?.oid === seq.oid;
23517
+ } catch {
23518
+ return false;
23519
+ }
23520
+ };
23521
+ const rewrite = (value) => {
23522
+ if (Array.isArray(value)) return value.map(rewrite);
23523
+ if (value === null || typeof value !== "object") return value;
23524
+ const node = value;
23525
+ const updated = Object.fromEntries(Object.entries(node).map(([key, child]) => [key, rewrite(child)]));
23526
+ const rewriteLiteral = (literal2) => {
23527
+ if (literal2 && typeof literal2 === "object" && "type" in literal2 && literal2.type === "string_lit" && "value" in literal2 && typeof literal2.value === "string" && matches2(literal2.value)) {
23528
+ return { ...literal2, value: [seq.schema, newName].map(quoteIdent).join(".") };
23529
+ }
23530
+ return literal2;
23531
+ };
23532
+ if (node.type === "func" && Array.isArray(node.name) && ["nextval", "currval", "setval"].includes(String(node.name.at(-1))) && Array.isArray(updated.args))
23533
+ updated.args[0] = rewriteLiteral(updated.args[0]);
23534
+ 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")
23535
+ updated.expr = rewriteLiteral(updated.expr);
23536
+ return updated;
23537
+ };
23538
+ for (const schema of state.schemas.values()) {
23539
+ for (const table of [...schema.tables.values()]) {
23540
+ const writable = state.ensureWritableTable(table);
23541
+ for (const column of writable.columns) {
23542
+ if (column.defaultExpr) column.defaultExpr = rewrite(column.defaultExpr);
23543
+ if (column.identity?.sequence === `${seq.schema}.${seq.name}`)
23544
+ column.identity = { ...column.identity, sequence: `${seq.schema}.${newName}` };
23545
+ }
23546
+ }
23547
+ }
23548
+ }
23353
23549
  function executeAlterSequence(env, stmt) {
23354
23550
  const state = env.ctx.state;
23355
- const seq = state.findSequence(stmt.name);
23356
- if (!seq) {
23551
+ const foundSequence = state.findSequence(stmt.name);
23552
+ if (!foundSequence) {
23357
23553
  if (stmt.ifExists) return commandResult("ALTER SEQUENCE", 0);
23358
23554
  throw pgError("undefined_table", `relation "${stmt.name.join(".")}" does not exist`, "42P01");
23359
23555
  }
23556
+ const seq = state.ensureWritableSequence(foundSequence);
23557
+ if (stmt.renameTo) {
23558
+ const schema = state.getSchema(seq.schema);
23559
+ if (schema.hasRelation(stmt.renameTo))
23560
+ throw pgError("duplicate_table", `relation "${stmt.renameTo}" already exists`, "42P07");
23561
+ renameSequenceReferences(env, seq, stmt.renameTo);
23562
+ schema.sequences.delete(seq.name);
23563
+ seq.name = stmt.renameTo;
23564
+ schema.sequences.set(seq.name, seq);
23565
+ return commandResult("ALTER SEQUENCE", 0);
23566
+ }
23360
23567
  const o = stmt.options;
23361
23568
  if (o.logged !== void 0) {
23362
23569
  setSequenceLogged(state, seq, o.logged);
@@ -23414,7 +23621,7 @@ function buildColumn(env, schema, tableName2, def, out, taken) {
23414
23621
  col.defaultExpr = {
23415
23622
  type: "func",
23416
23623
  name: ["nextval"],
23417
- args: [{ type: "string_lit", value: `${schema.name}.${seqName}` }]
23624
+ args: [{ type: "string_lit", value: [schema.name, seqName].map(quoteIdent).join(".") }]
23418
23625
  };
23419
23626
  }
23420
23627
  for (const c of def.constraints) {
@@ -23667,7 +23874,11 @@ function executeCreateTableAs(env, stmt) {
23667
23874
  const table = new TableData(schema.name, name, columns, state.nextOid(), stmt.temp);
23668
23875
  table.unlogged = stmt.unlogged === true;
23669
23876
  if (stmt.withData) {
23670
- for (const row of rel3.rows) table.mutableRows().push(row.slice());
23877
+ for (const row of rel3.rows) {
23878
+ const stored = row.slice();
23879
+ table.rowXmins.set(stored, env.ctx.rowVersionXid());
23880
+ table.mutableRows().push(stored);
23881
+ }
23671
23882
  }
23672
23883
  schema.tables.set(name, table);
23673
23884
  const count = stmt.withData ? table.rowCount() : 0;
@@ -23695,7 +23906,7 @@ function executeCreateIndex(env, stmt) {
23695
23906
  }
23696
23907
  }
23697
23908
  }
23698
- assertGinTrgmIndex(state, table, stmt);
23909
+ assertGinTrgmIndex(state, table, stmt, (expr) => expressionTypeOf(env, table, expr));
23699
23910
  const method = stmt.using ?? "btree";
23700
23911
  if (!ACCESS_METHODS.has(method) || method === "heap") {
23701
23912
  throw pgError("undefined_object", `access method "${method}" does not exist`, "42704");
@@ -23936,6 +24147,12 @@ function executeCreateFunction(env, stmt) {
23936
24147
  language: lang,
23937
24148
  body,
23938
24149
  rawBody: stmt.body,
24150
+ settings: Object.fromEntries(
24151
+ Object.entries(stmt.settings ?? {}).map(([key, value]) => [
24152
+ key,
24153
+ value === "__from_current__" ? state.getSetting(key) ?? "" : value
24154
+ ])
24155
+ ),
23939
24156
  strict: stmt.strict,
23940
24157
  oid: state.nextOid()
23941
24158
  };
@@ -23944,6 +24161,50 @@ function executeCreateFunction(env, stmt) {
23944
24161
  schema.functions.set(name, existing);
23945
24162
  return commandResult("CREATE FUNCTION", 0);
23946
24163
  }
24164
+ function validateTransitionTables(stmt) {
24165
+ const transitions = stmt.transitions ?? [];
24166
+ if (transitions.length === 0) return {};
24167
+ const invalid = (message) => pgError("invalid_table_definition", message, "42P17");
24168
+ const unsupportedClause = (message) => pgError("feature_not_supported", message, "0A000");
24169
+ if (stmt.timing !== "after") throw invalid("transition table name can only be specified for an AFTER trigger");
24170
+ if (stmt.events.some((e) => e.event === "truncate")) {
24171
+ throw unsupportedClause("TRUNCATE triggers with transition tables are not supported");
24172
+ }
24173
+ if (stmt.events.some((e) => e.columns !== null)) {
24174
+ throw unsupportedClause("transition tables cannot be specified for triggers with column lists");
24175
+ }
24176
+ if (stmt.events.length > 1) {
24177
+ throw unsupportedClause("transition tables cannot be specified for triggers with more than one event");
24178
+ }
24179
+ const event = stmt.events[0].event;
24180
+ let oldTable;
24181
+ let newTable;
24182
+ for (const transition of transitions) {
24183
+ if (transition.isNew) {
24184
+ if (event !== "insert" && event !== "update") {
24185
+ throw invalid("NEW TABLE can only be specified for an INSERT or UPDATE trigger");
24186
+ }
24187
+ if (newTable !== void 0) throw invalid("NEW TABLE cannot be specified multiple times");
24188
+ newTable = transition.name;
24189
+ } else {
24190
+ if (event !== "delete" && event !== "update") {
24191
+ throw invalid("OLD TABLE can only be specified for a DELETE or UPDATE trigger");
24192
+ }
24193
+ if (oldTable !== void 0) throw invalid("OLD TABLE cannot be specified multiple times");
24194
+ oldTable = transition.name;
24195
+ }
24196
+ }
24197
+ if (oldTable !== void 0 && oldTable === newTable) {
24198
+ throw invalid("OLD TABLE name and NEW TABLE name cannot be the same");
24199
+ }
24200
+ if (stmt.forEachRow) {
24201
+ throw pgError("unsupported", "transition tables on FOR EACH ROW triggers are not supported", "0A000");
24202
+ }
24203
+ return {
24204
+ ...oldTable !== void 0 ? { oldTable } : {},
24205
+ ...newTable !== void 0 ? { newTable } : {}
24206
+ };
24207
+ }
23947
24208
  function executeCreateTrigger(env, stmt) {
23948
24209
  if (stmt.constraint && (stmt.timing !== "after" || !stmt.forEachRow))
23949
24210
  throw pgError("syntax", "constraint triggers must be AFTER ROW triggers", "42601");
@@ -23953,6 +24214,7 @@ function executeCreateTrigger(env, stmt) {
23953
24214
  throw pgError("undefined_table", `relation "${stmt.table.join(".")}" does not exist`, "42P01");
23954
24215
  }
23955
24216
  const table = state.ensureWritableTable(found);
24217
+ const transitionTables = validateTransitionTables(stmt);
23956
24218
  const fnSchema = stmt.funcName.length >= 2 ? stmt.funcName[stmt.funcName.length - 2] : null;
23957
24219
  const fnName = stmt.funcName[stmt.funcName.length - 1];
23958
24220
  const fns = state.findFunctions(stmt.funcName);
@@ -23971,6 +24233,7 @@ function executeCreateTrigger(env, stmt) {
23971
24233
  timing: stmt.timing,
23972
24234
  events: stmt.events,
23973
24235
  forEachRow: stmt.forEachRow,
24236
+ ...transitionTables,
23974
24237
  when: stmt.when,
23975
24238
  funcSchema: fnSchema ?? fns[0].schema,
23976
24239
  funcName: fnName,
@@ -24120,6 +24383,7 @@ function executeAlterTable(env, stmt) {
24120
24383
  }
24121
24384
  const next = row.slice();
24122
24385
  next[idx] = nv;
24386
+ table.rowXmins.set(next, table.rowXmins.get(rows[i]) ?? 2);
24123
24387
  rows[i] = next;
24124
24388
  }
24125
24389
  col.type = resolved.column;
@@ -24221,6 +24485,11 @@ function executeAlterTable(env, stmt) {
24221
24485
  );
24222
24486
  }
24223
24487
  table.columns[idx].name = action.to;
24488
+ for (const seq of [...schema.sequences.values()]) {
24489
+ if (seq.ownedBy?.table === table.name && seq.ownedBy.column === action.from) {
24490
+ state.ensureWritableSequence(seq).ownedBy = { table: table.name, column: action.to };
24491
+ }
24492
+ }
24224
24493
  for (const con of table.constraints) {
24225
24494
  if (con.kind === "primary_key" || con.kind === "unique" || con.kind === "foreign_key") {
24226
24495
  con.columns = con.columns.map((c) => c === action.from ? action.to : c);
@@ -24257,6 +24526,11 @@ function executeAlterTable(env, stmt) {
24257
24526
  throw pgError("duplicate_table", `relation "${action.to}" already exists`, "42P07");
24258
24527
  }
24259
24528
  const oldName = table.name;
24529
+ for (const seq of [...schema.sequences.values()]) {
24530
+ if (seq.ownedBy?.table === oldName) {
24531
+ state.ensureWritableSequence(seq).ownedBy = { ...seq.ownedBy, table: action.to };
24532
+ }
24533
+ }
24260
24534
  schema.tables.delete(table.name);
24261
24535
  table.name = action.to;
24262
24536
  schema.tables.set(action.to, table);
@@ -24895,6 +25169,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
24895
25169
  const updated = existing.slice();
24896
25170
  applyUpdateSets(env, table, sets, scope, updated);
24897
25171
  computeGeneratedColumns(env, table, updated);
25172
+ table.rowXmins.set(updated, env.ctx.rowVersionXid());
24898
25173
  rows[existingIdx] = updated;
24899
25174
  indexUpdateRow(env, table, existingIdx, existing, updated);
24900
25175
  checkNotNull(env, table, updated);
@@ -24913,7 +25188,13 @@ function executeInsert(env0, stmt) {
24913
25188
  const sourceRows = insertSourceRows(env, stmt, colIdxs);
24914
25189
  const insertedRows = [];
24915
25190
  let insertedCount = 0;
25191
+ const addedRows = [];
25192
+ const conflictOldRows = [];
25193
+ const conflictNewRows = [];
25194
+ const updatesOnConflict = stmt.onConflict !== null && stmt.onConflict.action !== "nothing";
24916
25195
  return withStatementRollback(env, () => {
25196
+ fireStatementTriggers(env, table, "before", "insert");
25197
+ if (updatesOnConflict) fireStatementTriggers(env, table, "before", "update");
24917
25198
  for (const srcRow of sourceRows) {
24918
25199
  const row = table.columns.map(() => null);
24919
25200
  const provided = /* @__PURE__ */ new Set();
@@ -24959,6 +25240,7 @@ function executeInsert(env0, stmt) {
24959
25240
  }
24960
25241
  if (conflictIdx !== null && conflictWhereOk) {
24961
25242
  if (stmt.onConflict.action === "nothing") continue;
25243
+ const replaced = rows[conflictIdx];
24962
25244
  const did = applyOnConflictUpdate(
24963
25245
  env,
24964
25246
  table,
@@ -24971,6 +25253,8 @@ function executeInsert(env0, stmt) {
24971
25253
  if (did) {
24972
25254
  insertedCount++;
24973
25255
  insertedRows.push(rows[conflictIdx]);
25256
+ conflictOldRows.push(replaced);
25257
+ conflictNewRows.push(rows[conflictIdx]);
24974
25258
  fireRowTriggers(env, table, "after", "update", null, rows[conflictIdx]);
24975
25259
  }
24976
25260
  continue;
@@ -24980,12 +25264,18 @@ function executeInsert(env0, stmt) {
24980
25264
  checkChecks(env, table, newRow);
24981
25265
  checkUnique(env, table, newRow, rows.length);
24982
25266
  checkForeignKeys(env, table, newRow);
25267
+ table.rowXmins.set(newRow, env.ctx.rowVersionXid());
24983
25268
  rows.push(newRow);
24984
25269
  indexInsertRow(env, table, rows.length - 1, newRow);
24985
25270
  insertedCount++;
24986
25271
  insertedRows.push(newRow);
25272
+ addedRows.push(newRow);
24987
25273
  fireRowTriggers(env, table, "after", "insert", null, newRow);
24988
25274
  }
25275
+ fireStatementTriggers(env, table, "after", "insert", { oldRows: [], newRows: addedRows });
25276
+ if (updatesOnConflict) {
25277
+ fireStatementTriggers(env, table, "after", "update", { oldRows: conflictOldRows, newRows: conflictNewRows });
25278
+ }
24989
25279
  env.ctx.state.changes = insertedCount;
24990
25280
  if (stmt.returning) {
24991
25281
  const res = evalReturning(env, table, label, stmt.returning, insertedRows, "INSERT");
@@ -25066,10 +25356,12 @@ function executeUpdate(env0, stmt) {
25066
25356
  const env = applyWith(env0, stmt.with);
25067
25357
  const table = requireTargetTable(env, stmt.table, "update");
25068
25358
  const label = stmt.alias ?? table.name;
25359
+ fireStatementTriggers(env, table, "before", "update");
25069
25360
  const fromSource = stmt.from.length > 0 ? buildFrom(env, stmt.from) : null;
25070
25361
  const rows = table.mutableRows();
25071
25362
  const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
25072
25363
  const updatedRows = [];
25364
+ const replacedRows = [];
25073
25365
  let updateCount = 0;
25074
25366
  for (let ri = 0; ri < rows.length; ri++) {
25075
25367
  const oldRow = rows[ri];
@@ -25097,6 +25389,7 @@ function executeUpdate(env0, stmt) {
25097
25389
  if (fired.row === null) continue;
25098
25390
  const finalRow = fired.row;
25099
25391
  computeGeneratedColumns(env, table, finalRow);
25392
+ table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
25100
25393
  rows[ri] = finalRow;
25101
25394
  try {
25102
25395
  checkNotNull(env, table, finalRow);
@@ -25111,8 +25404,10 @@ function executeUpdate(env0, stmt) {
25111
25404
  handleReferencedUpdate(env, table, [oldRow], [finalRow]);
25112
25405
  updateCount++;
25113
25406
  updatedRows.push(finalRow);
25407
+ replacedRows.push(oldRow);
25114
25408
  fireRowTriggers(env, table, "after", "update", oldRow, finalRow);
25115
25409
  }
25410
+ fireStatementTriggers(env, table, "after", "update", { oldRows: replacedRows, newRows: updatedRows });
25116
25411
  env.ctx.state.changes = updateCount;
25117
25412
  if (stmt.returning) {
25118
25413
  const res = evalReturning(env, table, label, stmt.returning, updatedRows, "UPDATE");
@@ -25124,6 +25419,7 @@ function executeDelete(env0, stmt) {
25124
25419
  const env = applyWith(env0, stmt.with);
25125
25420
  const table = requireTargetTable(env, stmt.table, "delete from");
25126
25421
  const label = stmt.alias ?? table.name;
25422
+ fireStatementTriggers(env, table, "before", "delete");
25127
25423
  const rows = table.mutableRows();
25128
25424
  const usingSource = stmt.using.length > 0 ? buildFrom(env, stmt.using) : null;
25129
25425
  const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
@@ -25161,6 +25457,7 @@ function executeDelete(env0, stmt) {
25161
25457
  fireRowTriggers(env, table, "after", "delete", row, null);
25162
25458
  }
25163
25459
  if (deletedRows.length > 0) rebuildTableIndexes(env, table);
25460
+ fireStatementTriggers(env, table, "after", "delete", { oldRows: deletedRows, newRows: [] });
25164
25461
  env.ctx.state.changes = deletedRows.length;
25165
25462
  if (stmt.returning) {
25166
25463
  const res = evalReturning(env, table, label, stmt.returning, deletedRows, "DELETE");
@@ -25216,6 +25513,7 @@ function handleReferencedDelete(env, table, row, depth) {
25216
25513
  for (const c of con.columns) {
25217
25514
  newRow[child.columnIndex(c)] = null;
25218
25515
  }
25516
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
25219
25517
  childRows[i] = newRow;
25220
25518
  checkNotNull(env, child, newRow);
25221
25519
  checkChecks(env, child, newRow);
@@ -25229,6 +25527,7 @@ function handleReferencedDelete(env, table, row, depth) {
25229
25527
  const ci = child.columnIndex(c);
25230
25528
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
25231
25529
  }
25530
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
25232
25531
  childRows[i] = newRow;
25233
25532
  checkNotNull(env, child, newRow);
25234
25533
  checkChecks(env, child, newRow);
@@ -25266,6 +25565,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
25266
25565
  const refIdx = table.columnIndex(con.refColumns[c]);
25267
25566
  newRow[localIdx] = newRows[r][refIdx] ?? null;
25268
25567
  }
25568
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
25269
25569
  childRows[i] = newRow;
25270
25570
  checkChecks(env, child, newRow);
25271
25571
  }
@@ -25275,6 +25575,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
25275
25575
  for (const i of idxs) {
25276
25576
  const newRow = childRows[i].slice();
25277
25577
  for (const c of con.columns) newRow[child.columnIndex(c)] = null;
25578
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
25278
25579
  childRows[i] = newRow;
25279
25580
  checkNotNull(env, child, newRow);
25280
25581
  }
@@ -25287,6 +25588,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
25287
25588
  const ci = child.columnIndex(c);
25288
25589
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
25289
25590
  }
25591
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
25290
25592
  childRows[i] = newRow;
25291
25593
  checkForeignKeys(env, child, newRow);
25292
25594
  }
@@ -25477,6 +25779,7 @@ var TransactionManager = class {
25477
25779
  this.base = null;
25478
25780
  this.savepoints = [];
25479
25781
  this.state.inTransaction = false;
25782
+ this.state.transactionXid = null;
25480
25783
  this.state.localSettings.clear();
25481
25784
  this.state.pendingTriggers = [];
25482
25785
  this.state.constraintModes.clear();
@@ -25489,6 +25792,7 @@ var TransactionManager = class {
25489
25792
  this.base = null;
25490
25793
  this.savepoints = [];
25491
25794
  this.state.inTransaction = false;
25795
+ this.state.transactionXid = null;
25492
25796
  this.state.localSettings.clear();
25493
25797
  this.state.pendingTriggers = [];
25494
25798
  this.state.constraintModes.clear();
@@ -25523,6 +25827,7 @@ var TransactionManager = class {
25523
25827
  this.base = null;
25524
25828
  this.savepoints = [];
25525
25829
  this.state.inTransaction = false;
25830
+ this.state.transactionXid = null;
25526
25831
  this.freezeDepth = 0;
25527
25832
  }
25528
25833
  };