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