@crvouga/postgres-mem 1.1.1 → 1.1.2

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/index.js CHANGED
@@ -2319,11 +2319,12 @@ function jsonbCompare(a, b) {
2319
2319
  return assertNever(a);
2320
2320
  }
2321
2321
  }
2322
- function jsonbContains(a, b) {
2322
+ function jsonbContains(a, b, opts) {
2323
+ const allowScalarInArray = opts?.allowScalarInArray ?? true;
2323
2324
  if (a.j === "obj" && b.j === "obj") {
2324
2325
  for (const [k, bv] of b.v) {
2325
2326
  const av = a.v.get(k);
2326
- if (av === void 0 || !jsonbContains(av, bv)) return false;
2327
+ if (av === void 0 || !jsonbContains(av, bv, { allowScalarInArray: false })) return false;
2327
2328
  }
2328
2329
  return true;
2329
2330
  }
@@ -2331,7 +2332,7 @@ function jsonbContains(a, b) {
2331
2332
  for (const bv of b.v) {
2332
2333
  let found = false;
2333
2334
  for (const av of a.v) {
2334
- if (jsonbContains(av, bv)) {
2335
+ if (jsonbContains(av, bv, opts)) {
2335
2336
  found = true;
2336
2337
  break;
2337
2338
  }
@@ -2340,7 +2341,7 @@ function jsonbContains(a, b) {
2340
2341
  }
2341
2342
  return true;
2342
2343
  }
2343
- if (a.j === "arr" && b.j !== "arr" && b.j !== "obj") {
2344
+ if (allowScalarInArray && a.j === "arr" && b.j !== "arr" && b.j !== "obj") {
2344
2345
  for (const av of a.v) {
2345
2346
  if (av.j === b.j && jsonbEquals(av, b)) return true;
2346
2347
  }
@@ -3271,6 +3272,8 @@ var DatabaseState = class _DatabaseState {
3271
3272
  inTransaction = false;
3272
3273
  /** most recent sequence touched by nextval/setval, for lastval() */
3273
3274
  lastSequence = null;
3275
+ /** Session currval per sequence; absent entry means currval is undefined. */
3276
+ sequenceCurrval = /* @__PURE__ */ new Map();
3274
3277
  constructor(prng, clock) {
3275
3278
  this.prng = prng;
3276
3279
  this.clock = clock;
@@ -3459,6 +3462,7 @@ var DatabaseState = class _DatabaseState {
3459
3462
  s.changes = this.changes;
3460
3463
  s.inTransaction = this.inTransaction;
3461
3464
  s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
3465
+ s.sequenceCurrval = new Map(this.sequenceCurrval);
3462
3466
  s.oidCounter = this.oidCounter;
3463
3467
  return s;
3464
3468
  }
@@ -3473,6 +3477,7 @@ var DatabaseState = class _DatabaseState {
3473
3477
  s.changes = this.changes;
3474
3478
  s.inTransaction = this.inTransaction;
3475
3479
  s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
3480
+ s.sequenceCurrval = new Map(this.sequenceCurrval);
3476
3481
  s.oidCounter = this.oidCounter;
3477
3482
  return s;
3478
3483
  }
@@ -3543,6 +3548,7 @@ var DatabaseState = class _DatabaseState {
3543
3548
  this.prepared = other.prepared;
3544
3549
  this.changes = other.changes;
3545
3550
  this.lastSequence = other.lastSequence;
3551
+ this.sequenceCurrval = other.sequenceCurrval;
3546
3552
  this.oidCounter = other.oidCounter;
3547
3553
  }
3548
3554
  /** @internal Snapshot codec access to the oid allocator. */
@@ -4761,6 +4767,14 @@ function numericSecondsToMicros(n) {
4761
4767
 
4762
4768
  // src/types/compare.ts
4763
4769
  var DEFAULT_COMPARE_CTX = {};
4770
+ function expectNumber(a, t) {
4771
+ if (typeof a !== "number") throw pgError("internal", `invalid ${t} datum for comparison`, "XX000");
4772
+ return a;
4773
+ }
4774
+ function expectBigint(a, t) {
4775
+ if (typeof a !== "bigint") throw pgError("internal", `invalid ${t} datum for comparison`, "XX000");
4776
+ return a;
4777
+ }
4764
4778
  function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
4765
4779
  if (a === null || b === null) throw pgError("internal", "datumCompare called with null");
4766
4780
  if (isArrayType(t)) return arrayCompare(t, a, b, ctx);
@@ -4775,7 +4789,7 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
4775
4789
  case "int4":
4776
4790
  case "oid":
4777
4791
  case "date":
4778
- return a - b;
4792
+ return expectNumber(a, t) - expectNumber(b, t);
4779
4793
  case "float4":
4780
4794
  case "float8": {
4781
4795
  const fa = a;
@@ -4790,8 +4804,8 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
4790
4804
  case "timestamp":
4791
4805
  case "timestamptz":
4792
4806
  case "time": {
4793
- const ba = a;
4794
- const bb = b;
4807
+ const ba = expectBigint(a, t);
4808
+ const bb = expectBigint(b, t);
4795
4809
  return ba < bb ? -1 : ba > bb ? 1 : 0;
4796
4810
  }
4797
4811
  case "numeric":
@@ -6116,6 +6130,7 @@ function getJsonFunctions() {
6116
6130
  });
6117
6131
  m.set("json_typeof", typeofFn);
6118
6132
  m.set("jsonb_typeof", typeofFn);
6133
+ const jsonpathArg = (ctx, arg) => arg.t === "jsonpath" ? arg.v : argText(ctx, arg);
6119
6134
  m.set("jsonb_path_query_first", (ctx, args) => {
6120
6135
  if (args.length < 2) {
6121
6136
  throw pgError(
@@ -6126,11 +6141,22 @@ function getJsonFunctions() {
6126
6141
  }
6127
6142
  if (args[0].v === null || args[1].v === null) return tv("jsonb", null);
6128
6143
  const doc = jsonArg(ctx, args[0]);
6129
- const path = args[1].t === "jsonpath" ? args[1].v : argText(ctx, args[1]);
6130
- const found = jsonpathQueryFirst(doc, path);
6144
+ const found = jsonpathQueryFirst(doc, jsonpathArg(ctx, args[1]));
6131
6145
  if (found === null) return tv("jsonb", null);
6132
6146
  return outJsonb(found);
6133
6147
  });
6148
+ m.set("jsonb_path_exists", (ctx, args) => {
6149
+ if (args.length < 2) {
6150
+ throw pgError(
6151
+ "undefined_function",
6152
+ `function jsonb_path_exists(${args.map((a) => a.t).join(", ")}) does not exist`,
6153
+ "42883"
6154
+ );
6155
+ }
6156
+ if (args[0].v === null || args[1].v === null) return tv("bool", null);
6157
+ const doc = jsonArg(ctx, args[0]);
6158
+ return tv("bool", jsonpathQueryFirst(doc, jsonpathArg(ctx, args[1])) !== null);
6159
+ });
6134
6160
  m.set(
6135
6161
  "json_array_length",
6136
6162
  strict("int4", (ctx, args) => {
@@ -6951,6 +6977,18 @@ function parseQualifiedName(name) {
6951
6977
  parts.push(current);
6952
6978
  return parts.map((p) => p.trim()).filter((p) => p.length > 0);
6953
6979
  }
6980
+ function sequenceSessionKey(seq) {
6981
+ return `${seq.schema}\0${seq.name}`;
6982
+ }
6983
+ function markSessionCurrval(ctx, seq, value) {
6984
+ ctx.state.sequenceCurrval.set(sequenceSessionKey(seq), value);
6985
+ }
6986
+ function sessionCurrvalDefined(ctx, seq) {
6987
+ return ctx.state.sequenceCurrval.has(sequenceSessionKey(seq));
6988
+ }
6989
+ function readSessionCurrval(ctx, seq) {
6990
+ return ctx.state.sequenceCurrval.get(sequenceSessionKey(seq));
6991
+ }
6954
6992
  function sequenceNextval(ctx, seq) {
6955
6993
  seq = ctx.state.ensureWritableSequence(seq);
6956
6994
  let next;
@@ -6980,6 +7018,7 @@ function sequenceNextval(ctx, seq) {
6980
7018
  }
6981
7019
  seq.lastValue = next;
6982
7020
  seq.isCalled = true;
7021
+ markSessionCurrval(ctx, seq, next);
6983
7022
  ctx.state.lastSequence = { schema: seq.schema, name: seq.name };
6984
7023
  return next;
6985
7024
  }
@@ -7055,14 +7094,14 @@ function getMiscFunctions() {
7055
7094
  "currval",
7056
7095
  strict("int8", (ctx, args) => {
7057
7096
  const seq = findSequenceForCall(ctx, argText(ctx, args[0]));
7058
- if (!seq.isCalled) {
7097
+ if (!sessionCurrvalDefined(ctx, seq)) {
7059
7098
  throw pgError(
7060
7099
  "object_not_in_prerequisite_state",
7061
7100
  `currval of sequence "${seq.name}" is not yet defined in this session`,
7062
7101
  "55000"
7063
7102
  );
7064
7103
  }
7065
- return tv("int8", seq.lastValue);
7104
+ return tv("int8", readSessionCurrval(ctx, seq));
7066
7105
  })
7067
7106
  );
7068
7107
  m.set("lastval", (ctx) => {
@@ -7071,10 +7110,10 @@ function getMiscFunctions() {
7071
7110
  throw pgError("object_not_in_prerequisite_state", "lastval is not yet defined in this session", "55000");
7072
7111
  }
7073
7112
  const seq = ctx.state.findSequence([last.schema, last.name]);
7074
- if (!seq?.isCalled) {
7113
+ if (!seq || !sessionCurrvalDefined(ctx, seq)) {
7075
7114
  throw pgError("object_not_in_prerequisite_state", "lastval is not yet defined in this session", "55000");
7076
7115
  }
7077
- return tv("int8", seq.lastValue);
7116
+ return tv("int8", readSessionCurrval(ctx, seq));
7078
7117
  });
7079
7118
  m.set(
7080
7119
  "setval",
@@ -7091,6 +7130,7 @@ function getMiscFunctions() {
7091
7130
  }
7092
7131
  seq.lastValue = value;
7093
7132
  seq.isCalled = isCalled;
7133
+ if (isCalled) markSessionCurrval(ctx, seq, value);
7094
7134
  ctx.state.lastSequence = { schema: seq.schema, name: seq.name };
7095
7135
  return tv("int8", value);
7096
7136
  })
@@ -9470,16 +9510,31 @@ function evalUnary(ctx, op, operand) {
9470
9510
  switch (op) {
9471
9511
  case "-": {
9472
9512
  if (t === "unknown") throw pgError("ambiguous_function", "operator is not unique: - unknown");
9473
- if (v === null) return tv(t, null);
9474
9513
  if (t === "int2" || t === "int4") {
9514
+ if (v === null) return tv(t, null);
9475
9515
  const neg = -v;
9476
9516
  return tv(t, t === "int2" ? checkInt2(neg) : checkInt4(neg));
9477
9517
  }
9478
- if (t === "int8") return tv(t, checkInt8(-v));
9479
- if (t === "float4" || t === "float8") return tv(t, -v);
9480
- if (t === "numeric") return tv(t, numericNeg(v));
9481
- if (t === "interval") return tv(t, intervalNeg(v));
9482
- if (t === "money") return tv(t, -v);
9518
+ if (t === "int8") {
9519
+ if (v === null) return tv(t, null);
9520
+ return tv(t, checkInt8(-v));
9521
+ }
9522
+ if (t === "float4" || t === "float8") {
9523
+ if (v === null) return tv(t, null);
9524
+ return tv(t, -v);
9525
+ }
9526
+ if (t === "numeric") {
9527
+ if (v === null) return tv(t, null);
9528
+ return tv(t, numericNeg(v));
9529
+ }
9530
+ if (t === "interval") {
9531
+ if (v === null) return tv(t, null);
9532
+ return tv(t, intervalNeg(v));
9533
+ }
9534
+ if (t === "money") {
9535
+ if (v === null) return tv(t, null);
9536
+ return tv(t, -v);
9537
+ }
9483
9538
  throw pgError("undefined_function", `operator does not exist: - ${typeDisplayName(t)}`);
9484
9539
  }
9485
9540
  case "+": {
@@ -9727,21 +9782,39 @@ function boolArg(ctx, kind, v) {
9727
9782
  }
9728
9783
  return toBool(ctx, v);
9729
9784
  }
9730
- function isPureLiteral(e) {
9731
- switch (e.type) {
9732
- case "number_lit":
9733
- case "string_lit":
9734
- case "bool_lit":
9735
- case "null_lit":
9736
- return true;
9737
- case "cast":
9738
- return isPureLiteral(e.expr);
9739
- default:
9740
- return false;
9785
+ function evalAsPredicate(ctx, kind, v) {
9786
+ return boolArg(ctx, kind, v) === true;
9787
+ }
9788
+ function checkBoolExprType(ctx, scope, e, kind) {
9789
+ if (e.type === "binop" && e.op === "and") {
9790
+ boolArg(ctx, "AND", evalExpr(ctx, scope, e.left));
9791
+ boolArg(ctx, "AND", evalExpr(ctx, scope, e.right));
9792
+ return;
9793
+ }
9794
+ if (e.type === "binop" && e.op === "or") {
9795
+ boolArg(ctx, "OR", evalExpr(ctx, scope, e.left));
9796
+ boolArg(ctx, "OR", evalExpr(ctx, scope, e.right));
9797
+ return;
9798
+ }
9799
+ if (e.type === "unop" && e.op === "not") {
9800
+ boolArg(ctx, "NOT", evalExpr(ctx, scope, e.operand));
9801
+ return;
9802
+ }
9803
+ if (e.type === "cast") {
9804
+ checkBoolExprType(ctx, scope, e.expr, kind);
9805
+ return;
9806
+ }
9807
+ if (e.type === "case") {
9808
+ validateSearchedCaseTree(ctx, scope, e);
9809
+ return;
9810
+ }
9811
+ const v = evalExpr(ctx, scope, e);
9812
+ if (v.t !== "bool" && v.t !== "unknown") {
9813
+ throw pgError("datatype_mismatch", `argument of ${kind} must be type boolean, not type ${typeDisplayName(v.t)}`);
9741
9814
  }
9742
9815
  }
9743
9816
  function checkSkippedBoolArg(ctx, scope, kind, e) {
9744
- if (isPureLiteral(e)) boolArg(ctx, kind, evalExpr(ctx, scope, e));
9817
+ boolArg(ctx, kind, evalExpr(ctx, scope, e));
9745
9818
  }
9746
9819
  function evalBinaryNode(ctx, scope, op, leftE, rightE) {
9747
9820
  if (op === "and") {
@@ -9844,7 +9917,55 @@ function applyDomainChecks(ctx, domainKey, value) {
9844
9917
  }
9845
9918
  }
9846
9919
  }
9920
+ function validateSearchedCaseTree(ctx, scope, e) {
9921
+ if (e.operand !== null) return;
9922
+ for (const { when, then } of e.whens) {
9923
+ boolArg(ctx, "CASE/WHEN", evalExpr(ctx, scope, when));
9924
+ validateCaseSubExpr(ctx, scope, then);
9925
+ }
9926
+ if (e.elseExpr !== null) validateCaseSubExpr(ctx, scope, e.elseExpr);
9927
+ }
9928
+ function validateCaseSubExpr(ctx, scope, e) {
9929
+ switch (e.type) {
9930
+ case "case":
9931
+ validateSearchedCaseTree(ctx, scope, e);
9932
+ return;
9933
+ case "binop":
9934
+ if (e.op === "and") {
9935
+ boolArg(ctx, "AND", evalExpr(ctx, scope, e.left));
9936
+ boolArg(ctx, "AND", evalExpr(ctx, scope, e.right));
9937
+ } else if (e.op === "or") {
9938
+ boolArg(ctx, "OR", evalExpr(ctx, scope, e.left));
9939
+ boolArg(ctx, "OR", evalExpr(ctx, scope, e.right));
9940
+ }
9941
+ validateCaseSubExpr(ctx, scope, e.left);
9942
+ validateCaseSubExpr(ctx, scope, e.right);
9943
+ return;
9944
+ case "unop":
9945
+ if (e.op === "not") {
9946
+ boolArg(ctx, "NOT", evalExpr(ctx, scope, e.operand));
9947
+ }
9948
+ validateCaseSubExpr(ctx, scope, e.operand);
9949
+ return;
9950
+ case "cast":
9951
+ case "collate":
9952
+ validateCaseSubExpr(ctx, scope, e.expr);
9953
+ return;
9954
+ case "func":
9955
+ for (const arg of e.args) validateCaseSubExpr(ctx, scope, arg);
9956
+ return;
9957
+ case "row":
9958
+ for (const item of e.items) validateCaseSubExpr(ctx, scope, item);
9959
+ return;
9960
+ case "array_ctor":
9961
+ for (const item of e.items) validateCaseSubExpr(ctx, scope, item);
9962
+ return;
9963
+ default:
9964
+ return;
9965
+ }
9966
+ }
9847
9967
  function evalCase(ctx, scope, e) {
9968
+ validateSearchedCaseTree(ctx, scope, e);
9848
9969
  let chosen = null;
9849
9970
  if (e.operand !== null) {
9850
9971
  const operand = evalExpr(ctx, scope, e.operand);
@@ -9858,7 +9979,8 @@ function evalCase(ctx, scope, e) {
9858
9979
  }
9859
9980
  } else {
9860
9981
  for (const { when, then } of e.whens) {
9861
- if (toBool(ctx, evalExpr(ctx, scope, when)) === true) {
9982
+ const w = evalExpr(ctx, scope, when);
9983
+ if (boolArg(ctx, "CASE/WHEN", w) === true) {
9862
9984
  chosen = then;
9863
9985
  break;
9864
9986
  }
@@ -14661,7 +14783,10 @@ var Parser = class {
14661
14783
  this.pos++;
14662
14784
  const operand = this.parseUnary();
14663
14785
  if (operand.type === "number_lit") {
14664
- return t.value === "-" ? { type: "number_lit", raw: `-${operand.raw}` } : operand;
14786
+ if (t.value === "+") return operand;
14787
+ const raw = operand.raw;
14788
+ if (raw.startsWith("-")) return { type: "number_lit", raw: raw.slice(1) };
14789
+ return { type: "number_lit", raw: `-${raw}` };
14665
14790
  }
14666
14791
  return { type: "unop", op: t.value, operand };
14667
14792
  }
@@ -15441,6 +15566,9 @@ var PlParser = class {
15441
15566
  this.expectSemi();
15442
15567
  return { kind: "for", targets, query, body };
15443
15568
  }
15569
+ if (this.atKw("update") || this.atKw("insert") || this.atKw("delete")) {
15570
+ return { kind: "sql", text: this.parseSqlTextUntilSemi() };
15571
+ }
15444
15572
  const target = [];
15445
15573
  const first = this.next();
15446
15574
  if (first.type !== "ident" && first.type !== "quoted_ident") {
@@ -15458,6 +15586,22 @@ var PlParser = class {
15458
15586
  }
15459
15587
  return { kind: "assign", target, expr: this.parseExprUntilSemi() };
15460
15588
  }
15589
+ parseSqlTextUntilSemi() {
15590
+ const start = this.peek().pos;
15591
+ let depth = 0;
15592
+ for (; ; ) {
15593
+ const t = this.peek();
15594
+ if (t.type === "eof") throw unsupported("plpgsql: unterminated statement");
15595
+ if (t.type === "punct" && t.value === "(") depth++;
15596
+ if (t.type === "punct" && t.value === ")") depth--;
15597
+ if (t.type === "punct" && t.value === ";" && depth === 0) {
15598
+ const text = this.src.slice(start, t.pos).trim();
15599
+ this.pos++;
15600
+ return text;
15601
+ }
15602
+ this.pos++;
15603
+ }
15604
+ }
15461
15605
  parseExprUntilSemi() {
15462
15606
  const start = this.peek().pos;
15463
15607
  let depth = 0;
@@ -15675,6 +15819,12 @@ function runStmt(env, stmt, vars, emit, tableNames) {
15675
15819
  }
15676
15820
  return;
15677
15821
  }
15822
+ case "sql": {
15823
+ const stmts = parse(stmt.text);
15824
+ if (stmts.length !== 1) throw unsupported(`plpgsql SQL statement: ${stmt.text}`);
15825
+ runStatement(env, stmts[0]);
15826
+ return;
15827
+ }
15678
15828
  }
15679
15829
  }
15680
15830
  function bindArgs(env, fn, args) {
@@ -16253,7 +16403,14 @@ function makeEvalScope(env, scope, extras) {
16253
16403
  return { type: t === UNKNOWN ? "text" : t, values: rel2.rows.map((r) => r[0] ?? null) };
16254
16404
  },
16255
16405
  aggValue(node) {
16256
- return extras?.aggMap?.get(node);
16406
+ const map = extras?.aggMap;
16407
+ if (!map) return void 0;
16408
+ const direct = map.get(node);
16409
+ if (direct !== void 0) return direct;
16410
+ for (const [call, value] of map) {
16411
+ if (exprEq(call, node)) return value;
16412
+ }
16413
+ return void 0;
16257
16414
  },
16258
16415
  windowValue(node) {
16259
16416
  if (!node.over) return void 0;
@@ -16274,11 +16431,9 @@ function makeEvalScope(env, scope, extras) {
16274
16431
  function evalScalar(env, scope, e, extras) {
16275
16432
  return evalExpr(env.ctx, makeEvalScope(env, scope, extras), e);
16276
16433
  }
16277
- function evalPredicate(env, scope, e, extras) {
16434
+ function evalPredicate(env, scope, e, extras, kind = "WHERE") {
16278
16435
  const v = evalScalar(env, scope, e, extras);
16279
- if (v.v === null) return false;
16280
- const b = castTo(env.ctx, v, "bool", {});
16281
- return b.v === true;
16436
+ return evalAsPredicate(env.ctx, kind, v);
16282
16437
  }
16283
16438
  function resolveUserFunctionForArgs(env, name, args) {
16284
16439
  const candidates = env.ctx.state.findFunctions(name);
@@ -16904,7 +17059,7 @@ function combineJoin(env, kind, left, right, on, using, usingAlias, rangeVars, e
16904
17059
  for (let i = 0; i < left.columns.length; i++) row.push(lrow[i] ?? null);
16905
17060
  for (let i = 0; i < right.columns.length; i++) row.push(rrow[i] ?? null);
16906
17061
  const jscope = new RowScope(columns, row, env.outer, rangeVars);
16907
- return evalPredicate(env, jscope, on);
17062
+ return evalPredicate(env, jscope, on, void 0, "ON");
16908
17063
  };
16909
17064
  const useHashJoin = kind !== "cross" && hashLeftIdxs.length > 0;
16910
17065
  if (useHashJoin) {
@@ -17019,6 +17174,11 @@ function buildFrom(env, items, where = null) {
17019
17174
  }
17020
17175
  return acc;
17021
17176
  }
17177
+ function exprHasAggregateCall(e) {
17178
+ const collector = { aggs: [], windows: [], groupings: [] };
17179
+ collectCalls(e, collector);
17180
+ return collector.aggs.length > 0;
17181
+ }
17022
17182
  function collectCalls(e, out) {
17023
17183
  if (!e || typeof e !== "object") return;
17024
17184
  if (e.type === "subquery_expr") return;
@@ -17160,7 +17320,192 @@ function groupDefMatches(def, e, columns) {
17160
17320
  }
17161
17321
  return exprEq(def.expr, e);
17162
17322
  }
17163
- function computeAggregate(env, call, rows) {
17323
+ function groupingErrorForColref(parts, columns) {
17324
+ const idx = resolveColIdx(columns, parts);
17325
+ let label;
17326
+ if (idx !== null) {
17327
+ const c = columns[idx];
17328
+ label = c.table ? `${c.table}.${c.name}` : c.name;
17329
+ } else {
17330
+ label = parts.join(".");
17331
+ }
17332
+ throw pgError(
17333
+ "grouping_error",
17334
+ `column "${label}" must appear in the GROUP BY clause or be used in an aggregate function`,
17335
+ "42803"
17336
+ );
17337
+ }
17338
+ function isGroupingExpr(e, groupDefs, columns) {
17339
+ return groupDefs.some((d) => groupDefMatches(d, e, columns));
17340
+ }
17341
+ function validateGroupedExpr(e, groupDefs, columns, inAgg) {
17342
+ if (!e || typeof e !== "object") return;
17343
+ if (e.type === "subquery_expr") return;
17344
+ if (!inAgg && isGroupingExpr(e, groupDefs, columns)) return;
17345
+ switch (e.type) {
17346
+ case "null_lit":
17347
+ case "string_lit":
17348
+ case "number_lit":
17349
+ case "bool_lit":
17350
+ case "bitstring_lit":
17351
+ case "param":
17352
+ case "default_expr":
17353
+ return;
17354
+ case "colref":
17355
+ if (!inAgg) {
17356
+ if (resolveColIdx(columns, e.parts) === null) return;
17357
+ groupingErrorForColref(e.parts, columns);
17358
+ }
17359
+ return;
17360
+ case "grouping_func":
17361
+ for (const a of e.args) validateGroupedExpr(a, groupDefs, columns, inAgg);
17362
+ return;
17363
+ case "func": {
17364
+ const name = e.name[e.name.length - 1];
17365
+ if (e.over) {
17366
+ for (const a of e.args) validateGroupedExpr(a, groupDefs, columns, false);
17367
+ if (e.filter) validateGroupedExpr(e.filter, groupDefs, columns, false);
17368
+ for (const p of e.over.partitionBy ?? []) validateGroupedExpr(p, groupDefs, columns, false);
17369
+ for (const ob of e.over.orderBy ?? []) validateGroupedExpr(ob.expr, groupDefs, columns, false);
17370
+ return;
17371
+ }
17372
+ if (isAggregateName(name)) {
17373
+ for (const a of e.args) validateGroupedExpr(a, groupDefs, columns, true);
17374
+ if (e.filter) validateGroupedExpr(e.filter, groupDefs, columns, true);
17375
+ for (const ob of e.orderBy ?? []) validateGroupedExpr(ob.expr, groupDefs, columns, true);
17376
+ return;
17377
+ }
17378
+ for (const a of e.args) validateGroupedExpr(a, groupDefs, columns, inAgg);
17379
+ if (e.filter) validateGroupedExpr(e.filter, groupDefs, columns, inAgg);
17380
+ for (const ob of e.orderBy ?? []) validateGroupedExpr(ob.expr, groupDefs, columns, inAgg);
17381
+ return;
17382
+ }
17383
+ case "binop":
17384
+ validateGroupedExpr(e.left, groupDefs, columns, inAgg);
17385
+ validateGroupedExpr(e.right, groupDefs, columns, inAgg);
17386
+ return;
17387
+ case "unop":
17388
+ validateGroupedExpr(e.operand, groupDefs, columns, inAgg);
17389
+ return;
17390
+ case "cast":
17391
+ validateGroupedExpr(e.expr, groupDefs, columns, inAgg);
17392
+ return;
17393
+ case "collate":
17394
+ validateGroupedExpr(e.expr, groupDefs, columns, inAgg);
17395
+ return;
17396
+ case "case": {
17397
+ if (e.operand) validateGroupedExpr(e.operand, groupDefs, columns, inAgg);
17398
+ for (const w of e.whens) {
17399
+ validateGroupedExpr(w.when, groupDefs, columns, inAgg);
17400
+ validateGroupedExpr(w.then, groupDefs, columns, inAgg);
17401
+ }
17402
+ if (e.elseExpr) validateGroupedExpr(e.elseExpr, groupDefs, columns, inAgg);
17403
+ return;
17404
+ }
17405
+ case "in_expr":
17406
+ validateGroupedExpr(e.left, groupDefs, columns, inAgg);
17407
+ if (e.list) {
17408
+ for (const r of e.list) validateGroupedExpr(r, groupDefs, columns, inAgg);
17409
+ }
17410
+ return;
17411
+ case "between":
17412
+ validateGroupedExpr(e.left, groupDefs, columns, inAgg);
17413
+ validateGroupedExpr(e.low, groupDefs, columns, inAgg);
17414
+ validateGroupedExpr(e.high, groupDefs, columns, inAgg);
17415
+ return;
17416
+ case "is_null":
17417
+ case "bool_test":
17418
+ validateGroupedExpr(e.expr, groupDefs, columns, inAgg);
17419
+ return;
17420
+ case "is_distinct":
17421
+ validateGroupedExpr(e.left, groupDefs, columns, inAgg);
17422
+ validateGroupedExpr(e.right, groupDefs, columns, inAgg);
17423
+ return;
17424
+ case "row":
17425
+ for (const el of e.items) validateGroupedExpr(el, groupDefs, columns, inAgg);
17426
+ return;
17427
+ case "array_ctor":
17428
+ for (const el of e.items) validateGroupedExpr(el, groupDefs, columns, inAgg);
17429
+ return;
17430
+ case "array_query":
17431
+ return;
17432
+ case "subscript":
17433
+ validateGroupedExpr(e.base, groupDefs, columns, inAgg);
17434
+ for (const idx of e.indexes) {
17435
+ if (idx.lower) validateGroupedExpr(idx.lower, groupDefs, columns, inAgg);
17436
+ if (idx.upper) validateGroupedExpr(idx.upper, groupDefs, columns, inAgg);
17437
+ }
17438
+ return;
17439
+ case "field_select":
17440
+ validateGroupedExpr(e.base, groupDefs, columns, inAgg);
17441
+ return;
17442
+ case "at_time_zone":
17443
+ validateGroupedExpr(e.expr, groupDefs, columns, inAgg);
17444
+ validateGroupedExpr(e.zone, groupDefs, columns, inAgg);
17445
+ return;
17446
+ case "like":
17447
+ validateGroupedExpr(e.left, groupDefs, columns, inAgg);
17448
+ validateGroupedExpr(e.pattern, groupDefs, columns, inAgg);
17449
+ if (e.escape) validateGroupedExpr(e.escape, groupDefs, columns, inAgg);
17450
+ return;
17451
+ case "position":
17452
+ validateGroupedExpr(e.needle, groupDefs, columns, inAgg);
17453
+ validateGroupedExpr(e.haystack, groupDefs, columns, inAgg);
17454
+ return;
17455
+ case "substring_sql":
17456
+ validateGroupedExpr(e.source, groupDefs, columns, inAgg);
17457
+ if (e.from) validateGroupedExpr(e.from, groupDefs, columns, inAgg);
17458
+ if (e.forLen) validateGroupedExpr(e.forLen, groupDefs, columns, inAgg);
17459
+ if (e.similar) validateGroupedExpr(e.similar, groupDefs, columns, inAgg);
17460
+ if (e.escape) validateGroupedExpr(e.escape, groupDefs, columns, inAgg);
17461
+ return;
17462
+ case "overlay":
17463
+ validateGroupedExpr(e.source, groupDefs, columns, inAgg);
17464
+ validateGroupedExpr(e.placing, groupDefs, columns, inAgg);
17465
+ validateGroupedExpr(e.from, groupDefs, columns, inAgg);
17466
+ if (e.forLen) validateGroupedExpr(e.forLen, groupDefs, columns, inAgg);
17467
+ return;
17468
+ case "trim":
17469
+ validateGroupedExpr(e.source, groupDefs, columns, inAgg);
17470
+ if (e.chars) validateGroupedExpr(e.chars, groupDefs, columns, inAgg);
17471
+ return;
17472
+ case "extract":
17473
+ validateGroupedExpr(e.source, groupDefs, columns, inAgg);
17474
+ return;
17475
+ default:
17476
+ return;
17477
+ }
17478
+ }
17479
+ function validateGroupedTargets(targets, groupDefs, columns) {
17480
+ for (const t of targets) {
17481
+ if (t.expr.type === "star") {
17482
+ if (t.expr.table) {
17483
+ const label = t.expr.table[t.expr.table.length - 1];
17484
+ for (const c of columns) {
17485
+ if (c.table === label) {
17486
+ const parts = c.table ? [c.table, c.name] : [c.name];
17487
+ validateGroupedExpr({ type: "colref", parts }, groupDefs, columns, false);
17488
+ }
17489
+ }
17490
+ } else {
17491
+ for (const c of columns) {
17492
+ if (!c.hidden) {
17493
+ const parts = c.table ? [c.table, c.name] : [c.name];
17494
+ validateGroupedExpr({ type: "colref", parts }, groupDefs, columns, false);
17495
+ }
17496
+ }
17497
+ }
17498
+ continue;
17499
+ }
17500
+ validateGroupedExpr(t.expr, groupDefs, columns, false);
17501
+ }
17502
+ }
17503
+ function validateGroupedQuery(core, groupDefs, columns, orderBy = []) {
17504
+ validateGroupedTargets(core.targets, groupDefs, columns);
17505
+ if (core.having) validateGroupedExpr(core.having, groupDefs, columns, false);
17506
+ for (const ob of orderBy) validateGroupedExpr(ob.expr, groupDefs, columns, false);
17507
+ }
17508
+ function computeAggregate(env, call, rows, probeScope) {
17164
17509
  const ctx = env.ctx;
17165
17510
  const name = call.name[call.name.length - 1];
17166
17511
  const orderedSet = isOrderedSetAggregate(name);
@@ -17247,6 +17592,17 @@ function computeAggregate(env, call, rows) {
17247
17592
  }
17248
17593
  argTypes.push(t);
17249
17594
  }
17595
+ if (effective.length === 0 && probeScope !== null && argCount > 0) {
17596
+ const scope = makeEvalScope(env, probeScope);
17597
+ for (let i = 0; i < argCount; i++) {
17598
+ if (argTypes[i] !== UNKNOWN) continue;
17599
+ if (call.star) continue;
17600
+ const expr = orderedSet && i >= call.args.length ? orderBy[0].expr : call.args[i] ?? orderBy[0].expr;
17601
+ if (!expr) continue;
17602
+ const v = evalExpr(ctx, scope, expr);
17603
+ argTypes[i] = v.t === UNKNOWN ? "text" : v.t;
17604
+ }
17605
+ }
17250
17606
  const acc = createAggregate(ctx, name, argTypes);
17251
17607
  for (const t of effective) acc.step(t.args);
17252
17608
  return acc.result();
@@ -17551,7 +17907,16 @@ function expandTargets(core, columns) {
17551
17907
  }
17552
17908
  return items;
17553
17909
  }
17554
- function executeCore(env0, core, orderBy) {
17910
+ function checkPredicateType(env, columns, rangeVars, e, kind, extras) {
17911
+ const probe = new RowScope(
17912
+ columns,
17913
+ columns.map(() => null),
17914
+ env.outer,
17915
+ rangeVars
17916
+ );
17917
+ checkBoolExprType(env.ctx, makeEvalScope(env, probe, extras), e, kind);
17918
+ }
17919
+ function executeCore(env0, core, orderBy, opts) {
17555
17920
  const env = env0;
17556
17921
  const ctx = env.ctx;
17557
17922
  const source = buildFrom(env, core.from, core.where);
@@ -17560,6 +17925,7 @@ function executeCore(env0, core, orderBy) {
17560
17925
  const rowScope = (row) => new RowScope(srcCols, row, env.outer, rangeVars);
17561
17926
  let srcRows = source.rel.rows;
17562
17927
  if (core.where) {
17928
+ checkPredicateType(env, srcCols, rangeVars, core.where, "WHERE");
17563
17929
  if (core.from.length === 1) {
17564
17930
  const indexed = tryIndexedFromItem(env, core.from[0], core.where);
17565
17931
  if (indexed !== null) {
@@ -17649,7 +18015,7 @@ function executeCore(env0, core, orderBy) {
17649
18015
  const aggMap = /* @__PURE__ */ new Map();
17650
18016
  const groupScopes = rows.map((r) => rowScope(r));
17651
18017
  for (const agg of collector.aggs) {
17652
- aggMap.set(agg, computeAggregate(env, agg, groupScopes));
18018
+ aggMap.set(agg, computeAggregate(env, agg, groupScopes, repScope));
17653
18019
  }
17654
18020
  ctxs.push({
17655
18021
  scope: repScope,
@@ -17690,9 +18056,19 @@ function executeCore(env0, core, orderBy) {
17690
18056
  return tv("int4", mask);
17691
18057
  } : void 0
17692
18058
  });
18059
+ if (core.having) {
18060
+ if (ctxs.length > 0) {
18061
+ checkPredicateType(env, srcCols, rangeVars, core.having, "HAVING", extrasFor(ctxs[0]));
18062
+ } else if (!exprHasAggregateCall(core.having)) {
18063
+ checkPredicateType(env, srcCols, rangeVars, core.having, "HAVING");
18064
+ }
18065
+ }
18066
+ if (grouped) {
18067
+ validateGroupedQuery(core, groupDefs, srcCols, orderBy);
18068
+ }
17693
18069
  if (core.having) {
17694
18070
  const having = core.having;
17695
- ctxs = ctxs.filter((rc) => evalPredicate(env, rc.scope, having, extrasFor(rc)));
18071
+ ctxs = ctxs.filter((rc) => evalPredicate(env, rc.scope, having, extrasFor(rc), "HAVING"));
17696
18072
  }
17697
18073
  const windowMaps = /* @__PURE__ */ new Map();
17698
18074
  if (collector.windows.length > 0) {
@@ -17737,6 +18113,14 @@ function executeCore(env0, core, orderBy) {
17737
18113
  sortSpecs.push(spec);
17738
18114
  orderExprs.push({ item, spec });
17739
18115
  }
18116
+ if (core.distinct && !core.distinct.on && sortSpecs.length > 0 && !opts?.hasLimit) {
18117
+ const used = new Set(sortSpecs.map((s) => s.colIdx));
18118
+ for (let i = 0; i < visibleCount; i++) {
18119
+ if (projItems[i].hidden || used.has(i)) continue;
18120
+ sortSpecs.push({ colIdx: i, dir: "asc", nullsFirst: false });
18121
+ used.add(i);
18122
+ }
18123
+ }
17740
18124
  const distinctOnIdx = [];
17741
18125
  if (core.distinct?.on) {
17742
18126
  for (const e of core.distinct.on) {
@@ -17920,7 +18304,7 @@ function executeSelectStmt(env0, stmt) {
17920
18304
  const env = applyWith(env0, stmt.with);
17921
18305
  let rel2;
17922
18306
  if (stmt.body.type === "select_core") {
17923
- rel2 = executeCore(env, stmt.body, stmt.orderBy);
18307
+ rel2 = executeCore(env, stmt.body, stmt.orderBy, { hasLimit: stmt.limit !== null });
17924
18308
  } else {
17925
18309
  rel2 = executeBody(env, stmt.body);
17926
18310
  const specs = outputOrderSpecs(env, rel2, stmt.orderBy);
@@ -18132,6 +18516,22 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
18132
18516
  }
18133
18517
 
18134
18518
  // src/executor/dml.ts
18519
+ function withStatementRollback(env, fn) {
18520
+ if (env.ctx.state.inTransaction) return fn();
18521
+ const state = env.ctx.state;
18522
+ state.freezeShared();
18523
+ const snap = state.cloneShallow();
18524
+ const prngSnap = state.prng.getState();
18525
+ try {
18526
+ return fn();
18527
+ } catch (e) {
18528
+ state.restoreFrom(snap);
18529
+ state.prng.setState(prngSnap);
18530
+ throw e;
18531
+ } finally {
18532
+ state.thawShared();
18533
+ }
18534
+ }
18135
18535
  function requireTargetTable(env, parts, verb) {
18136
18536
  const state = env.ctx.state;
18137
18537
  const table = state.findTable(parts);
@@ -18332,84 +18732,86 @@ function executeInsert(env0, stmt) {
18332
18732
  const sourceRows = insertSourceRows(env, stmt, colIdxs);
18333
18733
  const insertedRows = [];
18334
18734
  let insertedCount = 0;
18335
- for (const srcRow of sourceRows) {
18336
- const row = table.columns.map(() => null);
18337
- const provided = /* @__PURE__ */ new Set();
18338
- for (let k = 0; k < srcRow.length; k++) {
18339
- const ci = colIdxs[k];
18340
- const col = table.columns[ci];
18341
- const cell = srcRow[k];
18342
- if (cell === DEFAULT_MARKER) {
18343
- row[ci] = columnDefault(env, table, col);
18735
+ return withStatementRollback(env, () => {
18736
+ for (const srcRow of sourceRows) {
18737
+ const row = table.columns.map(() => null);
18738
+ const provided = /* @__PURE__ */ new Set();
18739
+ for (let k = 0; k < srcRow.length; k++) {
18740
+ const ci = colIdxs[k];
18741
+ const col = table.columns[ci];
18742
+ const cell = srcRow[k];
18743
+ if (cell === DEFAULT_MARKER) {
18744
+ row[ci] = columnDefault(env, table, col);
18745
+ provided.add(ci);
18746
+ continue;
18747
+ }
18748
+ if (col.identity?.always && stmt.overriding !== "system") {
18749
+ throw pgError("generated_always", `cannot insert a non-DEFAULT value into column "${col.name}"`, "428C9");
18750
+ }
18751
+ row[ci] = coerceToColumn(env, cell, col);
18344
18752
  provided.add(ci);
18345
- continue;
18346
18753
  }
18347
- if (col.identity?.always && stmt.overriding !== "system") {
18348
- throw pgError("generated_always", `cannot insert a non-DEFAULT value into column "${col.name}"`, "428C9");
18349
- }
18350
- row[ci] = coerceToColumn(env, cell, col);
18351
- provided.add(ci);
18352
- }
18353
- for (let i = 0; i < table.columns.length; i++) {
18354
- if (provided.has(i)) continue;
18355
- const col = table.columns[i];
18356
- if (col.generated) continue;
18357
- row[i] = columnDefault(env, table, col);
18358
- }
18359
- const fired = fireRowTriggers(env, table, "before", "insert", null, row);
18360
- if (fired.row === null) continue;
18361
- const newRow = fired.row;
18362
- computeGeneratedColumns(env, table, newRow);
18363
- if (stmt.onConflict) {
18364
- const arbiters = resolveArbiters(env, table, stmt.onConflict);
18365
- let conflictIdx = null;
18366
- let conflictWhereOk = true;
18367
- for (const a of arbiters) {
18368
- if ("columns" in (stmt.onConflict.target ?? {}) && stmt.onConflict.target && "columns" in stmt.onConflict.target && stmt.onConflict.target.where) {
18369
- const scope = tableRowScope(env, table, label, newRow);
18370
- conflictWhereOk = evalPredicate(env, scope, stmt.onConflict.target.where);
18371
- }
18372
- const idx = findConflict(env, table, a.spec, newRow);
18373
- if (idx !== null) {
18374
- conflictIdx = idx;
18375
- break;
18754
+ for (let i = 0; i < table.columns.length; i++) {
18755
+ if (provided.has(i)) continue;
18756
+ const col = table.columns[i];
18757
+ if (col.generated) continue;
18758
+ row[i] = columnDefault(env, table, col);
18759
+ }
18760
+ const fired = fireRowTriggers(env, table, "before", "insert", null, row);
18761
+ if (fired.row === null) continue;
18762
+ const newRow = fired.row;
18763
+ computeGeneratedColumns(env, table, newRow);
18764
+ if (stmt.onConflict) {
18765
+ const arbiters = resolveArbiters(env, table, stmt.onConflict);
18766
+ let conflictIdx = null;
18767
+ let conflictWhereOk = true;
18768
+ for (const a of arbiters) {
18769
+ if ("columns" in (stmt.onConflict.target ?? {}) && stmt.onConflict.target && "columns" in stmt.onConflict.target && stmt.onConflict.target.where) {
18770
+ const scope = tableRowScope(env, table, label, newRow);
18771
+ conflictWhereOk = evalPredicate(env, scope, stmt.onConflict.target.where);
18772
+ }
18773
+ const idx = findConflict(env, table, a.spec, newRow);
18774
+ if (idx !== null) {
18775
+ conflictIdx = idx;
18776
+ break;
18777
+ }
18376
18778
  }
18377
- }
18378
- if (conflictIdx !== null && conflictWhereOk) {
18379
- if (stmt.onConflict.action === "nothing") continue;
18380
- const did = applyOnConflictUpdate(
18381
- env,
18382
- table,
18383
- label,
18384
- conflictIdx,
18385
- newRow,
18386
- stmt.onConflict.action.sets,
18387
- stmt.onConflict.action.where
18388
- );
18389
- if (did) {
18390
- insertedCount++;
18391
- insertedRows.push(rows[conflictIdx]);
18392
- fireRowTriggers(env, table, "after", "update", null, rows[conflictIdx]);
18779
+ if (conflictIdx !== null && conflictWhereOk) {
18780
+ if (stmt.onConflict.action === "nothing") continue;
18781
+ const did = applyOnConflictUpdate(
18782
+ env,
18783
+ table,
18784
+ label,
18785
+ conflictIdx,
18786
+ newRow,
18787
+ stmt.onConflict.action.sets,
18788
+ stmt.onConflict.action.where
18789
+ );
18790
+ if (did) {
18791
+ insertedCount++;
18792
+ insertedRows.push(rows[conflictIdx]);
18793
+ fireRowTriggers(env, table, "after", "update", null, rows[conflictIdx]);
18794
+ }
18795
+ continue;
18393
18796
  }
18394
- continue;
18395
18797
  }
18798
+ checkNotNull(env, table, newRow);
18799
+ checkChecks(env, table, newRow);
18800
+ checkUnique(env, table, newRow, rows.length);
18801
+ checkForeignKeys(env, table, newRow);
18802
+ rows.push(newRow);
18803
+ indexInsertRow(env, table, rows.length - 1, newRow);
18804
+ insertedCount++;
18805
+ insertedRows.push(newRow);
18806
+ fireRowTriggers(env, table, "after", "insert", null, newRow);
18396
18807
  }
18397
- checkNotNull(env, table, newRow);
18398
- checkChecks(env, table, newRow);
18399
- checkUnique(env, table, newRow, rows.length);
18400
- checkForeignKeys(env, table, newRow);
18401
- rows.push(newRow);
18402
- indexInsertRow(env, table, rows.length - 1, newRow);
18403
- insertedCount++;
18404
- insertedRows.push(newRow);
18405
- fireRowTriggers(env, table, "after", "insert", null, newRow);
18406
- }
18407
- env.ctx.state.changes = insertedCount;
18408
- if (stmt.returning) {
18409
- const res = evalReturning(env, table, label, stmt.returning, insertedRows, "INSERT");
18410
- return { ...res, rowCount: insertedCount };
18411
- }
18412
- return commandResult("INSERT", insertedCount);
18808
+ env.ctx.state.changes = insertedCount;
18809
+ if (stmt.returning) {
18810
+ const res = evalReturning(env, table, label, stmt.returning, insertedRows, "INSERT");
18811
+ return { ...res, rowCount: insertedCount };
18812
+ }
18813
+ return commandResult("INSERT", insertedCount);
18814
+ });
18413
18815
  }
18414
18816
  function applyUpdateSets(env, table, sets, scope, row) {
18415
18817
  for (const set of sets) {
@@ -20155,6 +20557,12 @@ function runTriggerBody(env, table, stmts, vars) {
20155
20557
  }
20156
20558
  break;
20157
20559
  }
20560
+ case "sql": {
20561
+ const stmts2 = parse(stmt.text);
20562
+ if (stmts2.length !== 1) throw unsupported(`trigger body SQL: ${stmt.text}`);
20563
+ runStatement(env, stmts2[0]);
20564
+ break;
20565
+ }
20158
20566
  default:
20159
20567
  throw unsupported(`trigger body: ${stmt.kind}`);
20160
20568
  }
@@ -22470,9 +22878,13 @@ function encodeDatabaseState(state, runtime) {
22470
22878
  }
22471
22879
  }
22472
22880
  pool.finalize();
22473
- forceSchemaIntern(pool, schemas);
22881
+ forceAllEncodeIntern(pool, state, schemas);
22474
22882
  const internId = (s) => pool.id(s);
22475
- const forceId = (s) => pool.forceId(s);
22883
+ const forceId = (s) => {
22884
+ const id = pool.id(s);
22885
+ if (id < 0) throw snapshotError();
22886
+ return id;
22887
+ };
22476
22888
  const w = new Writer(64 * 1024);
22477
22889
  w.raw(MAGIC);
22478
22890
  w.u32(VERSION);
@@ -22584,6 +22996,7 @@ function decodeInner(snapshot, prng, clock) {
22584
22996
  const tableCount = readVarintU32(r);
22585
22997
  for (let i = 0; i < tableCount; i++) {
22586
22998
  const meta = readBjv(r, intern);
22999
+ validateTableMetaBjv(meta);
22587
23000
  const table = new TableData(meta.schema, meta.name, meta.columns, meta.oid, meta.temp);
22588
23001
  table.constraints = meta.constraints;
22589
23002
  table.triggers = meta.triggers;
@@ -22596,6 +23009,7 @@ function decodeInner(snapshot, prng, clock) {
22596
23009
  const viewCount = readVarintU32(r);
22597
23010
  for (let i = 0; i < viewCount; i++) {
22598
23011
  const meta = readBjv(r, intern);
23012
+ validateViewMetaBjv(meta);
22599
23013
  let matRows = null;
22600
23014
  if (r.u8() === 1) {
22601
23015
  const matRowCount = readVarintU32(r);
@@ -22977,6 +23391,29 @@ function readSchemaCatalog(r, schema, intern, str) {
22977
23391
  schema.indexes.set(idx.name, idx);
22978
23392
  }
22979
23393
  }
23394
+ function isRecord(value) {
23395
+ return value !== null && typeof value === "object" && !Array.isArray(value);
23396
+ }
23397
+ function validateColumnType(value) {
23398
+ if (!isRecord(value) || typeof value.id !== "string") throw snapshotError();
23399
+ }
23400
+ function validateColumnMeta(value) {
23401
+ if (!isRecord(value) || typeof value.name !== "string") throw snapshotError();
23402
+ validateColumnType(value.type);
23403
+ }
23404
+ function validateTableMetaBjv(value) {
23405
+ if (!isRecord(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
23406
+ if (!Array.isArray(value.columns)) throw snapshotError();
23407
+ for (const col of value.columns) validateColumnMeta(col);
23408
+ }
23409
+ function validateViewMetaBjv(value) {
23410
+ if (!isRecord(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
23411
+ if (value.matColumns === null || value.matColumns === void 0) return;
23412
+ if (!Array.isArray(value.matColumns)) throw snapshotError();
23413
+ for (const col of value.matColumns) {
23414
+ if (!isRecord(col) || typeof col.name !== "string" || typeof col.type !== "string") throw snapshotError();
23415
+ }
23416
+ }
22980
23417
  function snapshotError() {
22981
23418
  return new PostgresError("snapshot_format", "invalid or truncated postgres-mem snapshot", "XX000");
22982
23419
  }
@@ -22993,6 +23430,67 @@ function compareNames(a, b) {
22993
23430
  function sortedValues(map) {
22994
23431
  return [...map.values()].sort((a, b) => compareNames(a.name, b.name));
22995
23432
  }
23433
+ function forceAllEncodeIntern(pool, state, schemas) {
23434
+ forceSchemaIntern(pool, schemas);
23435
+ for (const [k, v] of state.settings) {
23436
+ pool.forceId(k);
23437
+ pool.forceId(v);
23438
+ }
23439
+ if (state.lastSequence) {
23440
+ pool.forceId(state.lastSequence.schema);
23441
+ pool.forceId(state.lastSequence.name);
23442
+ }
23443
+ for (const schema of schemas) {
23444
+ pool.forceId(schema.name);
23445
+ for (const table of sortedValues(schema.tables)) {
23446
+ for (const row of table.allRows()) {
23447
+ for (const d of row) forceDatumIntern(pool, d);
23448
+ }
23449
+ }
23450
+ for (const view of sortedValues(schema.views)) {
23451
+ if (view.matRows) {
23452
+ for (const row of view.matRows) {
23453
+ for (const d of row) forceDatumIntern(pool, d);
23454
+ }
23455
+ }
23456
+ }
23457
+ }
23458
+ }
23459
+ function forceDatumIntern(pool, value) {
23460
+ if (value === null) return;
23461
+ if (typeof value === "string") {
23462
+ pool.forceId(value);
23463
+ return;
23464
+ }
23465
+ if (typeof value === "boolean" || typeof value === "number" || typeof value === "bigint") return;
23466
+ if (value instanceof Uint8Array) return;
23467
+ switch (value.kind) {
23468
+ case "numeric": {
23469
+ const min = -0x8000000000000000n;
23470
+ const max = 0x7fffffffffffffffn;
23471
+ if (value.coef < min || value.coef > max) pool.forceId(value.coef.toString());
23472
+ return;
23473
+ }
23474
+ case "pgarray": {
23475
+ pool.forceId(value.elem);
23476
+ for (const item of value.items) forceDatumIntern(pool, item);
23477
+ return;
23478
+ }
23479
+ case "pgrecord": {
23480
+ for (const t of value.types) pool.forceId(t);
23481
+ if (value.names) {
23482
+ for (const n of value.names) pool.forceId(n);
23483
+ }
23484
+ for (const item of value.values) forceDatumIntern(pool, item);
23485
+ return;
23486
+ }
23487
+ case "jsonb":
23488
+ pool.forceId(jsonbText(value.value));
23489
+ return;
23490
+ default:
23491
+ return;
23492
+ }
23493
+ }
22996
23494
  function forceSchemaIntern(pool, schemas) {
22997
23495
  for (const schema of schemas) {
22998
23496
  pool.forceId(schema.name);