@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/unstable.js CHANGED
@@ -1441,11 +1441,12 @@ function jsonbCompare(a, b) {
1441
1441
  return assertNever(a);
1442
1442
  }
1443
1443
  }
1444
- function jsonbContains(a, b) {
1444
+ function jsonbContains(a, b, opts) {
1445
+ const allowScalarInArray = opts?.allowScalarInArray ?? true;
1445
1446
  if (a.j === "obj" && b.j === "obj") {
1446
1447
  for (const [k, bv] of b.v) {
1447
1448
  const av = a.v.get(k);
1448
- if (av === void 0 || !jsonbContains(av, bv)) return false;
1449
+ if (av === void 0 || !jsonbContains(av, bv, { allowScalarInArray: false })) return false;
1449
1450
  }
1450
1451
  return true;
1451
1452
  }
@@ -1453,7 +1454,7 @@ function jsonbContains(a, b) {
1453
1454
  for (const bv of b.v) {
1454
1455
  let found = false;
1455
1456
  for (const av of a.v) {
1456
- if (jsonbContains(av, bv)) {
1457
+ if (jsonbContains(av, bv, opts)) {
1457
1458
  found = true;
1458
1459
  break;
1459
1460
  }
@@ -1462,7 +1463,7 @@ function jsonbContains(a, b) {
1462
1463
  }
1463
1464
  return true;
1464
1465
  }
1465
- if (a.j === "arr" && b.j !== "arr" && b.j !== "obj") {
1466
+ if (allowScalarInArray && a.j === "arr" && b.j !== "arr" && b.j !== "obj") {
1466
1467
  for (const av of a.v) {
1467
1468
  if (av.j === b.j && jsonbEquals(av, b)) return true;
1468
1469
  }
@@ -3413,6 +3414,14 @@ function unifyTypes(a, b) {
3413
3414
 
3414
3415
  // src/types/compare.ts
3415
3416
  var DEFAULT_COMPARE_CTX = {};
3417
+ function expectNumber(a, t) {
3418
+ if (typeof a !== "number") throw pgError("internal", `invalid ${t} datum for comparison`, "XX000");
3419
+ return a;
3420
+ }
3421
+ function expectBigint(a, t) {
3422
+ if (typeof a !== "bigint") throw pgError("internal", `invalid ${t} datum for comparison`, "XX000");
3423
+ return a;
3424
+ }
3416
3425
  function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
3417
3426
  if (a === null || b === null) throw pgError("internal", "datumCompare called with null");
3418
3427
  if (isArrayType(t)) return arrayCompare(t, a, b, ctx);
@@ -3427,7 +3436,7 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
3427
3436
  case "int4":
3428
3437
  case "oid":
3429
3438
  case "date":
3430
- return a - b;
3439
+ return expectNumber(a, t) - expectNumber(b, t);
3431
3440
  case "float4":
3432
3441
  case "float8": {
3433
3442
  const fa = a;
@@ -3442,8 +3451,8 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
3442
3451
  case "timestamp":
3443
3452
  case "timestamptz":
3444
3453
  case "time": {
3445
- const ba = a;
3446
- const bb = b;
3454
+ const ba = expectBigint(a, t);
3455
+ const bb = expectBigint(b, t);
3447
3456
  return ba < bb ? -1 : ba > bb ? 1 : 0;
3448
3457
  }
3449
3458
  case "numeric":
@@ -3758,6 +3767,7 @@ function getJsonFunctions() {
3758
3767
  });
3759
3768
  m.set("json_typeof", typeofFn);
3760
3769
  m.set("jsonb_typeof", typeofFn);
3770
+ const jsonpathArg = (ctx, arg) => arg.t === "jsonpath" ? arg.v : argText(ctx, arg);
3761
3771
  m.set("jsonb_path_query_first", (ctx, args) => {
3762
3772
  if (args.length < 2) {
3763
3773
  throw pgError(
@@ -3768,11 +3778,22 @@ function getJsonFunctions() {
3768
3778
  }
3769
3779
  if (args[0].v === null || args[1].v === null) return tv("jsonb", null);
3770
3780
  const doc = jsonArg(ctx, args[0]);
3771
- const path = args[1].t === "jsonpath" ? args[1].v : argText(ctx, args[1]);
3772
- const found = jsonpathQueryFirst(doc, path);
3781
+ const found = jsonpathQueryFirst(doc, jsonpathArg(ctx, args[1]));
3773
3782
  if (found === null) return tv("jsonb", null);
3774
3783
  return outJsonb(found);
3775
3784
  });
3785
+ m.set("jsonb_path_exists", (ctx, args) => {
3786
+ if (args.length < 2) {
3787
+ throw pgError(
3788
+ "undefined_function",
3789
+ `function jsonb_path_exists(${args.map((a) => a.t).join(", ")}) does not exist`,
3790
+ "42883"
3791
+ );
3792
+ }
3793
+ if (args[0].v === null || args[1].v === null) return tv("bool", null);
3794
+ const doc = jsonArg(ctx, args[0]);
3795
+ return tv("bool", jsonpathQueryFirst(doc, jsonpathArg(ctx, args[1])) !== null);
3796
+ });
3776
3797
  m.set(
3777
3798
  "json_array_length",
3778
3799
  strict("int4", (ctx, args) => {
@@ -6538,6 +6559,18 @@ function parseQualifiedName(name) {
6538
6559
  parts.push(current);
6539
6560
  return parts.map((p) => p.trim()).filter((p) => p.length > 0);
6540
6561
  }
6562
+ function sequenceSessionKey(seq) {
6563
+ return `${seq.schema}\0${seq.name}`;
6564
+ }
6565
+ function markSessionCurrval(ctx, seq, value) {
6566
+ ctx.state.sequenceCurrval.set(sequenceSessionKey(seq), value);
6567
+ }
6568
+ function sessionCurrvalDefined(ctx, seq) {
6569
+ return ctx.state.sequenceCurrval.has(sequenceSessionKey(seq));
6570
+ }
6571
+ function readSessionCurrval(ctx, seq) {
6572
+ return ctx.state.sequenceCurrval.get(sequenceSessionKey(seq));
6573
+ }
6541
6574
  function sequenceNextval(ctx, seq) {
6542
6575
  seq = ctx.state.ensureWritableSequence(seq);
6543
6576
  let next;
@@ -6567,6 +6600,7 @@ function sequenceNextval(ctx, seq) {
6567
6600
  }
6568
6601
  seq.lastValue = next;
6569
6602
  seq.isCalled = true;
6603
+ markSessionCurrval(ctx, seq, next);
6570
6604
  ctx.state.lastSequence = { schema: seq.schema, name: seq.name };
6571
6605
  return next;
6572
6606
  }
@@ -6642,14 +6676,14 @@ function getMiscFunctions() {
6642
6676
  "currval",
6643
6677
  strict("int8", (ctx, args) => {
6644
6678
  const seq = findSequenceForCall(ctx, argText(ctx, args[0]));
6645
- if (!seq.isCalled) {
6679
+ if (!sessionCurrvalDefined(ctx, seq)) {
6646
6680
  throw pgError(
6647
6681
  "object_not_in_prerequisite_state",
6648
6682
  `currval of sequence "${seq.name}" is not yet defined in this session`,
6649
6683
  "55000"
6650
6684
  );
6651
6685
  }
6652
- return tv("int8", seq.lastValue);
6686
+ return tv("int8", readSessionCurrval(ctx, seq));
6653
6687
  })
6654
6688
  );
6655
6689
  m.set("lastval", (ctx) => {
@@ -6658,10 +6692,10 @@ function getMiscFunctions() {
6658
6692
  throw pgError("object_not_in_prerequisite_state", "lastval is not yet defined in this session", "55000");
6659
6693
  }
6660
6694
  const seq = ctx.state.findSequence([last.schema, last.name]);
6661
- if (!seq?.isCalled) {
6695
+ if (!seq || !sessionCurrvalDefined(ctx, seq)) {
6662
6696
  throw pgError("object_not_in_prerequisite_state", "lastval is not yet defined in this session", "55000");
6663
6697
  }
6664
- return tv("int8", seq.lastValue);
6698
+ return tv("int8", readSessionCurrval(ctx, seq));
6665
6699
  });
6666
6700
  m.set(
6667
6701
  "setval",
@@ -6678,6 +6712,7 @@ function getMiscFunctions() {
6678
6712
  }
6679
6713
  seq.lastValue = value;
6680
6714
  seq.isCalled = isCalled;
6715
+ if (isCalled) markSessionCurrval(ctx, seq, value);
6681
6716
  ctx.state.lastSequence = { schema: seq.schema, name: seq.name };
6682
6717
  return tv("int8", value);
6683
6718
  })
@@ -12693,7 +12728,10 @@ var Parser = class {
12693
12728
  this.pos++;
12694
12729
  const operand = this.parseUnary();
12695
12730
  if (operand.type === "number_lit") {
12696
- return t.value === "-" ? { type: "number_lit", raw: `-${operand.raw}` } : operand;
12731
+ if (t.value === "+") return operand;
12732
+ const raw = operand.raw;
12733
+ if (raw.startsWith("-")) return { type: "number_lit", raw: raw.slice(1) };
12734
+ return { type: "number_lit", raw: `-${raw}` };
12697
12735
  }
12698
12736
  return { type: "unop", op: t.value, operand };
12699
12737
  }
@@ -14392,16 +14430,31 @@ function evalUnary(ctx, op, operand) {
14392
14430
  switch (op) {
14393
14431
  case "-": {
14394
14432
  if (t === "unknown") throw pgError("ambiguous_function", "operator is not unique: - unknown");
14395
- if (v === null) return tv(t, null);
14396
14433
  if (t === "int2" || t === "int4") {
14434
+ if (v === null) return tv(t, null);
14397
14435
  const neg = -v;
14398
14436
  return tv(t, t === "int2" ? checkInt2(neg) : checkInt4(neg));
14399
14437
  }
14400
- if (t === "int8") return tv(t, checkInt8(-v));
14401
- if (t === "float4" || t === "float8") return tv(t, -v);
14402
- if (t === "numeric") return tv(t, numericNeg(v));
14403
- if (t === "interval") return tv(t, intervalNeg(v));
14404
- if (t === "money") return tv(t, -v);
14438
+ if (t === "int8") {
14439
+ if (v === null) return tv(t, null);
14440
+ return tv(t, checkInt8(-v));
14441
+ }
14442
+ if (t === "float4" || t === "float8") {
14443
+ if (v === null) return tv(t, null);
14444
+ return tv(t, -v);
14445
+ }
14446
+ if (t === "numeric") {
14447
+ if (v === null) return tv(t, null);
14448
+ return tv(t, numericNeg(v));
14449
+ }
14450
+ if (t === "interval") {
14451
+ if (v === null) return tv(t, null);
14452
+ return tv(t, intervalNeg(v));
14453
+ }
14454
+ if (t === "money") {
14455
+ if (v === null) return tv(t, null);
14456
+ return tv(t, -v);
14457
+ }
14405
14458
  throw pgError("undefined_function", `operator does not exist: - ${typeDisplayName(t)}`);
14406
14459
  }
14407
14460
  case "+": {
@@ -14649,21 +14702,39 @@ function boolArg(ctx, kind, v) {
14649
14702
  }
14650
14703
  return toBool(ctx, v);
14651
14704
  }
14652
- function isPureLiteral(e) {
14653
- switch (e.type) {
14654
- case "number_lit":
14655
- case "string_lit":
14656
- case "bool_lit":
14657
- case "null_lit":
14658
- return true;
14659
- case "cast":
14660
- return isPureLiteral(e.expr);
14661
- default:
14662
- return false;
14705
+ function evalAsPredicate(ctx, kind, v) {
14706
+ return boolArg(ctx, kind, v) === true;
14707
+ }
14708
+ function checkBoolExprType(ctx, scope, e, kind) {
14709
+ if (e.type === "binop" && e.op === "and") {
14710
+ boolArg(ctx, "AND", evalExpr(ctx, scope, e.left));
14711
+ boolArg(ctx, "AND", evalExpr(ctx, scope, e.right));
14712
+ return;
14713
+ }
14714
+ if (e.type === "binop" && e.op === "or") {
14715
+ boolArg(ctx, "OR", evalExpr(ctx, scope, e.left));
14716
+ boolArg(ctx, "OR", evalExpr(ctx, scope, e.right));
14717
+ return;
14718
+ }
14719
+ if (e.type === "unop" && e.op === "not") {
14720
+ boolArg(ctx, "NOT", evalExpr(ctx, scope, e.operand));
14721
+ return;
14722
+ }
14723
+ if (e.type === "cast") {
14724
+ checkBoolExprType(ctx, scope, e.expr, kind);
14725
+ return;
14726
+ }
14727
+ if (e.type === "case") {
14728
+ validateSearchedCaseTree(ctx, scope, e);
14729
+ return;
14730
+ }
14731
+ const v = evalExpr(ctx, scope, e);
14732
+ if (v.t !== "bool" && v.t !== "unknown") {
14733
+ throw pgError("datatype_mismatch", `argument of ${kind} must be type boolean, not type ${typeDisplayName(v.t)}`);
14663
14734
  }
14664
14735
  }
14665
14736
  function checkSkippedBoolArg(ctx, scope, kind, e) {
14666
- if (isPureLiteral(e)) boolArg(ctx, kind, evalExpr(ctx, scope, e));
14737
+ boolArg(ctx, kind, evalExpr(ctx, scope, e));
14667
14738
  }
14668
14739
  function evalBinaryNode(ctx, scope, op, leftE, rightE) {
14669
14740
  if (op === "and") {
@@ -14766,7 +14837,55 @@ function applyDomainChecks(ctx, domainKey, value) {
14766
14837
  }
14767
14838
  }
14768
14839
  }
14840
+ function validateSearchedCaseTree(ctx, scope, e) {
14841
+ if (e.operand !== null) return;
14842
+ for (const { when, then } of e.whens) {
14843
+ boolArg(ctx, "CASE/WHEN", evalExpr(ctx, scope, when));
14844
+ validateCaseSubExpr(ctx, scope, then);
14845
+ }
14846
+ if (e.elseExpr !== null) validateCaseSubExpr(ctx, scope, e.elseExpr);
14847
+ }
14848
+ function validateCaseSubExpr(ctx, scope, e) {
14849
+ switch (e.type) {
14850
+ case "case":
14851
+ validateSearchedCaseTree(ctx, scope, e);
14852
+ return;
14853
+ case "binop":
14854
+ if (e.op === "and") {
14855
+ boolArg(ctx, "AND", evalExpr(ctx, scope, e.left));
14856
+ boolArg(ctx, "AND", evalExpr(ctx, scope, e.right));
14857
+ } else if (e.op === "or") {
14858
+ boolArg(ctx, "OR", evalExpr(ctx, scope, e.left));
14859
+ boolArg(ctx, "OR", evalExpr(ctx, scope, e.right));
14860
+ }
14861
+ validateCaseSubExpr(ctx, scope, e.left);
14862
+ validateCaseSubExpr(ctx, scope, e.right);
14863
+ return;
14864
+ case "unop":
14865
+ if (e.op === "not") {
14866
+ boolArg(ctx, "NOT", evalExpr(ctx, scope, e.operand));
14867
+ }
14868
+ validateCaseSubExpr(ctx, scope, e.operand);
14869
+ return;
14870
+ case "cast":
14871
+ case "collate":
14872
+ validateCaseSubExpr(ctx, scope, e.expr);
14873
+ return;
14874
+ case "func":
14875
+ for (const arg of e.args) validateCaseSubExpr(ctx, scope, arg);
14876
+ return;
14877
+ case "row":
14878
+ for (const item of e.items) validateCaseSubExpr(ctx, scope, item);
14879
+ return;
14880
+ case "array_ctor":
14881
+ for (const item of e.items) validateCaseSubExpr(ctx, scope, item);
14882
+ return;
14883
+ default:
14884
+ return;
14885
+ }
14886
+ }
14769
14887
  function evalCase(ctx, scope, e) {
14888
+ validateSearchedCaseTree(ctx, scope, e);
14770
14889
  let chosen = null;
14771
14890
  if (e.operand !== null) {
14772
14891
  const operand = evalExpr(ctx, scope, e.operand);
@@ -14780,7 +14899,8 @@ function evalCase(ctx, scope, e) {
14780
14899
  }
14781
14900
  } else {
14782
14901
  for (const { when, then } of e.whens) {
14783
- if (toBool(ctx, evalExpr(ctx, scope, when)) === true) {
14902
+ const w = evalExpr(ctx, scope, when);
14903
+ if (boolArg(ctx, "CASE/WHEN", w) === true) {
14784
14904
  chosen = then;
14785
14905
  break;
14786
14906
  }
@@ -16117,7 +16237,14 @@ function makeEvalScope(env, scope, extras) {
16117
16237
  return { type: t === UNKNOWN ? "text" : t, values: rel2.rows.map((r) => r[0] ?? null) };
16118
16238
  },
16119
16239
  aggValue(node) {
16120
- return extras?.aggMap?.get(node);
16240
+ const map = extras?.aggMap;
16241
+ if (!map) return void 0;
16242
+ const direct = map.get(node);
16243
+ if (direct !== void 0) return direct;
16244
+ for (const [call, value] of map) {
16245
+ if (exprEq(call, node)) return value;
16246
+ }
16247
+ return void 0;
16121
16248
  },
16122
16249
  windowValue(node) {
16123
16250
  if (!node.over) return void 0;
@@ -16138,11 +16265,9 @@ function makeEvalScope(env, scope, extras) {
16138
16265
  function evalScalar(env, scope, e, extras) {
16139
16266
  return evalExpr(env.ctx, makeEvalScope(env, scope, extras), e);
16140
16267
  }
16141
- function evalPredicate(env, scope, e, extras) {
16268
+ function evalPredicate(env, scope, e, extras, kind = "WHERE") {
16142
16269
  const v = evalScalar(env, scope, e, extras);
16143
- if (v.v === null) return false;
16144
- const b = castTo(env.ctx, v, "bool", {});
16145
- return b.v === true;
16270
+ return evalAsPredicate(env.ctx, kind, v);
16146
16271
  }
16147
16272
  function resolveUserFunctionForArgs(env, name, args) {
16148
16273
  const candidates = env.ctx.state.findFunctions(name);
@@ -16768,7 +16893,7 @@ function combineJoin(env, kind, left, right, on, using, usingAlias, rangeVars, e
16768
16893
  for (let i = 0; i < left.columns.length; i++) row.push(lrow[i] ?? null);
16769
16894
  for (let i = 0; i < right.columns.length; i++) row.push(rrow[i] ?? null);
16770
16895
  const jscope = new RowScope(columns, row, env.outer, rangeVars);
16771
- return evalPredicate(env, jscope, on);
16896
+ return evalPredicate(env, jscope, on, void 0, "ON");
16772
16897
  };
16773
16898
  const useHashJoin = kind !== "cross" && hashLeftIdxs.length > 0;
16774
16899
  if (useHashJoin) {
@@ -16883,6 +17008,11 @@ function buildFrom(env, items, where = null) {
16883
17008
  }
16884
17009
  return acc;
16885
17010
  }
17011
+ function exprHasAggregateCall(e) {
17012
+ const collector = { aggs: [], windows: [], groupings: [] };
17013
+ collectCalls(e, collector);
17014
+ return collector.aggs.length > 0;
17015
+ }
16886
17016
  function collectCalls(e, out) {
16887
17017
  if (!e || typeof e !== "object") return;
16888
17018
  if (e.type === "subquery_expr") return;
@@ -17024,7 +17154,192 @@ function groupDefMatches(def, e, columns) {
17024
17154
  }
17025
17155
  return exprEq(def.expr, e);
17026
17156
  }
17027
- function computeAggregate(env, call, rows) {
17157
+ function groupingErrorForColref(parts, columns) {
17158
+ const idx = resolveColIdx(columns, parts);
17159
+ let label;
17160
+ if (idx !== null) {
17161
+ const c = columns[idx];
17162
+ label = c.table ? `${c.table}.${c.name}` : c.name;
17163
+ } else {
17164
+ label = parts.join(".");
17165
+ }
17166
+ throw pgError(
17167
+ "grouping_error",
17168
+ `column "${label}" must appear in the GROUP BY clause or be used in an aggregate function`,
17169
+ "42803"
17170
+ );
17171
+ }
17172
+ function isGroupingExpr(e, groupDefs, columns) {
17173
+ return groupDefs.some((d) => groupDefMatches(d, e, columns));
17174
+ }
17175
+ function validateGroupedExpr(e, groupDefs, columns, inAgg) {
17176
+ if (!e || typeof e !== "object") return;
17177
+ if (e.type === "subquery_expr") return;
17178
+ if (!inAgg && isGroupingExpr(e, groupDefs, columns)) return;
17179
+ switch (e.type) {
17180
+ case "null_lit":
17181
+ case "string_lit":
17182
+ case "number_lit":
17183
+ case "bool_lit":
17184
+ case "bitstring_lit":
17185
+ case "param":
17186
+ case "default_expr":
17187
+ return;
17188
+ case "colref":
17189
+ if (!inAgg) {
17190
+ if (resolveColIdx(columns, e.parts) === null) return;
17191
+ groupingErrorForColref(e.parts, columns);
17192
+ }
17193
+ return;
17194
+ case "grouping_func":
17195
+ for (const a of e.args) validateGroupedExpr(a, groupDefs, columns, inAgg);
17196
+ return;
17197
+ case "func": {
17198
+ const name = e.name[e.name.length - 1];
17199
+ if (e.over) {
17200
+ for (const a of e.args) validateGroupedExpr(a, groupDefs, columns, false);
17201
+ if (e.filter) validateGroupedExpr(e.filter, groupDefs, columns, false);
17202
+ for (const p of e.over.partitionBy ?? []) validateGroupedExpr(p, groupDefs, columns, false);
17203
+ for (const ob of e.over.orderBy ?? []) validateGroupedExpr(ob.expr, groupDefs, columns, false);
17204
+ return;
17205
+ }
17206
+ if (isAggregateName(name)) {
17207
+ for (const a of e.args) validateGroupedExpr(a, groupDefs, columns, true);
17208
+ if (e.filter) validateGroupedExpr(e.filter, groupDefs, columns, true);
17209
+ for (const ob of e.orderBy ?? []) validateGroupedExpr(ob.expr, groupDefs, columns, true);
17210
+ return;
17211
+ }
17212
+ for (const a of e.args) validateGroupedExpr(a, groupDefs, columns, inAgg);
17213
+ if (e.filter) validateGroupedExpr(e.filter, groupDefs, columns, inAgg);
17214
+ for (const ob of e.orderBy ?? []) validateGroupedExpr(ob.expr, groupDefs, columns, inAgg);
17215
+ return;
17216
+ }
17217
+ case "binop":
17218
+ validateGroupedExpr(e.left, groupDefs, columns, inAgg);
17219
+ validateGroupedExpr(e.right, groupDefs, columns, inAgg);
17220
+ return;
17221
+ case "unop":
17222
+ validateGroupedExpr(e.operand, groupDefs, columns, inAgg);
17223
+ return;
17224
+ case "cast":
17225
+ validateGroupedExpr(e.expr, groupDefs, columns, inAgg);
17226
+ return;
17227
+ case "collate":
17228
+ validateGroupedExpr(e.expr, groupDefs, columns, inAgg);
17229
+ return;
17230
+ case "case": {
17231
+ if (e.operand) validateGroupedExpr(e.operand, groupDefs, columns, inAgg);
17232
+ for (const w of e.whens) {
17233
+ validateGroupedExpr(w.when, groupDefs, columns, inAgg);
17234
+ validateGroupedExpr(w.then, groupDefs, columns, inAgg);
17235
+ }
17236
+ if (e.elseExpr) validateGroupedExpr(e.elseExpr, groupDefs, columns, inAgg);
17237
+ return;
17238
+ }
17239
+ case "in_expr":
17240
+ validateGroupedExpr(e.left, groupDefs, columns, inAgg);
17241
+ if (e.list) {
17242
+ for (const r of e.list) validateGroupedExpr(r, groupDefs, columns, inAgg);
17243
+ }
17244
+ return;
17245
+ case "between":
17246
+ validateGroupedExpr(e.left, groupDefs, columns, inAgg);
17247
+ validateGroupedExpr(e.low, groupDefs, columns, inAgg);
17248
+ validateGroupedExpr(e.high, groupDefs, columns, inAgg);
17249
+ return;
17250
+ case "is_null":
17251
+ case "bool_test":
17252
+ validateGroupedExpr(e.expr, groupDefs, columns, inAgg);
17253
+ return;
17254
+ case "is_distinct":
17255
+ validateGroupedExpr(e.left, groupDefs, columns, inAgg);
17256
+ validateGroupedExpr(e.right, groupDefs, columns, inAgg);
17257
+ return;
17258
+ case "row":
17259
+ for (const el of e.items) validateGroupedExpr(el, groupDefs, columns, inAgg);
17260
+ return;
17261
+ case "array_ctor":
17262
+ for (const el of e.items) validateGroupedExpr(el, groupDefs, columns, inAgg);
17263
+ return;
17264
+ case "array_query":
17265
+ return;
17266
+ case "subscript":
17267
+ validateGroupedExpr(e.base, groupDefs, columns, inAgg);
17268
+ for (const idx of e.indexes) {
17269
+ if (idx.lower) validateGroupedExpr(idx.lower, groupDefs, columns, inAgg);
17270
+ if (idx.upper) validateGroupedExpr(idx.upper, groupDefs, columns, inAgg);
17271
+ }
17272
+ return;
17273
+ case "field_select":
17274
+ validateGroupedExpr(e.base, groupDefs, columns, inAgg);
17275
+ return;
17276
+ case "at_time_zone":
17277
+ validateGroupedExpr(e.expr, groupDefs, columns, inAgg);
17278
+ validateGroupedExpr(e.zone, groupDefs, columns, inAgg);
17279
+ return;
17280
+ case "like":
17281
+ validateGroupedExpr(e.left, groupDefs, columns, inAgg);
17282
+ validateGroupedExpr(e.pattern, groupDefs, columns, inAgg);
17283
+ if (e.escape) validateGroupedExpr(e.escape, groupDefs, columns, inAgg);
17284
+ return;
17285
+ case "position":
17286
+ validateGroupedExpr(e.needle, groupDefs, columns, inAgg);
17287
+ validateGroupedExpr(e.haystack, groupDefs, columns, inAgg);
17288
+ return;
17289
+ case "substring_sql":
17290
+ validateGroupedExpr(e.source, groupDefs, columns, inAgg);
17291
+ if (e.from) validateGroupedExpr(e.from, groupDefs, columns, inAgg);
17292
+ if (e.forLen) validateGroupedExpr(e.forLen, groupDefs, columns, inAgg);
17293
+ if (e.similar) validateGroupedExpr(e.similar, groupDefs, columns, inAgg);
17294
+ if (e.escape) validateGroupedExpr(e.escape, groupDefs, columns, inAgg);
17295
+ return;
17296
+ case "overlay":
17297
+ validateGroupedExpr(e.source, groupDefs, columns, inAgg);
17298
+ validateGroupedExpr(e.placing, groupDefs, columns, inAgg);
17299
+ validateGroupedExpr(e.from, groupDefs, columns, inAgg);
17300
+ if (e.forLen) validateGroupedExpr(e.forLen, groupDefs, columns, inAgg);
17301
+ return;
17302
+ case "trim":
17303
+ validateGroupedExpr(e.source, groupDefs, columns, inAgg);
17304
+ if (e.chars) validateGroupedExpr(e.chars, groupDefs, columns, inAgg);
17305
+ return;
17306
+ case "extract":
17307
+ validateGroupedExpr(e.source, groupDefs, columns, inAgg);
17308
+ return;
17309
+ default:
17310
+ return;
17311
+ }
17312
+ }
17313
+ function validateGroupedTargets(targets, groupDefs, columns) {
17314
+ for (const t of targets) {
17315
+ if (t.expr.type === "star") {
17316
+ if (t.expr.table) {
17317
+ const label = t.expr.table[t.expr.table.length - 1];
17318
+ for (const c of columns) {
17319
+ if (c.table === label) {
17320
+ const parts = c.table ? [c.table, c.name] : [c.name];
17321
+ validateGroupedExpr({ type: "colref", parts }, groupDefs, columns, false);
17322
+ }
17323
+ }
17324
+ } else {
17325
+ for (const c of columns) {
17326
+ if (!c.hidden) {
17327
+ const parts = c.table ? [c.table, c.name] : [c.name];
17328
+ validateGroupedExpr({ type: "colref", parts }, groupDefs, columns, false);
17329
+ }
17330
+ }
17331
+ }
17332
+ continue;
17333
+ }
17334
+ validateGroupedExpr(t.expr, groupDefs, columns, false);
17335
+ }
17336
+ }
17337
+ function validateGroupedQuery(core, groupDefs, columns, orderBy = []) {
17338
+ validateGroupedTargets(core.targets, groupDefs, columns);
17339
+ if (core.having) validateGroupedExpr(core.having, groupDefs, columns, false);
17340
+ for (const ob of orderBy) validateGroupedExpr(ob.expr, groupDefs, columns, false);
17341
+ }
17342
+ function computeAggregate(env, call, rows, probeScope) {
17028
17343
  const ctx = env.ctx;
17029
17344
  const name = call.name[call.name.length - 1];
17030
17345
  const orderedSet = isOrderedSetAggregate(name);
@@ -17111,6 +17426,17 @@ function computeAggregate(env, call, rows) {
17111
17426
  }
17112
17427
  argTypes.push(t);
17113
17428
  }
17429
+ if (effective.length === 0 && probeScope !== null && argCount > 0) {
17430
+ const scope = makeEvalScope(env, probeScope);
17431
+ for (let i = 0; i < argCount; i++) {
17432
+ if (argTypes[i] !== UNKNOWN) continue;
17433
+ if (call.star) continue;
17434
+ const expr = orderedSet && i >= call.args.length ? orderBy[0].expr : call.args[i] ?? orderBy[0].expr;
17435
+ if (!expr) continue;
17436
+ const v = evalExpr(ctx, scope, expr);
17437
+ argTypes[i] = v.t === UNKNOWN ? "text" : v.t;
17438
+ }
17439
+ }
17114
17440
  const acc = createAggregate(ctx, name, argTypes);
17115
17441
  for (const t of effective) acc.step(t.args);
17116
17442
  return acc.result();
@@ -17415,7 +17741,16 @@ function expandTargets(core, columns) {
17415
17741
  }
17416
17742
  return items;
17417
17743
  }
17418
- function executeCore(env0, core, orderBy) {
17744
+ function checkPredicateType(env, columns, rangeVars, e, kind, extras) {
17745
+ const probe = new RowScope(
17746
+ columns,
17747
+ columns.map(() => null),
17748
+ env.outer,
17749
+ rangeVars
17750
+ );
17751
+ checkBoolExprType(env.ctx, makeEvalScope(env, probe, extras), e, kind);
17752
+ }
17753
+ function executeCore(env0, core, orderBy, opts) {
17419
17754
  const env = env0;
17420
17755
  const ctx = env.ctx;
17421
17756
  const source = buildFrom(env, core.from, core.where);
@@ -17424,6 +17759,7 @@ function executeCore(env0, core, orderBy) {
17424
17759
  const rowScope = (row) => new RowScope(srcCols, row, env.outer, rangeVars);
17425
17760
  let srcRows = source.rel.rows;
17426
17761
  if (core.where) {
17762
+ checkPredicateType(env, srcCols, rangeVars, core.where, "WHERE");
17427
17763
  if (core.from.length === 1) {
17428
17764
  const indexed = tryIndexedFromItem(env, core.from[0], core.where);
17429
17765
  if (indexed !== null) {
@@ -17513,7 +17849,7 @@ function executeCore(env0, core, orderBy) {
17513
17849
  const aggMap = /* @__PURE__ */ new Map();
17514
17850
  const groupScopes = rows.map((r) => rowScope(r));
17515
17851
  for (const agg of collector.aggs) {
17516
- aggMap.set(agg, computeAggregate(env, agg, groupScopes));
17852
+ aggMap.set(agg, computeAggregate(env, agg, groupScopes, repScope));
17517
17853
  }
17518
17854
  ctxs.push({
17519
17855
  scope: repScope,
@@ -17554,9 +17890,19 @@ function executeCore(env0, core, orderBy) {
17554
17890
  return tv("int4", mask);
17555
17891
  } : void 0
17556
17892
  });
17893
+ if (core.having) {
17894
+ if (ctxs.length > 0) {
17895
+ checkPredicateType(env, srcCols, rangeVars, core.having, "HAVING", extrasFor(ctxs[0]));
17896
+ } else if (!exprHasAggregateCall(core.having)) {
17897
+ checkPredicateType(env, srcCols, rangeVars, core.having, "HAVING");
17898
+ }
17899
+ }
17900
+ if (grouped) {
17901
+ validateGroupedQuery(core, groupDefs, srcCols, orderBy);
17902
+ }
17557
17903
  if (core.having) {
17558
17904
  const having = core.having;
17559
- ctxs = ctxs.filter((rc) => evalPredicate(env, rc.scope, having, extrasFor(rc)));
17905
+ ctxs = ctxs.filter((rc) => evalPredicate(env, rc.scope, having, extrasFor(rc), "HAVING"));
17560
17906
  }
17561
17907
  const windowMaps = /* @__PURE__ */ new Map();
17562
17908
  if (collector.windows.length > 0) {
@@ -17601,6 +17947,14 @@ function executeCore(env0, core, orderBy) {
17601
17947
  sortSpecs.push(spec);
17602
17948
  orderExprs.push({ item, spec });
17603
17949
  }
17950
+ if (core.distinct && !core.distinct.on && sortSpecs.length > 0 && !opts?.hasLimit) {
17951
+ const used = new Set(sortSpecs.map((s) => s.colIdx));
17952
+ for (let i = 0; i < visibleCount; i++) {
17953
+ if (projItems[i].hidden || used.has(i)) continue;
17954
+ sortSpecs.push({ colIdx: i, dir: "asc", nullsFirst: false });
17955
+ used.add(i);
17956
+ }
17957
+ }
17604
17958
  const distinctOnIdx = [];
17605
17959
  if (core.distinct?.on) {
17606
17960
  for (const e of core.distinct.on) {
@@ -17784,7 +18138,7 @@ function executeSelectStmt(env0, stmt) {
17784
18138
  const env = applyWith(env0, stmt.with);
17785
18139
  let rel2;
17786
18140
  if (stmt.body.type === "select_core") {
17787
- rel2 = executeCore(env, stmt.body, stmt.orderBy);
18141
+ rel2 = executeCore(env, stmt.body, stmt.orderBy, { hasLimit: stmt.limit !== null });
17788
18142
  } else {
17789
18143
  rel2 = executeBody(env, stmt.body);
17790
18144
  const specs = outputOrderSpecs(env, rel2, stmt.orderBy);
@@ -18002,6 +18356,9 @@ var PlParser = class {
18002
18356
  this.expectSemi();
18003
18357
  return { kind: "for", targets, query, body };
18004
18358
  }
18359
+ if (this.atKw("update") || this.atKw("insert") || this.atKw("delete")) {
18360
+ return { kind: "sql", text: this.parseSqlTextUntilSemi() };
18361
+ }
18005
18362
  const target = [];
18006
18363
  const first = this.next();
18007
18364
  if (first.type !== "ident" && first.type !== "quoted_ident") {
@@ -18019,6 +18376,22 @@ var PlParser = class {
18019
18376
  }
18020
18377
  return { kind: "assign", target, expr: this.parseExprUntilSemi() };
18021
18378
  }
18379
+ parseSqlTextUntilSemi() {
18380
+ const start = this.peek().pos;
18381
+ let depth = 0;
18382
+ for (; ; ) {
18383
+ const t = this.peek();
18384
+ if (t.type === "eof") throw unsupported("plpgsql: unterminated statement");
18385
+ if (t.type === "punct" && t.value === "(") depth++;
18386
+ if (t.type === "punct" && t.value === ")") depth--;
18387
+ if (t.type === "punct" && t.value === ";" && depth === 0) {
18388
+ const text = this.src.slice(start, t.pos).trim();
18389
+ this.pos++;
18390
+ return text;
18391
+ }
18392
+ this.pos++;
18393
+ }
18394
+ }
18022
18395
  parseExprUntilSemi() {
18023
18396
  const start = this.peek().pos;
18024
18397
  let depth = 0;
@@ -18236,6 +18609,12 @@ function runStmt(env, stmt, vars, emit, tableNames) {
18236
18609
  }
18237
18610
  return;
18238
18611
  }
18612
+ case "sql": {
18613
+ const stmts = parse(stmt.text);
18614
+ if (stmts.length !== 1) throw unsupported(`plpgsql SQL statement: ${stmt.text}`);
18615
+ runStatement(env, stmts[0]);
18616
+ return;
18617
+ }
18239
18618
  }
18240
18619
  }
18241
18620
  function bindArgs(env, fn, args) {
@@ -18416,6 +18795,12 @@ function runTriggerBody(env, table, stmts, vars) {
18416
18795
  }
18417
18796
  break;
18418
18797
  }
18798
+ case "sql": {
18799
+ const stmts2 = parse(stmt.text);
18800
+ if (stmts2.length !== 1) throw unsupported(`trigger body SQL: ${stmt.text}`);
18801
+ runStatement(env, stmts2[0]);
18802
+ break;
18803
+ }
18419
18804
  default:
18420
18805
  throw unsupported(`trigger body: ${stmt.kind}`);
18421
18806
  }
@@ -18666,6 +19051,8 @@ var DatabaseState = class _DatabaseState {
18666
19051
  inTransaction = false;
18667
19052
  /** most recent sequence touched by nextval/setval, for lastval() */
18668
19053
  lastSequence = null;
19054
+ /** Session currval per sequence; absent entry means currval is undefined. */
19055
+ sequenceCurrval = /* @__PURE__ */ new Map();
18669
19056
  constructor(prng, clock) {
18670
19057
  this.prng = prng;
18671
19058
  this.clock = clock;
@@ -18854,6 +19241,7 @@ var DatabaseState = class _DatabaseState {
18854
19241
  s.changes = this.changes;
18855
19242
  s.inTransaction = this.inTransaction;
18856
19243
  s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
19244
+ s.sequenceCurrval = new Map(this.sequenceCurrval);
18857
19245
  s.oidCounter = this.oidCounter;
18858
19246
  return s;
18859
19247
  }
@@ -18868,6 +19256,7 @@ var DatabaseState = class _DatabaseState {
18868
19256
  s.changes = this.changes;
18869
19257
  s.inTransaction = this.inTransaction;
18870
19258
  s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
19259
+ s.sequenceCurrval = new Map(this.sequenceCurrval);
18871
19260
  s.oidCounter = this.oidCounter;
18872
19261
  return s;
18873
19262
  }
@@ -18938,6 +19327,7 @@ var DatabaseState = class _DatabaseState {
18938
19327
  this.prepared = other.prepared;
18939
19328
  this.changes = other.changes;
18940
19329
  this.lastSequence = other.lastSequence;
19330
+ this.sequenceCurrval = other.sequenceCurrval;
18941
19331
  this.oidCounter = other.oidCounter;
18942
19332
  }
18943
19333
  /** @internal Snapshot codec access to the oid allocator. */
@@ -20279,6 +20669,22 @@ function executeTruncate(env, stmt) {
20279
20669
  }
20280
20670
 
20281
20671
  // src/executor/dml.ts
20672
+ function withStatementRollback(env, fn) {
20673
+ if (env.ctx.state.inTransaction) return fn();
20674
+ const state = env.ctx.state;
20675
+ state.freezeShared();
20676
+ const snap = state.cloneShallow();
20677
+ const prngSnap = state.prng.getState();
20678
+ try {
20679
+ return fn();
20680
+ } catch (e) {
20681
+ state.restoreFrom(snap);
20682
+ state.prng.setState(prngSnap);
20683
+ throw e;
20684
+ } finally {
20685
+ state.thawShared();
20686
+ }
20687
+ }
20282
20688
  function requireTargetTable(env, parts, verb) {
20283
20689
  const state = env.ctx.state;
20284
20690
  const table = state.findTable(parts);
@@ -20479,84 +20885,86 @@ function executeInsert(env0, stmt) {
20479
20885
  const sourceRows = insertSourceRows(env, stmt, colIdxs);
20480
20886
  const insertedRows = [];
20481
20887
  let insertedCount = 0;
20482
- for (const srcRow of sourceRows) {
20483
- const row = table.columns.map(() => null);
20484
- const provided = /* @__PURE__ */ new Set();
20485
- for (let k = 0; k < srcRow.length; k++) {
20486
- const ci = colIdxs[k];
20487
- const col = table.columns[ci];
20488
- const cell = srcRow[k];
20489
- if (cell === DEFAULT_MARKER) {
20490
- row[ci] = columnDefault(env, table, col);
20888
+ return withStatementRollback(env, () => {
20889
+ for (const srcRow of sourceRows) {
20890
+ const row = table.columns.map(() => null);
20891
+ const provided = /* @__PURE__ */ new Set();
20892
+ for (let k = 0; k < srcRow.length; k++) {
20893
+ const ci = colIdxs[k];
20894
+ const col = table.columns[ci];
20895
+ const cell = srcRow[k];
20896
+ if (cell === DEFAULT_MARKER) {
20897
+ row[ci] = columnDefault(env, table, col);
20898
+ provided.add(ci);
20899
+ continue;
20900
+ }
20901
+ if (col.identity?.always && stmt.overriding !== "system") {
20902
+ throw pgError("generated_always", `cannot insert a non-DEFAULT value into column "${col.name}"`, "428C9");
20903
+ }
20904
+ row[ci] = coerceToColumn(env, cell, col);
20491
20905
  provided.add(ci);
20492
- continue;
20493
- }
20494
- if (col.identity?.always && stmt.overriding !== "system") {
20495
- throw pgError("generated_always", `cannot insert a non-DEFAULT value into column "${col.name}"`, "428C9");
20496
20906
  }
20497
- row[ci] = coerceToColumn(env, cell, col);
20498
- provided.add(ci);
20499
- }
20500
- for (let i = 0; i < table.columns.length; i++) {
20501
- if (provided.has(i)) continue;
20502
- const col = table.columns[i];
20503
- if (col.generated) continue;
20504
- row[i] = columnDefault(env, table, col);
20505
- }
20506
- const fired = fireRowTriggers(env, table, "before", "insert", null, row);
20507
- if (fired.row === null) continue;
20508
- const newRow = fired.row;
20509
- computeGeneratedColumns(env, table, newRow);
20510
- if (stmt.onConflict) {
20511
- const arbiters = resolveArbiters(env, table, stmt.onConflict);
20512
- let conflictIdx = null;
20513
- let conflictWhereOk = true;
20514
- for (const a of arbiters) {
20515
- if ("columns" in (stmt.onConflict.target ?? {}) && stmt.onConflict.target && "columns" in stmt.onConflict.target && stmt.onConflict.target.where) {
20516
- const scope = tableRowScope(env, table, label, newRow);
20517
- conflictWhereOk = evalPredicate(env, scope, stmt.onConflict.target.where);
20518
- }
20519
- const idx = findConflict(env, table, a.spec, newRow);
20520
- if (idx !== null) {
20521
- conflictIdx = idx;
20522
- break;
20907
+ for (let i = 0; i < table.columns.length; i++) {
20908
+ if (provided.has(i)) continue;
20909
+ const col = table.columns[i];
20910
+ if (col.generated) continue;
20911
+ row[i] = columnDefault(env, table, col);
20912
+ }
20913
+ const fired = fireRowTriggers(env, table, "before", "insert", null, row);
20914
+ if (fired.row === null) continue;
20915
+ const newRow = fired.row;
20916
+ computeGeneratedColumns(env, table, newRow);
20917
+ if (stmt.onConflict) {
20918
+ const arbiters = resolveArbiters(env, table, stmt.onConflict);
20919
+ let conflictIdx = null;
20920
+ let conflictWhereOk = true;
20921
+ for (const a of arbiters) {
20922
+ if ("columns" in (stmt.onConflict.target ?? {}) && stmt.onConflict.target && "columns" in stmt.onConflict.target && stmt.onConflict.target.where) {
20923
+ const scope = tableRowScope(env, table, label, newRow);
20924
+ conflictWhereOk = evalPredicate(env, scope, stmt.onConflict.target.where);
20925
+ }
20926
+ const idx = findConflict(env, table, a.spec, newRow);
20927
+ if (idx !== null) {
20928
+ conflictIdx = idx;
20929
+ break;
20930
+ }
20523
20931
  }
20524
- }
20525
- if (conflictIdx !== null && conflictWhereOk) {
20526
- if (stmt.onConflict.action === "nothing") continue;
20527
- const did = applyOnConflictUpdate(
20528
- env,
20529
- table,
20530
- label,
20531
- conflictIdx,
20532
- newRow,
20533
- stmt.onConflict.action.sets,
20534
- stmt.onConflict.action.where
20535
- );
20536
- if (did) {
20537
- insertedCount++;
20538
- insertedRows.push(rows[conflictIdx]);
20539
- fireRowTriggers(env, table, "after", "update", null, rows[conflictIdx]);
20932
+ if (conflictIdx !== null && conflictWhereOk) {
20933
+ if (stmt.onConflict.action === "nothing") continue;
20934
+ const did = applyOnConflictUpdate(
20935
+ env,
20936
+ table,
20937
+ label,
20938
+ conflictIdx,
20939
+ newRow,
20940
+ stmt.onConflict.action.sets,
20941
+ stmt.onConflict.action.where
20942
+ );
20943
+ if (did) {
20944
+ insertedCount++;
20945
+ insertedRows.push(rows[conflictIdx]);
20946
+ fireRowTriggers(env, table, "after", "update", null, rows[conflictIdx]);
20947
+ }
20948
+ continue;
20540
20949
  }
20541
- continue;
20542
20950
  }
20951
+ checkNotNull(env, table, newRow);
20952
+ checkChecks(env, table, newRow);
20953
+ checkUnique(env, table, newRow, rows.length);
20954
+ checkForeignKeys(env, table, newRow);
20955
+ rows.push(newRow);
20956
+ indexInsertRow(env, table, rows.length - 1, newRow);
20957
+ insertedCount++;
20958
+ insertedRows.push(newRow);
20959
+ fireRowTriggers(env, table, "after", "insert", null, newRow);
20543
20960
  }
20544
- checkNotNull(env, table, newRow);
20545
- checkChecks(env, table, newRow);
20546
- checkUnique(env, table, newRow, rows.length);
20547
- checkForeignKeys(env, table, newRow);
20548
- rows.push(newRow);
20549
- indexInsertRow(env, table, rows.length - 1, newRow);
20550
- insertedCount++;
20551
- insertedRows.push(newRow);
20552
- fireRowTriggers(env, table, "after", "insert", null, newRow);
20553
- }
20554
- env.ctx.state.changes = insertedCount;
20555
- if (stmt.returning) {
20556
- const res = evalReturning(env, table, label, stmt.returning, insertedRows, "INSERT");
20557
- return { ...res, rowCount: insertedCount };
20558
- }
20559
- return commandResult("INSERT", insertedCount);
20961
+ env.ctx.state.changes = insertedCount;
20962
+ if (stmt.returning) {
20963
+ const res = evalReturning(env, table, label, stmt.returning, insertedRows, "INSERT");
20964
+ return { ...res, rowCount: insertedCount };
20965
+ }
20966
+ return commandResult("INSERT", insertedCount);
20967
+ });
20560
20968
  }
20561
20969
  function applyUpdateSets(env, table, sets, scope, row) {
20562
20970
  for (const set of sets) {