@crvouga/postgres-mem 1.1.0 → 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/AGENTS.md +1 -1
- package/README.md +3 -2
- package/compat/divergences.json +0 -7
- package/compat/sections/par.ts +1 -8
- package/compat/unsupported-register.json +0 -1
- package/dist/executor/plpgsql.d.ts +3 -0
- package/dist/executor/select.d.ts +4 -2
- package/dist/expressions/eval.d.ts +4 -0
- package/dist/index.js +616 -118
- package/dist/index.js.map +3 -3
- package/dist/sql/deparse.d.ts +3 -0
- package/dist/storage/database-state.d.ts +2 -0
- package/dist/types/jsonb.d.ts +3 -1
- package/dist/types/range.d.ts +17 -0
- package/dist/unstable.js +524 -116
- package/dist/unstable.js.map +3 -3
- package/package.json +5 -3
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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")
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
9482
|
-
if (t === "
|
|
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
|
|
9731
|
-
|
|
9732
|
-
|
|
9733
|
-
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
9737
|
-
|
|
9738
|
-
|
|
9739
|
-
|
|
9740
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
18336
|
-
const
|
|
18337
|
-
|
|
18338
|
-
|
|
18339
|
-
|
|
18340
|
-
|
|
18341
|
-
|
|
18342
|
-
|
|
18343
|
-
|
|
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
|
-
|
|
18348
|
-
|
|
18349
|
-
|
|
18350
|
-
|
|
18351
|
-
|
|
18352
|
-
|
|
18353
|
-
|
|
18354
|
-
if (
|
|
18355
|
-
const
|
|
18356
|
-
|
|
18357
|
-
|
|
18358
|
-
|
|
18359
|
-
|
|
18360
|
-
|
|
18361
|
-
|
|
18362
|
-
|
|
18363
|
-
|
|
18364
|
-
|
|
18365
|
-
|
|
18366
|
-
|
|
18367
|
-
|
|
18368
|
-
|
|
18369
|
-
|
|
18370
|
-
|
|
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
|
-
|
|
18379
|
-
|
|
18380
|
-
|
|
18381
|
-
|
|
18382
|
-
|
|
18383
|
-
|
|
18384
|
-
|
|
18385
|
-
|
|
18386
|
-
|
|
18387
|
-
|
|
18388
|
-
|
|
18389
|
-
|
|
18390
|
-
|
|
18391
|
-
|
|
18392
|
-
|
|
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
|
-
|
|
18398
|
-
|
|
18399
|
-
|
|
18400
|
-
|
|
18401
|
-
|
|
18402
|
-
|
|
18403
|
-
|
|
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
|
-
|
|
22881
|
+
forceAllEncodeIntern(pool, state, schemas);
|
|
22474
22882
|
const internId = (s) => pool.id(s);
|
|
22475
|
-
const 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);
|