@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/wire/cli.js
CHANGED
|
@@ -744,9 +744,6 @@ function ownedTransport(policy) {
|
|
|
744
744
|
|
|
745
745
|
// ../../adapters/node/dist/cli.js
|
|
746
746
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
747
|
-
import { createRequire as createRequire3 } from "node:module";
|
|
748
|
-
import { resolve as resolve3 } from "node:path";
|
|
749
|
-
import { pathToFileURL } from "node:url";
|
|
750
747
|
import { parseArgs } from "node:util";
|
|
751
748
|
|
|
752
749
|
// ../../adapters/node/dist/fleet.js
|
|
@@ -760,6 +757,31 @@ import { createHash as createHash3, randomBytes, randomUUID as randomUUID3 } fro
|
|
|
760
757
|
|
|
761
758
|
// ../../adapters/node/dist/fleet-archive.js
|
|
762
759
|
import { createHash } from "node:crypto";
|
|
760
|
+
function validateCompatibilityTags(tags) {
|
|
761
|
+
if (!tags || typeof tags !== "object" || Array.isArray(tags))
|
|
762
|
+
throw new Error("invalid archive compatibility tags");
|
|
763
|
+
const entries = Object.entries(tags);
|
|
764
|
+
if (entries.length > 32 || entries.some(([key, value]) => !/^[A-Za-z0-9_.-]{1,64}$/.test(key) || typeof value !== "string" || value.length < 1 || value.length > 256 || [...value].some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127)))
|
|
765
|
+
throw new Error("invalid archive compatibility tags");
|
|
766
|
+
}
|
|
767
|
+
function assertCompatibilityTags(tags, policy) {
|
|
768
|
+
if (tags !== void 0)
|
|
769
|
+
validateCompatibilityTags(tags);
|
|
770
|
+
if (!policy)
|
|
771
|
+
return;
|
|
772
|
+
validateCompatibilityTags(policy.tags);
|
|
773
|
+
if (policy.missing !== void 0 && !["allow", "reject"].includes(policy.missing))
|
|
774
|
+
throw new Error("invalid missing compatibility policy");
|
|
775
|
+
if (tags === void 0 && policy.missing === "allow")
|
|
776
|
+
return;
|
|
777
|
+
if (canonical(tags) !== canonical(policy.tags))
|
|
778
|
+
throw new Error("application archive compatibility mismatch");
|
|
779
|
+
}
|
|
780
|
+
function assertArchiveCompatibility(input, policy) {
|
|
781
|
+
const archive = validateArchive(input);
|
|
782
|
+
assertCompatibilityTags(archive.compatibility, policy);
|
|
783
|
+
return archive;
|
|
784
|
+
}
|
|
763
785
|
var canonical = (value) => {
|
|
764
786
|
if (Array.isArray(value))
|
|
765
787
|
return `[${value.map(canonical).join(",")}]`;
|
|
@@ -779,6 +801,8 @@ function validateArchive(value) {
|
|
|
779
801
|
const { sha256: sha2563, ...content } = doc;
|
|
780
802
|
if (doc.format !== "mockingbird.fleet/v1" || typeof doc.sourceId !== "string" || typeof doc.createdAt !== "string" || !doc.namespaces || typeof doc.namespaces !== "object" || Array.isArray(doc.namespaces) || sha2563 !== digest(content))
|
|
781
803
|
throw new Error("unsupported or corrupt fleet archive");
|
|
804
|
+
if (doc.compatibility !== void 0)
|
|
805
|
+
validateCompatibilityTags(doc.compatibility);
|
|
782
806
|
for (const [namespace, entry] of Object.entries(doc.namespaces)) {
|
|
783
807
|
if (!/^[A-Za-z0-9_.-]{1,64}$/.test(namespace) || !entry || !Number.isFinite(entry.clock?.now) || typeof entry.clock?.frozen !== "boolean" || !entry.services || !Object.keys(entry.services).length)
|
|
784
808
|
throw new Error("invalid archive namespace");
|
|
@@ -794,6 +818,7 @@ function inspectArchive(input) {
|
|
|
794
818
|
format: archive.format,
|
|
795
819
|
createdAt: archive.createdAt,
|
|
796
820
|
sha256: archive.sha256,
|
|
821
|
+
...archive.compatibility ? { compatibility: archive.compatibility } : {},
|
|
797
822
|
namespaces: Object.fromEntries(Object.entries(archive.namespaces).map(([name2, ns]) => [
|
|
798
823
|
name2,
|
|
799
824
|
{
|
|
@@ -1436,11 +1461,28 @@ var ingressSupport = {
|
|
|
1436
1461
|
streaming: true,
|
|
1437
1462
|
signing: "vendor request signing is not used; webhook signatures remain payload based"
|
|
1438
1463
|
},
|
|
1464
|
+
cognito: {
|
|
1465
|
+
publicOrigin: true,
|
|
1466
|
+
pathPrefix: true,
|
|
1467
|
+
namespaces: "path-or-header",
|
|
1468
|
+
streaming: true,
|
|
1469
|
+
signing: "JWT issuer and JWKS use the configured public namespace; SigV4 verification is not modelled"
|
|
1470
|
+
},
|
|
1471
|
+
medplum: {
|
|
1472
|
+
publicOrigin: true,
|
|
1473
|
+
pathPrefix: true,
|
|
1474
|
+
namespaces: "path-or-header",
|
|
1475
|
+
streaming: true,
|
|
1476
|
+
signing: "FHIR, OAuth and storage URLs use the configured public namespace"
|
|
1477
|
+
},
|
|
1439
1478
|
other: {
|
|
1440
1479
|
publicOrigin: false,
|
|
1441
1480
|
reason: "host/path-sensitive signing and hosted URL rewriting are not certified; use a direct endpoint"
|
|
1442
1481
|
}
|
|
1443
1482
|
};
|
|
1483
|
+
function supportsPublicIngress(service) {
|
|
1484
|
+
return service === "stripe" || service === "cognito" || service === "medplum";
|
|
1485
|
+
}
|
|
1444
1486
|
function advertisedHttpBase(entry) {
|
|
1445
1487
|
if (entry.publicPath !== void 0 && !entry.publicOrigin)
|
|
1446
1488
|
throw new Error("publicPath requires publicOrigin");
|
|
@@ -1979,7 +2021,7 @@ data: ${JSON.stringify(data)}
|
|
|
1979
2021
|
{
|
|
1980
2022
|
protocol: c.protocol,
|
|
1981
2023
|
coverage: c.coverage,
|
|
1982
|
-
ingress: c.targetName
|
|
2024
|
+
ingress: supportsPublicIngress(c.targetName ?? "") ? ingressSupport[c.targetName] : ingressSupport.other,
|
|
1983
2025
|
target: c.targetName,
|
|
1984
2026
|
outboundPolicy: c.outboundPolicy ?? "unsupported",
|
|
1985
2027
|
version: 1,
|
|
@@ -3063,11 +3105,12 @@ data: ${JSON.stringify(data)}
|
|
|
3063
3105
|
format: "mockingbird.fleet/v1",
|
|
3064
3106
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3065
3107
|
sourceId: this.ctx.id,
|
|
3108
|
+
...this.ctx.options.archiveCompatibility ? { compatibility: structuredClone(this.ctx.options.archiveCompatibility.tags) } : {},
|
|
3066
3109
|
namespaces: contents
|
|
3067
3110
|
});
|
|
3068
3111
|
}
|
|
3069
3112
|
async restoreArchive(input, selectedNamespace) {
|
|
3070
|
-
const archive =
|
|
3113
|
+
const archive = assertArchiveCompatibility(input, this.ctx.options.archiveCompatibility);
|
|
3071
3114
|
const entries = Object.entries(archive.namespaces).filter(([ns]) => selectedNamespace === void 0 || ns === selectedNamespace);
|
|
3072
3115
|
if (!entries.length)
|
|
3073
3116
|
throw new Error("selected namespace absent from archive");
|
|
@@ -3651,7 +3694,7 @@ async function preflightFleet(config, options2) {
|
|
|
3651
3694
|
if (entry.target !== void 0 && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(entry.target))
|
|
3652
3695
|
throw new Error("target must name a supported service suffix");
|
|
3653
3696
|
const service = entry.target ?? name2;
|
|
3654
|
-
if (advertisedHttpBase(entry) && service
|
|
3697
|
+
if (advertisedHttpBase(entry) && !supportsPublicIngress(service))
|
|
3655
3698
|
throw new Error(`public ingress unsupported for ${service}; use a direct endpoint to preserve signed targets`);
|
|
3656
3699
|
const target = await options2.load(service);
|
|
3657
3700
|
const protocol = "protocol" in target ? target.protocol : "http";
|
|
@@ -3702,7 +3745,7 @@ async function preflightFleet(config, options2) {
|
|
|
3702
3745
|
break;
|
|
3703
3746
|
}
|
|
3704
3747
|
}
|
|
3705
|
-
targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.
|
|
3748
|
+
targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.7.0" });
|
|
3706
3749
|
} catch (error) {
|
|
3707
3750
|
throw new Error(`service ${name2}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
3708
3751
|
}
|
|
@@ -3746,6 +3789,11 @@ async function preflightFleet(config, options2) {
|
|
|
3746
3789
|
return ordered;
|
|
3747
3790
|
}
|
|
3748
3791
|
function validateFleetPolicies(options2) {
|
|
3792
|
+
if (options2.archiveCompatibility) {
|
|
3793
|
+
validateCompatibilityTags(options2.archiveCompatibility.tags);
|
|
3794
|
+
if (options2.archiveCompatibility.missing !== void 0 && !["allow", "reject"].includes(options2.archiveCompatibility.missing))
|
|
3795
|
+
throw new Error("archiveCompatibility.missing must be allow or reject");
|
|
3796
|
+
}
|
|
3749
3797
|
if (options2.journal && !options2.repository)
|
|
3750
3798
|
throw new Error("durable operation journal requires an archive repository");
|
|
3751
3799
|
if (options2.cors) {
|
|
@@ -4738,10 +4786,44 @@ async function startFleet(config, options2) {
|
|
|
4738
4786
|
}
|
|
4739
4787
|
}
|
|
4740
4788
|
|
|
4741
|
-
// ../../adapters/node/dist/fleet-
|
|
4742
|
-
import { readFile as readFile4 } from "node:fs/promises";
|
|
4789
|
+
// ../../adapters/node/dist/fleet-loader.js
|
|
4743
4790
|
import { createRequire as createRequire2 } from "node:module";
|
|
4744
4791
|
import { resolve as resolve2 } from "node:path";
|
|
4792
|
+
import { pathToFileURL } from "node:url";
|
|
4793
|
+
var suffix = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
4794
|
+
function createInstalledServiceLoader(options2) {
|
|
4795
|
+
if (!options2.projectRoot)
|
|
4796
|
+
throw new Error("consumer projectRoot required");
|
|
4797
|
+
const allowed = new Set(options2.services);
|
|
4798
|
+
for (const name2 of allowed)
|
|
4799
|
+
if (!suffix.test(name2))
|
|
4800
|
+
throw new Error("invalid service suffix");
|
|
4801
|
+
const require2 = createRequire2(resolve2(options2.projectRoot, "package.json"));
|
|
4802
|
+
const targets = new Map((options2.targets ?? []).map((target) => [target.name, target]));
|
|
4803
|
+
return async (name2) => {
|
|
4804
|
+
if (!suffix.test(name2) || !allowed.has(name2))
|
|
4805
|
+
throw new Error("service is not declared in loader allowlist");
|
|
4806
|
+
const own2 = targets.get(name2);
|
|
4807
|
+
if (own2)
|
|
4808
|
+
return own2;
|
|
4809
|
+
const specifier = `@crvouga/mockingbird-service-${name2}/server`;
|
|
4810
|
+
let location;
|
|
4811
|
+
try {
|
|
4812
|
+
location = require2.resolve(specifier);
|
|
4813
|
+
} catch {
|
|
4814
|
+
throw new Error(`cannot load service "${name2}": install @crvouga/mockingbird-service-${name2} in the consumer project; its /server export is required`);
|
|
4815
|
+
}
|
|
4816
|
+
const mod = await import(pathToFileURL(location).href);
|
|
4817
|
+
if (!mod.serveTarget || mod.serveTarget.name !== name2 || ("protocol" in mod.serveTarget ? typeof mod.serveTarget.start !== "function" : typeof mod.serveTarget.create !== "function"))
|
|
4818
|
+
throw new Error(`${specifier} exports no matching serveTarget`);
|
|
4819
|
+
return mod.serveTarget;
|
|
4820
|
+
};
|
|
4821
|
+
}
|
|
4822
|
+
|
|
4823
|
+
// ../../adapters/node/dist/fleet-tools.js
|
|
4824
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
4825
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
4826
|
+
import { resolve as resolve3 } from "node:path";
|
|
4745
4827
|
|
|
4746
4828
|
// ../../adapters/node/dist/fleet-client.js
|
|
4747
4829
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
@@ -4755,6 +4837,14 @@ var FleetClientError = class extends Error {
|
|
|
4755
4837
|
this.details = details;
|
|
4756
4838
|
}
|
|
4757
4839
|
};
|
|
4840
|
+
var FleetClientResponseError = class extends FleetClientError {
|
|
4841
|
+
code;
|
|
4842
|
+
constructor(code, status, origin) {
|
|
4843
|
+
super(status, { code, body: "omitted", ...origin ? { origin } : {} });
|
|
4844
|
+
this.code = code;
|
|
4845
|
+
this.name = "FleetClientResponseError";
|
|
4846
|
+
}
|
|
4847
|
+
};
|
|
4758
4848
|
var FleetClient = class {
|
|
4759
4849
|
base;
|
|
4760
4850
|
options;
|
|
@@ -4767,7 +4857,14 @@ var FleetClient = class {
|
|
|
4767
4857
|
if (url.username || url.password)
|
|
4768
4858
|
throw new Error("fleet client URL must not contain credentials");
|
|
4769
4859
|
url.searchParams.set("namespace", options2.namespace ?? this.options.namespace ?? "default");
|
|
4860
|
+
const limit = options2.maxResponseBytes ?? this.options.maxResponseBytes ?? 64 * 1024 * 1024;
|
|
4861
|
+
if (!Number.isSafeInteger(limit) || limit < 1)
|
|
4862
|
+
throw new Error("invalid response byte limit");
|
|
4863
|
+
const deadline = AbortSignal.timeout(this.options.timeoutMs ?? 3e4);
|
|
4864
|
+
const signal = options2.signal ? AbortSignal.any([options2.signal, deadline]) : deadline;
|
|
4865
|
+
signal.throwIfAborted();
|
|
4770
4866
|
const response = await (this.options.fetch ?? fetch)(url, {
|
|
4867
|
+
redirect: "manual",
|
|
4771
4868
|
method: options2.method ?? (options2.body === void 0 ? "GET" : "POST"),
|
|
4772
4869
|
headers: {
|
|
4773
4870
|
"content-type": "application/json",
|
|
@@ -4775,11 +4872,71 @@ var FleetClient = class {
|
|
|
4775
4872
|
...options2.idempotencyKey ? { "idempotency-key": options2.idempotencyKey } : {}
|
|
4776
4873
|
},
|
|
4777
4874
|
...options2.body !== void 0 ? { body: JSON.stringify(options2.body) } : {},
|
|
4778
|
-
signal
|
|
4875
|
+
signal
|
|
4779
4876
|
});
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
throw new
|
|
4877
|
+
if (response.status >= 300 && response.status < 400) {
|
|
4878
|
+
await response.body?.cancel();
|
|
4879
|
+
throw new FleetClientResponseError("redirect", response.status, url.origin);
|
|
4880
|
+
}
|
|
4881
|
+
if (Number(response.headers.get("content-length")) > limit) {
|
|
4882
|
+
await response.body?.cancel();
|
|
4883
|
+
throw new FleetClientResponseError("response_too_large", response.status);
|
|
4884
|
+
}
|
|
4885
|
+
const reader = response.body?.getReader();
|
|
4886
|
+
const chunks = [];
|
|
4887
|
+
let size = 0;
|
|
4888
|
+
const abort = () => {
|
|
4889
|
+
void reader?.cancel(signal.reason).catch(() => {
|
|
4890
|
+
});
|
|
4891
|
+
};
|
|
4892
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
4893
|
+
try {
|
|
4894
|
+
if (reader)
|
|
4895
|
+
while (true) {
|
|
4896
|
+
signal.throwIfAborted();
|
|
4897
|
+
const { done, value } = await reader.read();
|
|
4898
|
+
signal.throwIfAborted();
|
|
4899
|
+
if (done)
|
|
4900
|
+
break;
|
|
4901
|
+
size += value.byteLength;
|
|
4902
|
+
if (size > limit) {
|
|
4903
|
+
await reader.cancel();
|
|
4904
|
+
throw new FleetClientResponseError("response_too_large", response.status);
|
|
4905
|
+
}
|
|
4906
|
+
chunks.push(value);
|
|
4907
|
+
}
|
|
4908
|
+
} finally {
|
|
4909
|
+
signal.removeEventListener("abort", abort);
|
|
4910
|
+
if (signal.aborted)
|
|
4911
|
+
await reader?.cancel(signal.reason).catch(() => {
|
|
4912
|
+
});
|
|
4913
|
+
reader?.releaseLock();
|
|
4914
|
+
}
|
|
4915
|
+
const bytes = new Uint8Array(size);
|
|
4916
|
+
let offset = 0;
|
|
4917
|
+
for (const chunk of chunks) {
|
|
4918
|
+
bytes.set(chunk, offset);
|
|
4919
|
+
offset += chunk.byteLength;
|
|
4920
|
+
}
|
|
4921
|
+
const text = new TextDecoder().decode(bytes);
|
|
4922
|
+
let data;
|
|
4923
|
+
try {
|
|
4924
|
+
data = text.length ? JSON.parse(text) : void 0;
|
|
4925
|
+
} catch {
|
|
4926
|
+
if (response.ok)
|
|
4927
|
+
throw new FleetClientResponseError("invalid_json", response.status);
|
|
4928
|
+
}
|
|
4929
|
+
if (!response.ok) {
|
|
4930
|
+
const error = data && typeof data === "object" ? data.error : void 0;
|
|
4931
|
+
const detail = { body: "omitted" };
|
|
4932
|
+
if (error && typeof error === "object")
|
|
4933
|
+
for (const key of ["type", "code"]) {
|
|
4934
|
+
const value = error[key];
|
|
4935
|
+
if (typeof value === "string" && /^[A-Za-z0-9_.-]{1,128}$/.test(value))
|
|
4936
|
+
detail[key] = value;
|
|
4937
|
+
}
|
|
4938
|
+
throw new FleetClientError(response.status, detail);
|
|
4939
|
+
}
|
|
4783
4940
|
return data;
|
|
4784
4941
|
}
|
|
4785
4942
|
discover() {
|
|
@@ -4845,17 +5002,52 @@ function renderConnections(manifest, privateManifest, namespace, mapping) {
|
|
|
4845
5002
|
const child = manifest.services[entry.service], secret = privateManifest.services[entry.service];
|
|
4846
5003
|
if (!child || !secret)
|
|
4847
5004
|
throw new Error(`missing service mapping ${entry.service}`);
|
|
5005
|
+
let endpoint;
|
|
4848
5006
|
if (child.protocol === "http") {
|
|
4849
5007
|
const template = child.namespaces.path;
|
|
4850
5008
|
if (typeof template !== "string")
|
|
4851
5009
|
throw new Error(`missing HTTP namespace mapping ${entry.service}`);
|
|
4852
|
-
|
|
5010
|
+
endpoint = new URL(template.replace("{name}", encodeURIComponent(namespace)), secret.url).href;
|
|
4853
5011
|
} else {
|
|
4854
|
-
const
|
|
4855
|
-
if (!
|
|
5012
|
+
const selected = secret.namespaces?.[namespace];
|
|
5013
|
+
if (!selected)
|
|
4856
5014
|
throw new Error(`missing namespace mapping ${namespace}/${entry.service}`);
|
|
4857
|
-
|
|
5015
|
+
endpoint = selected;
|
|
5016
|
+
}
|
|
5017
|
+
const url = new URL(endpoint);
|
|
5018
|
+
const field = entry.field ?? "url";
|
|
5019
|
+
let value;
|
|
5020
|
+
switch (field) {
|
|
5021
|
+
case "url":
|
|
5022
|
+
value = endpoint;
|
|
5023
|
+
break;
|
|
5024
|
+
case "hostname":
|
|
5025
|
+
value = url.hostname.replace(/^\[|\]$/g, "");
|
|
5026
|
+
break;
|
|
5027
|
+
case "port":
|
|
5028
|
+
value = url.port;
|
|
5029
|
+
break;
|
|
5030
|
+
case "username":
|
|
5031
|
+
value = decodeURIComponent(url.username);
|
|
5032
|
+
break;
|
|
5033
|
+
case "password":
|
|
5034
|
+
value = decodeURIComponent(url.password);
|
|
5035
|
+
break;
|
|
5036
|
+
case "pathname":
|
|
5037
|
+
value = decodeURIComponent(url.pathname);
|
|
5038
|
+
break;
|
|
5039
|
+
case "database":
|
|
5040
|
+
value = decodeURIComponent(url.pathname.replace(/^\//, ""));
|
|
5041
|
+
break;
|
|
5042
|
+
default:
|
|
5043
|
+
throw new Error("unsupported connection field");
|
|
5044
|
+
}
|
|
5045
|
+
if (!value) {
|
|
5046
|
+
if (typeof entry.fallback !== "string")
|
|
5047
|
+
throw new Error(`missing connection component ${field}`);
|
|
5048
|
+
value = entry.fallback;
|
|
4858
5049
|
}
|
|
5050
|
+
result[variable] = value;
|
|
4859
5051
|
}
|
|
4860
5052
|
return result;
|
|
4861
5053
|
}
|
|
@@ -4879,7 +5071,7 @@ async function doctorFleet(config, options2, probes = []) {
|
|
|
4879
5071
|
const plan = [];
|
|
4880
5072
|
try {
|
|
4881
5073
|
const targets = await preflightFleet(config, options2);
|
|
4882
|
-
const require2 =
|
|
5074
|
+
const require2 = createRequire3(resolve3(process.cwd(), "package.json"));
|
|
4883
5075
|
for (const [service, target] of targets) {
|
|
4884
5076
|
let version = "development";
|
|
4885
5077
|
try {
|
|
@@ -4934,7 +5126,7 @@ async function doctorFleet(config, options2, probes = []) {
|
|
|
4934
5126
|
};
|
|
4935
5127
|
}
|
|
4936
5128
|
async function rehearseFleet(config, options2, input, probes = [], timeoutMs = 3e4) {
|
|
4937
|
-
const archive =
|
|
5129
|
+
const archive = assertArchiveCompatibility(input, options2.archiveCompatibility);
|
|
4938
5130
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4939
5131
|
const isolated = {
|
|
4940
5132
|
...config,
|
|
@@ -4946,7 +5138,7 @@ async function rehearseFleet(config, options2, input, probes = [], timeoutMs = 3
|
|
|
4946
5138
|
};
|
|
4947
5139
|
let fleet;
|
|
4948
5140
|
try {
|
|
4949
|
-
fleet = await startFleet(isolated,
|
|
5141
|
+
fleet = await startFleet(isolated, options2);
|
|
4950
5142
|
const client = new FleetClient(fleet.manifest.adminBase, {
|
|
4951
5143
|
...config.adminKey ? { adminKey: config.adminKey } : {}
|
|
4952
5144
|
});
|
|
@@ -5321,26 +5513,7 @@ var resolveServeControls = async (values, env = process.env, base) => {
|
|
|
5321
5513
|
normalizeBootControls(document, "adminControls");
|
|
5322
5514
|
return document;
|
|
5323
5515
|
};
|
|
5324
|
-
var loadTarget =
|
|
5325
|
-
if (name2 === own2.name)
|
|
5326
|
-
return own2;
|
|
5327
|
-
const specifier = `@crvouga/mockingbird-service-${name2}/server`;
|
|
5328
|
-
try {
|
|
5329
|
-
let mod;
|
|
5330
|
-
try {
|
|
5331
|
-
mod = await import(specifier);
|
|
5332
|
-
} catch {
|
|
5333
|
-
const fromProject = createRequire3(resolve3(process.cwd(), "package.json"));
|
|
5334
|
-
mod = await import(pathToFileURL(fromProject.resolve(specifier)).href);
|
|
5335
|
-
}
|
|
5336
|
-
if (!mod.serveTarget)
|
|
5337
|
-
throw new Error(`${specifier} exports no serveTarget`);
|
|
5338
|
-
return mod.serveTarget;
|
|
5339
|
-
} catch (error) {
|
|
5340
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
5341
|
-
throw new Error(`cannot load service "${name2}": ${reason}. Install @crvouga/mockingbird-service-${name2}.`);
|
|
5342
|
-
}
|
|
5343
|
-
};
|
|
5516
|
+
var loadTarget = (name2, own2) => createInstalledServiceLoader({ projectRoot: process.cwd(), services: [name2], targets: [own2] })(name2);
|
|
5344
5517
|
var start = async (target, values, config) => {
|
|
5345
5518
|
const adminPrefix = resolveAdminPrefix(config.adminPrefix);
|
|
5346
5519
|
const runtime = await target.create(values, {
|
|
@@ -5539,6 +5712,13 @@ function isPostgresError(err) {
|
|
|
5539
5712
|
return typeof sqlState === "string" && /^[0-9A-Z]{5}$/.test(sqlState);
|
|
5540
5713
|
}
|
|
5541
5714
|
|
|
5715
|
+
// src/storage/guc.ts
|
|
5716
|
+
function validateStorageSetting(name2, value) {
|
|
5717
|
+
if (name2 === "default_table_access_method" && value !== "heap" || name2 === "default_tablespace" && value !== "" && value !== "pg_default") {
|
|
5718
|
+
throw pgError("invalid_parameter_value", `invalid value for parameter "${name2}": "${value}"`, "22023");
|
|
5719
|
+
}
|
|
5720
|
+
}
|
|
5721
|
+
|
|
5542
5722
|
// src/runtime/prng.ts
|
|
5543
5723
|
var Prng = class _Prng {
|
|
5544
5724
|
state;
|
|
@@ -5779,9 +5959,9 @@ function stemEnglish(input) {
|
|
|
5779
5959
|
return false;
|
|
5780
5960
|
})();
|
|
5781
5961
|
if (!step1bDone) {
|
|
5782
|
-
for (const
|
|
5783
|
-
if (w.endsWith(
|
|
5784
|
-
const stem = w.slice(0, -
|
|
5962
|
+
for (const suffix2 of ["ingly", "edly", "ing", "ed"]) {
|
|
5963
|
+
if (w.endsWith(suffix2)) {
|
|
5964
|
+
const stem = w.slice(0, -suffix2.length);
|
|
5785
5965
|
if ([...stem].some(isVowel)) {
|
|
5786
5966
|
w = stem;
|
|
5787
5967
|
if (w.endsWith("at") || w.endsWith("bl") || w.endsWith("iz")) w += "e";
|
|
@@ -5819,9 +5999,9 @@ function stemEnglish(input) {
|
|
|
5819
5999
|
["alli", "al"],
|
|
5820
6000
|
["bli", "ble"]
|
|
5821
6001
|
];
|
|
5822
|
-
for (const [
|
|
5823
|
-
if (w.endsWith(
|
|
5824
|
-
if (w.length -
|
|
6002
|
+
for (const [suffix2, repl] of step2) {
|
|
6003
|
+
if (w.endsWith(suffix2)) {
|
|
6004
|
+
if (w.length - suffix2.length >= r1) w = w.slice(0, -suffix2.length) + repl;
|
|
5825
6005
|
break;
|
|
5826
6006
|
}
|
|
5827
6007
|
}
|
|
@@ -5840,9 +6020,9 @@ function stemEnglish(input) {
|
|
|
5840
6020
|
["ness", ""],
|
|
5841
6021
|
["ful", ""]
|
|
5842
6022
|
];
|
|
5843
|
-
for (const [
|
|
5844
|
-
if (w.endsWith(
|
|
5845
|
-
if (w.length -
|
|
6023
|
+
for (const [suffix2, repl] of step3) {
|
|
6024
|
+
if (w.endsWith(suffix2)) {
|
|
6025
|
+
if (w.length - suffix2.length >= r1) w = w.slice(0, -suffix2.length) + repl;
|
|
5846
6026
|
break;
|
|
5847
6027
|
}
|
|
5848
6028
|
}
|
|
@@ -5868,9 +6048,9 @@ function stemEnglish(input) {
|
|
|
5868
6048
|
"er",
|
|
5869
6049
|
"ic"
|
|
5870
6050
|
];
|
|
5871
|
-
for (const
|
|
5872
|
-
if (w.endsWith(
|
|
5873
|
-
if (w.length -
|
|
6051
|
+
for (const suffix2 of step4) {
|
|
6052
|
+
if (w.endsWith(suffix2)) {
|
|
6053
|
+
if (w.length - suffix2.length >= r2) w = w.slice(0, -suffix2.length);
|
|
5874
6054
|
break;
|
|
5875
6055
|
}
|
|
5876
6056
|
}
|
|
@@ -8078,6 +8258,12 @@ var invalidName = () => {
|
|
|
8078
8258
|
throw pgError("syntax", "invalid name syntax", "42602");
|
|
8079
8259
|
};
|
|
8080
8260
|
function parseNamespaceInput(text) {
|
|
8261
|
+
const parsed = parseRelationInput(text);
|
|
8262
|
+
if ("oid" in parsed) return parsed;
|
|
8263
|
+
if (parsed.parts.length !== 1) invalidName();
|
|
8264
|
+
return { name: parsed.parts[0] };
|
|
8265
|
+
}
|
|
8266
|
+
function parseRelationInput(text) {
|
|
8081
8267
|
if (text === "-") return { oid: 0 };
|
|
8082
8268
|
if (/^\d+$/.test(text)) return { oid: parseOidText(text) };
|
|
8083
8269
|
const names = [];
|
|
@@ -8113,8 +8299,8 @@ function parseNamespaceInput(text) {
|
|
|
8113
8299
|
skipSpace();
|
|
8114
8300
|
if (at === text.length) invalidName();
|
|
8115
8301
|
}
|
|
8116
|
-
if (names.length
|
|
8117
|
-
return {
|
|
8302
|
+
if (names.length === 0 || names.length > 3) invalidName();
|
|
8303
|
+
return { parts: names };
|
|
8118
8304
|
}
|
|
8119
8305
|
function namespaceText(oid, name2) {
|
|
8120
8306
|
if (oid === 0) return "-";
|
|
@@ -8187,6 +8373,7 @@ var TYPE_ALIASES = {
|
|
|
8187
8373
|
regtype: "regtype",
|
|
8188
8374
|
regproc: "regproc",
|
|
8189
8375
|
regnamespace: "regnamespace",
|
|
8376
|
+
xid: "xid",
|
|
8190
8377
|
oid: "oid",
|
|
8191
8378
|
void: "void",
|
|
8192
8379
|
record: "record",
|
|
@@ -8263,6 +8450,7 @@ var TYPE_OIDS = {
|
|
|
8263
8450
|
regproc: 24,
|
|
8264
8451
|
text: 25,
|
|
8265
8452
|
oid: 26,
|
|
8453
|
+
xid: 28,
|
|
8266
8454
|
json: 114,
|
|
8267
8455
|
float4: 700,
|
|
8268
8456
|
float8: 701,
|
|
@@ -8582,6 +8770,7 @@ function recordText(rec, ctx) {
|
|
|
8582
8770
|
return `(${parts.join(",")})`;
|
|
8583
8771
|
}
|
|
8584
8772
|
function datumText(t, v, ctx) {
|
|
8773
|
+
if (t === "regclass") return v === 0 ? "-" : ctx.relationName?.(v) ?? String(v);
|
|
8585
8774
|
if (t === "regnamespace") return namespaceText(v, ctx.namespaceName?.(v));
|
|
8586
8775
|
if (v === null) throw pgError("internal", "datumText called with null");
|
|
8587
8776
|
if (isArrayType(t)) return arrayText(v, ctx);
|
|
@@ -8592,6 +8781,7 @@ function datumText(t, v, ctx) {
|
|
|
8592
8781
|
case "int2":
|
|
8593
8782
|
case "int4":
|
|
8594
8783
|
case "oid":
|
|
8784
|
+
case "xid":
|
|
8595
8785
|
return String(v);
|
|
8596
8786
|
case "int8":
|
|
8597
8787
|
return String(v);
|
|
@@ -8656,6 +8846,12 @@ function datumText(t, v, ctx) {
|
|
|
8656
8846
|
}
|
|
8657
8847
|
var UTC_INPUT = { zoneOffsetForNaive: () => 0 };
|
|
8658
8848
|
function datumFromText(t, text, ctx) {
|
|
8849
|
+
if (t === "regclass") {
|
|
8850
|
+
const parsed = parseRelationInput(text);
|
|
8851
|
+
if ("oid" in parsed) return parsed.oid;
|
|
8852
|
+
if (!ctx.relationOid) throw unsupported("regclass input without a catalog");
|
|
8853
|
+
return ctx.relationOid(parsed.parts);
|
|
8854
|
+
}
|
|
8659
8855
|
if (t === "regnamespace") {
|
|
8660
8856
|
const parsed = parseNamespaceInput(text);
|
|
8661
8857
|
if ("oid" in parsed) return parsed.oid;
|
|
@@ -8677,6 +8873,7 @@ function datumFromText(t, text, ctx) {
|
|
|
8677
8873
|
case "int8":
|
|
8678
8874
|
return parseIntegerText(text, t);
|
|
8679
8875
|
case "oid":
|
|
8876
|
+
case "xid":
|
|
8680
8877
|
return parseOidText(text);
|
|
8681
8878
|
case "float4":
|
|
8682
8879
|
return Math.fround(parseFloatText(text, "float4"));
|
|
@@ -8833,6 +9030,8 @@ var TableData = class _TableData {
|
|
|
8833
9030
|
schema;
|
|
8834
9031
|
columns;
|
|
8835
9032
|
rows;
|
|
9033
|
+
rowXmins = /* @__PURE__ */ new WeakMap();
|
|
9034
|
+
slabXmins = null;
|
|
8836
9035
|
/** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
|
|
8837
9036
|
slab = null;
|
|
8838
9037
|
constraints;
|
|
@@ -8875,6 +9074,11 @@ var TableData = class _TableData {
|
|
|
8875
9074
|
materializeSlab() {
|
|
8876
9075
|
if (!this.slab) return;
|
|
8877
9076
|
this.rows = this.slab.materialize();
|
|
9077
|
+
if (this.slabXmins)
|
|
9078
|
+
this.rows.forEach((row, index) => {
|
|
9079
|
+
this.rowXmins.set(row, this.slabXmins[index] ?? 2);
|
|
9080
|
+
});
|
|
9081
|
+
this.slabXmins = null;
|
|
8878
9082
|
this.slab = null;
|
|
8879
9083
|
this.indexStores = null;
|
|
8880
9084
|
}
|
|
@@ -8908,6 +9112,10 @@ var TableData = class _TableData {
|
|
|
8908
9112
|
} else {
|
|
8909
9113
|
t.rows = this.rows.map((r) => r.slice());
|
|
8910
9114
|
}
|
|
9115
|
+
t.rows.forEach((row, index) => {
|
|
9116
|
+
const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.rows[index]);
|
|
9117
|
+
if (xmin !== void 0) t.rowXmins.set(row, xmin);
|
|
9118
|
+
});
|
|
8911
9119
|
t.unlogged = this.unlogged;
|
|
8912
9120
|
t.constraints = this.constraints.map((c) => ({ ...c }));
|
|
8913
9121
|
t.triggers = this.triggers.map((tr) => ({ ...tr }));
|
|
@@ -8993,7 +9201,18 @@ var DatabaseState = class _DatabaseState {
|
|
|
8993
9201
|
clock;
|
|
8994
9202
|
changes = 0;
|
|
8995
9203
|
oidCounter = 16384;
|
|
9204
|
+
/** Local monotonic xid allocator; 2 denotes a row from a legacy snapshot without metadata. */
|
|
9205
|
+
xidCounter = 3;
|
|
9206
|
+
transactionXid = null;
|
|
9207
|
+
allocateXid() {
|
|
9208
|
+
if (this.xidCounter > 4294967295)
|
|
9209
|
+
throw pgError("program_limit_exceeded", "transaction ID space exhausted; xid wraparound is not modeled", "54000");
|
|
9210
|
+
return this.xidCounter++;
|
|
9211
|
+
}
|
|
8996
9212
|
inTransaction = false;
|
|
9213
|
+
/** Transaction-only events: included in rollback clones, never in exported snapshots. */
|
|
9214
|
+
pendingTriggers = [];
|
|
9215
|
+
constraintModes = /* @__PURE__ */ new Map();
|
|
8997
9216
|
/** most recent sequence touched by nextval/setval, for lastval() */
|
|
8998
9217
|
lastSequence = null;
|
|
8999
9218
|
/** Session currval per sequence; absent entry means currval is undefined. */
|
|
@@ -9036,6 +9255,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
9036
9255
|
this.settings.set("row_security", "on");
|
|
9037
9256
|
this.settings.set("array_nulls", "on");
|
|
9038
9257
|
this.settings.set("backslash_quote", "safe_encoding");
|
|
9258
|
+
this.settings.set("default_tablespace", "");
|
|
9259
|
+
this.settings.set("default_table_access_method", "heap");
|
|
9039
9260
|
}
|
|
9040
9261
|
nextOid() {
|
|
9041
9262
|
return this.oidCounter++;
|
|
@@ -9195,10 +9416,14 @@ var DatabaseState = class _DatabaseState {
|
|
|
9195
9416
|
s.prepared = new Map(this.prepared);
|
|
9196
9417
|
s.changes = this.changes;
|
|
9197
9418
|
s.inTransaction = this.inTransaction;
|
|
9419
|
+
s.pendingTriggers = this.pendingTriggers.slice();
|
|
9420
|
+
s.constraintModes = new Map(this.constraintModes);
|
|
9198
9421
|
s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
|
|
9199
9422
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
9200
9423
|
s.tableStats = new Map(this.tableStats);
|
|
9201
9424
|
s.oidCounter = this.oidCounter;
|
|
9425
|
+
s.xidCounter = this.xidCounter;
|
|
9426
|
+
s.transactionXid = this.transactionXid;
|
|
9202
9427
|
for (const [name2, overloads] of this.systemFunctions) s.systemFunctions.set(name2, overloads.slice());
|
|
9203
9428
|
return s;
|
|
9204
9429
|
}
|
|
@@ -9212,10 +9437,14 @@ var DatabaseState = class _DatabaseState {
|
|
|
9212
9437
|
s.prepared = new Map(this.prepared);
|
|
9213
9438
|
s.changes = this.changes;
|
|
9214
9439
|
s.inTransaction = this.inTransaction;
|
|
9440
|
+
s.pendingTriggers = this.pendingTriggers.slice();
|
|
9441
|
+
s.constraintModes = new Map(this.constraintModes);
|
|
9215
9442
|
s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
|
|
9216
9443
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
9217
9444
|
s.tableStats = new Map(this.tableStats);
|
|
9218
9445
|
s.oidCounter = this.oidCounter;
|
|
9446
|
+
s.xidCounter = this.xidCounter;
|
|
9447
|
+
s.transactionXid = this.transactionXid;
|
|
9219
9448
|
for (const [name2, overloads] of this.systemFunctions) s.systemFunctions.set(name2, overloads.slice());
|
|
9220
9449
|
return s;
|
|
9221
9450
|
}
|
|
@@ -9284,11 +9513,15 @@ var DatabaseState = class _DatabaseState {
|
|
|
9284
9513
|
this.settings = other.settings;
|
|
9285
9514
|
this.localSettings = other.localSettings;
|
|
9286
9515
|
this.prepared = other.prepared;
|
|
9516
|
+
this.pendingTriggers = other.pendingTriggers.slice();
|
|
9517
|
+
this.constraintModes = new Map(other.constraintModes);
|
|
9287
9518
|
this.changes = other.changes;
|
|
9288
9519
|
this.lastSequence = other.lastSequence;
|
|
9289
9520
|
this.sequenceCurrval = other.sequenceCurrval;
|
|
9290
9521
|
this.tableStats = other.tableStats;
|
|
9291
9522
|
this.oidCounter = other.oidCounter;
|
|
9523
|
+
this.xidCounter = Math.max(this.xidCounter, other.xidCounter);
|
|
9524
|
+
this.transactionXid = other.transactionXid;
|
|
9292
9525
|
}
|
|
9293
9526
|
/** @internal Snapshot codec access to the oid allocator. */
|
|
9294
9527
|
snapshotOidCounter() {
|
|
@@ -9300,91 +9533,215 @@ var DatabaseState = class _DatabaseState {
|
|
|
9300
9533
|
}
|
|
9301
9534
|
};
|
|
9302
9535
|
|
|
9303
|
-
// src/
|
|
9304
|
-
var
|
|
9305
|
-
|
|
9306
|
-
|
|
9536
|
+
// src/types/timezone.ts
|
|
9537
|
+
var intlCache = /* @__PURE__ */ new Map();
|
|
9538
|
+
function intlFor(zone) {
|
|
9539
|
+
const cached = intlCache.get(zone);
|
|
9540
|
+
if (cached) return cached;
|
|
9541
|
+
try {
|
|
9542
|
+
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
9543
|
+
timeZone: zone,
|
|
9544
|
+
timeZoneName: "longOffset",
|
|
9545
|
+
year: "numeric"
|
|
9546
|
+
});
|
|
9547
|
+
intlCache.set(zone, fmt);
|
|
9548
|
+
return fmt;
|
|
9549
|
+
} catch {
|
|
9550
|
+
return null;
|
|
9551
|
+
}
|
|
9552
|
+
}
|
|
9553
|
+
function parseFixedOffset(zone) {
|
|
9554
|
+
const m = /^([+-]?)(\d{1,2})(?::(\d{2}))?(?::(\d{2}))?$/.exec(zone.trim());
|
|
9555
|
+
if (!m) return null;
|
|
9556
|
+
const sign = m[1] === "-" ? -1 : 1;
|
|
9557
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60 + Number(m[4] ?? 0));
|
|
9558
|
+
}
|
|
9559
|
+
function parsePosixOffset(zone) {
|
|
9560
|
+
const m = /^(?:utc|gmt)([+-])(\d{1,2})(?::(\d{2}))?$/i.exec(zone.trim());
|
|
9561
|
+
if (!m) return null;
|
|
9562
|
+
const sign = m[1] === "-" ? 1 : -1;
|
|
9563
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60);
|
|
9564
|
+
}
|
|
9565
|
+
function pgMicrosToUnixMs(utcMicros) {
|
|
9566
|
+
return Number((utcMicros - UNIX_EPOCH_MICROS_FROM_PG) / 1000n);
|
|
9567
|
+
}
|
|
9568
|
+
function zoneOffsetAtUtc(zone, utcMicros) {
|
|
9569
|
+
const z = zone.trim();
|
|
9570
|
+
const lower = z.toLowerCase();
|
|
9571
|
+
if (lower === "utc" || lower === "gmt" || lower === "z" || lower === "zulu" || lower === "universal") return 0;
|
|
9572
|
+
const posix = parsePosixOffset(z);
|
|
9573
|
+
if (posix !== null) return posix;
|
|
9574
|
+
const fixed = parseFixedOffset(z);
|
|
9575
|
+
if (fixed !== null) return fixed;
|
|
9576
|
+
const fmt = intlFor(z);
|
|
9577
|
+
if (fmt) {
|
|
9578
|
+
const ms = clampDateMs(pgMicrosToUnixMs(utcMicros));
|
|
9579
|
+
const parts = fmt.formatToParts(new Date(ms));
|
|
9580
|
+
const tzName = parts.find((p) => p.type === "timeZoneName")?.value ?? "GMT";
|
|
9581
|
+
const m = /GMT([+-])(\d{2}):(\d{2})(?::(\d{2}))?/.exec(tzName);
|
|
9582
|
+
if (!m) return 0;
|
|
9583
|
+
const sign = m[1] === "-" ? -1 : 1;
|
|
9584
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60 + Number(m[4] ?? 0));
|
|
9307
9585
|
}
|
|
9586
|
+
throw pgError("invalid_parameter_value", `time zone "${zone}" not recognized`);
|
|
9587
|
+
}
|
|
9588
|
+
function clampDateMs(ms) {
|
|
9589
|
+
const MAX = 864e13;
|
|
9590
|
+
return Math.max(-MAX, Math.min(MAX, ms));
|
|
9591
|
+
}
|
|
9592
|
+
function zoneOffsetForNaive(zone, naiveMicros) {
|
|
9593
|
+
const first = zoneOffsetAtUtc(zone, naiveMicros);
|
|
9594
|
+
const second = zoneOffsetAtUtc(zone, naiveMicros - BigInt(first) * 1000000n);
|
|
9595
|
+
return second;
|
|
9596
|
+
}
|
|
9597
|
+
function validateZone(zone) {
|
|
9598
|
+
zoneOffsetAtUtc(zone, 0n);
|
|
9599
|
+
}
|
|
9600
|
+
|
|
9601
|
+
// src/expressions/context.ts
|
|
9602
|
+
var EngineCtx = class {
|
|
9308
9603
|
state;
|
|
9309
|
-
|
|
9310
|
-
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
return this.base !== null;
|
|
9604
|
+
writeXid = null;
|
|
9605
|
+
rowVersionXid() {
|
|
9606
|
+
if (this.state.inTransaction) return this.state.transactionXid ??= this.state.allocateXid();
|
|
9607
|
+
return this.writeXid ??= this.state.allocateXid();
|
|
9314
9608
|
}
|
|
9315
|
-
|
|
9316
|
-
|
|
9317
|
-
|
|
9318
|
-
|
|
9609
|
+
/** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
|
|
9610
|
+
txNow;
|
|
9611
|
+
/** statement timestamp */
|
|
9612
|
+
stmtNow;
|
|
9613
|
+
constructor(state, txNow) {
|
|
9614
|
+
this.state = state;
|
|
9615
|
+
const nowMs = state.clock().getTime();
|
|
9616
|
+
const nowMicros = BigInt(Math.round(nowMs)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG;
|
|
9617
|
+
this.txNow = txNow ?? nowMicros;
|
|
9618
|
+
this.stmtNow = nowMicros;
|
|
9319
9619
|
}
|
|
9320
|
-
|
|
9321
|
-
this.state.
|
|
9322
|
-
this.state.prng.setState(snap.prngState);
|
|
9620
|
+
timezone() {
|
|
9621
|
+
return this.state.getSetting("timezone") ?? "UTC";
|
|
9323
9622
|
}
|
|
9324
|
-
|
|
9325
|
-
|
|
9326
|
-
|
|
9327
|
-
|
|
9328
|
-
}
|
|
9623
|
+
relationOid(parts) {
|
|
9624
|
+
const target = this.state.resolveRelationSchema(parts);
|
|
9625
|
+
const schema = target ? this.state.schemas.get(target.schema) : void 0;
|
|
9626
|
+
const relation = target ? schema?.sequences.get(target.name) ?? schema?.tables.get(target.name) ?? schema?.views.get(target.name) : void 0;
|
|
9627
|
+
if (!relation) throw pgError("undefined_table", `relation "${parts.join(".")}" does not exist`, "42P01");
|
|
9628
|
+
return relation.oid;
|
|
9329
9629
|
}
|
|
9330
|
-
|
|
9331
|
-
|
|
9332
|
-
|
|
9630
|
+
relationName(oid) {
|
|
9631
|
+
for (const schema of this.state.schemas.values()) {
|
|
9632
|
+
for (const relation of [...schema.tables.values(), ...schema.sequences.values(), ...schema.views.values()]) {
|
|
9633
|
+
if (relation.oid !== oid) continue;
|
|
9634
|
+
const visible = this.state.resolveRelationSchema([relation.name])?.schema === schema.name;
|
|
9635
|
+
return (visible ? [relation.name] : [schema.name, relation.name]).map(quoteIdentifier).join(".");
|
|
9636
|
+
}
|
|
9333
9637
|
}
|
|
9334
|
-
|
|
9335
|
-
this.state.inTransaction = true;
|
|
9336
|
-
assert(this.freezeDepth === 1, "BEGIN freeze depth");
|
|
9638
|
+
return null;
|
|
9337
9639
|
}
|
|
9338
|
-
|
|
9339
|
-
|
|
9340
|
-
|
|
9341
|
-
|
|
9342
|
-
this.state.localSettings.clear();
|
|
9343
|
-
while (this.freezeDepth > 0) this.thawOnce();
|
|
9640
|
+
namespaceOid(name2) {
|
|
9641
|
+
const oid = builtinNamespaceOid(name2) ?? this.state.schemas.get(name2)?.oid;
|
|
9642
|
+
if (oid === void 0) throw pgError("undefined_object", `schema "${name2}" does not exist`, "3F000");
|
|
9643
|
+
return oid;
|
|
9344
9644
|
}
|
|
9345
|
-
|
|
9346
|
-
|
|
9347
|
-
|
|
9645
|
+
namespaceName(oid) {
|
|
9646
|
+
const builtin = builtinNamespaceName(oid);
|
|
9647
|
+
if (builtin !== void 0) return builtin;
|
|
9648
|
+
for (const schema of this.state.schemas.values()) {
|
|
9649
|
+
if (schema.oid === oid) return schema.name;
|
|
9348
9650
|
}
|
|
9349
|
-
|
|
9350
|
-
this.savepoints = [];
|
|
9351
|
-
this.state.inTransaction = false;
|
|
9352
|
-
this.state.localSettings.clear();
|
|
9353
|
-
while (this.freezeDepth > 0) this.thawOnce();
|
|
9651
|
+
return null;
|
|
9354
9652
|
}
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
throw pgError("transaction_state", "SAVEPOINT can only be used in transaction blocks", "25P01");
|
|
9358
|
-
}
|
|
9359
|
-
this.savepoints.push({ name: name2, snap: this.takeSnapshot() });
|
|
9653
|
+
zoneOffsetAt(utcMicros) {
|
|
9654
|
+
return zoneOffsetAtUtc(this.timezone(), utcMicros);
|
|
9360
9655
|
}
|
|
9361
|
-
|
|
9362
|
-
|
|
9363
|
-
this.savepoints.splice(idx);
|
|
9656
|
+
zoneOffsetForNaive(naiveMicros) {
|
|
9657
|
+
return zoneOffsetForNaive(this.timezone(), naiveMicros);
|
|
9364
9658
|
}
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
const
|
|
9368
|
-
|
|
9369
|
-
this.savepoints.splice(idx + 1);
|
|
9659
|
+
enumLabels(enumType) {
|
|
9660
|
+
if (!isEnumType(enumType)) return null;
|
|
9661
|
+
const e = this.state.findEnumByKey(enumType.slice(5));
|
|
9662
|
+
return e?.labels ?? null;
|
|
9370
9663
|
}
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
}
|
|
9375
|
-
for (let i = this.savepoints.length - 1; i >= 0; i--) {
|
|
9376
|
-
if (this.savepoints[i].name === name2) return i;
|
|
9377
|
-
}
|
|
9378
|
-
throw pgError("invalid_savepoint_specification", `savepoint "${name2}" does not exist`, "3B001");
|
|
9664
|
+
enumHasLabel(enumType, label) {
|
|
9665
|
+
const labels = this.enumLabels(enumType);
|
|
9666
|
+
return labels === null ? true : labels.includes(label);
|
|
9379
9667
|
}
|
|
9380
|
-
|
|
9381
|
-
|
|
9382
|
-
|
|
9383
|
-
|
|
9384
|
-
|
|
9668
|
+
enumOrder(enumType, label) {
|
|
9669
|
+
const labels = this.enumLabels(enumType);
|
|
9670
|
+
if (!labels) return 0;
|
|
9671
|
+
const idx = labels.indexOf(label);
|
|
9672
|
+
return idx === -1 ? labels.length : idx;
|
|
9673
|
+
}
|
|
9674
|
+
requireEnum(enumType) {
|
|
9675
|
+
const labels = this.enumLabels(enumType);
|
|
9676
|
+
if (!labels) throw pgError("undefined_object", `type "${enumType.slice(5)}" does not exist`);
|
|
9677
|
+
return labels;
|
|
9385
9678
|
}
|
|
9386
9679
|
};
|
|
9387
9680
|
|
|
9681
|
+
// src/api/bind.ts
|
|
9682
|
+
var INT4_MIN2 = -2147483648;
|
|
9683
|
+
var INT4_MAX2 = 2147483647;
|
|
9684
|
+
function bindValueToTyped(value, index) {
|
|
9685
|
+
if (value === null || value === void 0) return tv(UNKNOWN, null);
|
|
9686
|
+
switch (typeof value) {
|
|
9687
|
+
case "boolean":
|
|
9688
|
+
return tv("bool", value);
|
|
9689
|
+
case "number":
|
|
9690
|
+
if (Number.isInteger(value) && value >= INT4_MIN2 && value <= INT4_MAX2) {
|
|
9691
|
+
return tv("int4", value);
|
|
9692
|
+
}
|
|
9693
|
+
if (Number.isInteger(value) && Number.isSafeInteger(value)) {
|
|
9694
|
+
return tv("int8", BigInt(value));
|
|
9695
|
+
}
|
|
9696
|
+
return tv("float8", value);
|
|
9697
|
+
case "bigint":
|
|
9698
|
+
if (value < -9223372036854775808n || value > 9223372036854775807n) {
|
|
9699
|
+
throw pgError("numeric_value_out_of_range", `bigint parameter $${index + 1} out of int8 range`, "22003");
|
|
9700
|
+
}
|
|
9701
|
+
return tv("int8", value);
|
|
9702
|
+
case "string":
|
|
9703
|
+
return tv(UNKNOWN, value);
|
|
9704
|
+
case "object": {
|
|
9705
|
+
if (value instanceof Uint8Array) return tv("bytea", value);
|
|
9706
|
+
if (value instanceof Date) {
|
|
9707
|
+
const ms = value.getTime();
|
|
9708
|
+
if (Number.isNaN(ms)) {
|
|
9709
|
+
throw pgError("invalid_datetime", `invalid Date parameter $${index + 1}`, "22008");
|
|
9710
|
+
}
|
|
9711
|
+
return tv("timestamptz", BigInt(Math.round(ms)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG);
|
|
9712
|
+
}
|
|
9713
|
+
break;
|
|
9714
|
+
}
|
|
9715
|
+
default:
|
|
9716
|
+
break;
|
|
9717
|
+
}
|
|
9718
|
+
throw pgError("misuse", `unsupported parameter type for $${index + 1}: ${typeof value}`, "XX000");
|
|
9719
|
+
}
|
|
9720
|
+
function datumToJs(t, v, ctx, int8 = "bigint") {
|
|
9721
|
+
if (v === null) return null;
|
|
9722
|
+
switch (t) {
|
|
9723
|
+
case "bool":
|
|
9724
|
+
return v;
|
|
9725
|
+
case "int2":
|
|
9726
|
+
case "int4":
|
|
9727
|
+
case "oid":
|
|
9728
|
+
return typeof v === "bigint" ? Number(v) : v;
|
|
9729
|
+
case "int8": {
|
|
9730
|
+
const n = typeof v === "bigint" ? v : BigInt(v);
|
|
9731
|
+
if (int8 === "string") return n.toString();
|
|
9732
|
+
if (int8 === "number") return Number(n);
|
|
9733
|
+
return n;
|
|
9734
|
+
}
|
|
9735
|
+
case "float4":
|
|
9736
|
+
case "float8":
|
|
9737
|
+
return v;
|
|
9738
|
+
case "bytea":
|
|
9739
|
+
return v;
|
|
9740
|
+
default:
|
|
9741
|
+
return datumText(t === UNKNOWN ? "text" : t, v, ctx);
|
|
9742
|
+
}
|
|
9743
|
+
}
|
|
9744
|
+
|
|
9388
9745
|
// src/types/cast.ts
|
|
9389
9746
|
var UTC_CAST_ENV = {
|
|
9390
9747
|
zoneOffsetAt: () => 0,
|
|
@@ -9580,7 +9937,7 @@ function castTo(env, value, target, opts = {}) {
|
|
|
9580
9937
|
return tv(target, makeArray(toElem, items, arr.dims.slice(), arr.lbs.slice()));
|
|
9581
9938
|
}
|
|
9582
9939
|
if (from === "oid" && target === "regnamespace") return tv(target, v);
|
|
9583
|
-
if (from === "regnamespace" && (target === "oid" || target === "int4" || target === "int8")) {
|
|
9940
|
+
if ((from === "regnamespace" || from === "regclass") && (target === "oid" || target === "int4" || target === "int8")) {
|
|
9584
9941
|
return tv(target, target === "int8" ? BigInt(v) : v);
|
|
9585
9942
|
}
|
|
9586
9943
|
if ((from === "int4" || from === "int8" || from === "int2") && (target === "oid" || target === "regnamespace")) {
|
|
@@ -9861,259 +10218,6 @@ function unifyTypes(a, b) {
|
|
|
9861
10218
|
return null;
|
|
9862
10219
|
}
|
|
9863
10220
|
|
|
9864
|
-
// src/types/resolve.ts
|
|
9865
|
-
var SERIALS = {
|
|
9866
|
-
smallserial: "int2",
|
|
9867
|
-
serial2: "int2",
|
|
9868
|
-
serial: "int4",
|
|
9869
|
-
serial4: "int4",
|
|
9870
|
-
bigserial: "int8",
|
|
9871
|
-
serial8: "int8"
|
|
9872
|
-
};
|
|
9873
|
-
function modOf(t, mods) {
|
|
9874
|
-
if (mods.length === 0) return null;
|
|
9875
|
-
if (t === "numeric") return { a: mods[0], b: mods[1] ?? 0 };
|
|
9876
|
-
return { a: mods[0] };
|
|
9877
|
-
}
|
|
9878
|
-
function resolveTypeName(state, tn) {
|
|
9879
|
-
const joined = tn.parts.join(".");
|
|
9880
|
-
const bare = tn.parts.length === 1 ? tn.parts[0] : tn.parts.length === 2 && tn.parts[0] === "pg_catalog" ? tn.parts[1] : null;
|
|
9881
|
-
if (bare !== null) {
|
|
9882
|
-
const serial = SERIALS[bare];
|
|
9883
|
-
if (serial !== void 0 && tn.arrayDims === 0) {
|
|
9884
|
-
return { column: { id: serial, mod: null }, domain: null, serial };
|
|
9885
|
-
}
|
|
9886
|
-
const builtin = normalizeTypeName(bare);
|
|
9887
|
-
if (builtin !== null) {
|
|
9888
|
-
const id = tn.arrayDims > 0 ? arrayTypeOf(builtin) : builtin;
|
|
9889
|
-
return { column: { id, mod: modOf(builtin, tn.mods) }, domain: null, serial: null };
|
|
9890
|
-
}
|
|
9891
|
-
}
|
|
9892
|
-
const enumData = state.findEnum(tn.parts);
|
|
9893
|
-
if (enumData) {
|
|
9894
|
-
const elem = `enum:${enumData.schema}.${enumData.name}`;
|
|
9895
|
-
const id = tn.arrayDims > 0 ? arrayTypeOf(elem) : elem;
|
|
9896
|
-
return { column: { id, mod: null }, domain: null, serial: null };
|
|
9897
|
-
}
|
|
9898
|
-
const domainData = state.findDomain(tn.parts);
|
|
9899
|
-
if (domainData) {
|
|
9900
|
-
if (tn.arrayDims > 0) {
|
|
9901
|
-
const id = arrayTypeOf(domainData.baseType.id);
|
|
9902
|
-
return { column: { id, mod: domainData.baseType.mod }, domain: null, serial: null };
|
|
9903
|
-
}
|
|
9904
|
-
return {
|
|
9905
|
-
column: domainData.baseType,
|
|
9906
|
-
domain: `${domainData.schema}.${domainData.name}`,
|
|
9907
|
-
serial: null
|
|
9908
|
-
};
|
|
9909
|
-
}
|
|
9910
|
-
throw pgError("undefined_object", `type "${joined}" does not exist`);
|
|
9911
|
-
}
|
|
9912
|
-
|
|
9913
|
-
// src/executor/relation.ts
|
|
9914
|
-
var RowScope = class {
|
|
9915
|
-
constructor(columns, row, parent = null, rangeVars = /* @__PURE__ */ new Set()) {
|
|
9916
|
-
this.columns = columns;
|
|
9917
|
-
this.row = row;
|
|
9918
|
-
this.parent = parent;
|
|
9919
|
-
this.rangeVars = rangeVars;
|
|
9920
|
-
}
|
|
9921
|
-
columns;
|
|
9922
|
-
row;
|
|
9923
|
-
parent;
|
|
9924
|
-
rangeVars;
|
|
9925
|
-
/** Resolve a (possibly qualified) column reference. undefined = not found. */
|
|
9926
|
-
lookup(parts) {
|
|
9927
|
-
if (parts.length === 1) {
|
|
9928
|
-
const name3 = parts[0];
|
|
9929
|
-
let found2;
|
|
9930
|
-
let count2 = 0;
|
|
9931
|
-
for (let i = 0; i < this.columns.length; i++) {
|
|
9932
|
-
const c = this.columns[i];
|
|
9933
|
-
if (c.name === name3 && !c.hidden) {
|
|
9934
|
-
count2++;
|
|
9935
|
-
if (count2 > 1) {
|
|
9936
|
-
throw pgError("ambiguous_column", `column reference "${name3}" is ambiguous`);
|
|
9937
|
-
}
|
|
9938
|
-
found2 = tv(c.type, this.row[i] ?? null);
|
|
9939
|
-
}
|
|
9940
|
-
}
|
|
9941
|
-
if (found2 !== void 0) return found2;
|
|
9942
|
-
if (this.rangeVars.has(name3)) {
|
|
9943
|
-
return this.wholeRow(name3);
|
|
9944
|
-
}
|
|
9945
|
-
return this.parent?.lookup(parts);
|
|
9946
|
-
}
|
|
9947
|
-
const table = parts[parts.length - 2];
|
|
9948
|
-
const name2 = parts[parts.length - 1];
|
|
9949
|
-
let found;
|
|
9950
|
-
let count = 0;
|
|
9951
|
-
for (let i = 0; i < this.columns.length; i++) {
|
|
9952
|
-
const c = this.columns[i];
|
|
9953
|
-
if (c.table === table && c.name === name2) {
|
|
9954
|
-
count++;
|
|
9955
|
-
if (count > 1) {
|
|
9956
|
-
throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
|
|
9957
|
-
}
|
|
9958
|
-
found = tv(c.type, this.row[i] ?? null);
|
|
9959
|
-
}
|
|
9960
|
-
}
|
|
9961
|
-
if (found !== void 0) return found;
|
|
9962
|
-
return this.parent?.lookup(parts);
|
|
9963
|
-
}
|
|
9964
|
-
/** Build a record value from all columns belonging to a range variable. */
|
|
9965
|
-
wholeRow(rangeVar) {
|
|
9966
|
-
const types = [];
|
|
9967
|
-
const values = [];
|
|
9968
|
-
const names = [];
|
|
9969
|
-
for (let i = 0; i < this.columns.length; i++) {
|
|
9970
|
-
const c = this.columns[i];
|
|
9971
|
-
if (c.table === rangeVar) {
|
|
9972
|
-
types.push(c.type);
|
|
9973
|
-
values.push(this.row[i] ?? null);
|
|
9974
|
-
names.push(c.name);
|
|
9975
|
-
}
|
|
9976
|
-
}
|
|
9977
|
-
if (types.length === 0) return void 0;
|
|
9978
|
-
return tv("record", { kind: "pgrecord", types, values, names });
|
|
9979
|
-
}
|
|
9980
|
-
hasRangeVar(name2) {
|
|
9981
|
-
if (this.rangeVars.has(name2)) return true;
|
|
9982
|
-
return this.parent?.hasRangeVar(name2) ?? false;
|
|
9983
|
-
}
|
|
9984
|
-
};
|
|
9985
|
-
function childEnv(env, outer) {
|
|
9986
|
-
return {
|
|
9987
|
-
ctx: env.ctx,
|
|
9988
|
-
params: env.params,
|
|
9989
|
-
ctes: env.ctes,
|
|
9990
|
-
outer,
|
|
9991
|
-
allowUnpopulatedMatviews: env.allowUnpopulatedMatviews
|
|
9992
|
-
};
|
|
9993
|
-
}
|
|
9994
|
-
function relationResult(rel3, command2) {
|
|
9995
|
-
const visible = rel3.columns.map((c, i) => ({ i, c })).filter(({ c }) => !c.hidden);
|
|
9996
|
-
return {
|
|
9997
|
-
columns: visible.map(({ c }) => ({ name: c.name, type: c.type })),
|
|
9998
|
-
rows: rel3.rows.map((r) => visible.map(({ i }) => r[i] ?? null)),
|
|
9999
|
-
command: command2,
|
|
10000
|
-
rowCount: rel3.rows.length
|
|
10001
|
-
};
|
|
10002
|
-
}
|
|
10003
|
-
function commandResult(command2, rowCount) {
|
|
10004
|
-
return { columns: [], rows: [], command: command2, rowCount };
|
|
10005
|
-
}
|
|
10006
|
-
function inferColumnName(e) {
|
|
10007
|
-
switch (e.type) {
|
|
10008
|
-
case "colref":
|
|
10009
|
-
return e.parts[e.parts.length - 1];
|
|
10010
|
-
case "func":
|
|
10011
|
-
return e.name[e.name.length - 1];
|
|
10012
|
-
case "cast": {
|
|
10013
|
-
const inner = inferColumnName(e.expr);
|
|
10014
|
-
if (inner !== "?column?") return inner;
|
|
10015
|
-
return e.target.parts[e.target.parts.length - 1];
|
|
10016
|
-
}
|
|
10017
|
-
case "collate":
|
|
10018
|
-
return inferColumnName(e.expr);
|
|
10019
|
-
case "case":
|
|
10020
|
-
return "case";
|
|
10021
|
-
case "array_ctor":
|
|
10022
|
-
case "array_query":
|
|
10023
|
-
return "array";
|
|
10024
|
-
case "row":
|
|
10025
|
-
return "row";
|
|
10026
|
-
case "subquery_expr":
|
|
10027
|
-
return e.kind === "exists" ? "exists" : "?column?";
|
|
10028
|
-
case "bool_lit":
|
|
10029
|
-
return "bool";
|
|
10030
|
-
case "extract":
|
|
10031
|
-
return "extract";
|
|
10032
|
-
case "position":
|
|
10033
|
-
return "position";
|
|
10034
|
-
case "substring_sql":
|
|
10035
|
-
return "substring";
|
|
10036
|
-
case "overlay":
|
|
10037
|
-
return "overlay";
|
|
10038
|
-
case "trim":
|
|
10039
|
-
return e.side === "leading" ? "ltrim" : e.side === "trailing" ? "rtrim" : "btrim";
|
|
10040
|
-
case "field_select":
|
|
10041
|
-
return e.field === "*" ? "?column?" : e.field;
|
|
10042
|
-
case "at_time_zone":
|
|
10043
|
-
return "timezone";
|
|
10044
|
-
case "grouping_func":
|
|
10045
|
-
return "grouping";
|
|
10046
|
-
case "subscript":
|
|
10047
|
-
return inferColumnName(e.base);
|
|
10048
|
-
default:
|
|
10049
|
-
return "?column?";
|
|
10050
|
-
}
|
|
10051
|
-
}
|
|
10052
|
-
|
|
10053
|
-
// src/api/bind.ts
|
|
10054
|
-
var INT4_MIN2 = -2147483648;
|
|
10055
|
-
var INT4_MAX2 = 2147483647;
|
|
10056
|
-
function bindValueToTyped(value, index) {
|
|
10057
|
-
if (value === null || value === void 0) return tv(UNKNOWN, null);
|
|
10058
|
-
switch (typeof value) {
|
|
10059
|
-
case "boolean":
|
|
10060
|
-
return tv("bool", value);
|
|
10061
|
-
case "number":
|
|
10062
|
-
if (Number.isInteger(value) && value >= INT4_MIN2 && value <= INT4_MAX2) {
|
|
10063
|
-
return tv("int4", value);
|
|
10064
|
-
}
|
|
10065
|
-
if (Number.isInteger(value) && Number.isSafeInteger(value)) {
|
|
10066
|
-
return tv("int8", BigInt(value));
|
|
10067
|
-
}
|
|
10068
|
-
return tv("float8", value);
|
|
10069
|
-
case "bigint":
|
|
10070
|
-
if (value < -9223372036854775808n || value > 9223372036854775807n) {
|
|
10071
|
-
throw pgError("numeric_value_out_of_range", `bigint parameter $${index + 1} out of int8 range`, "22003");
|
|
10072
|
-
}
|
|
10073
|
-
return tv("int8", value);
|
|
10074
|
-
case "string":
|
|
10075
|
-
return tv(UNKNOWN, value);
|
|
10076
|
-
case "object": {
|
|
10077
|
-
if (value instanceof Uint8Array) return tv("bytea", value);
|
|
10078
|
-
if (value instanceof Date) {
|
|
10079
|
-
const ms = value.getTime();
|
|
10080
|
-
if (Number.isNaN(ms)) {
|
|
10081
|
-
throw pgError("invalid_datetime", `invalid Date parameter $${index + 1}`, "22008");
|
|
10082
|
-
}
|
|
10083
|
-
return tv("timestamptz", BigInt(Math.round(ms)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG);
|
|
10084
|
-
}
|
|
10085
|
-
break;
|
|
10086
|
-
}
|
|
10087
|
-
default:
|
|
10088
|
-
break;
|
|
10089
|
-
}
|
|
10090
|
-
throw pgError("misuse", `unsupported parameter type for $${index + 1}: ${typeof value}`, "XX000");
|
|
10091
|
-
}
|
|
10092
|
-
function datumToJs(t, v, ctx, int8 = "bigint") {
|
|
10093
|
-
if (v === null) return null;
|
|
10094
|
-
switch (t) {
|
|
10095
|
-
case "bool":
|
|
10096
|
-
return v;
|
|
10097
|
-
case "int2":
|
|
10098
|
-
case "int4":
|
|
10099
|
-
case "oid":
|
|
10100
|
-
return typeof v === "bigint" ? Number(v) : v;
|
|
10101
|
-
case "int8": {
|
|
10102
|
-
const n = typeof v === "bigint" ? v : BigInt(v);
|
|
10103
|
-
if (int8 === "string") return n.toString();
|
|
10104
|
-
if (int8 === "number") return Number(n);
|
|
10105
|
-
return n;
|
|
10106
|
-
}
|
|
10107
|
-
case "float4":
|
|
10108
|
-
case "float8":
|
|
10109
|
-
return v;
|
|
10110
|
-
case "bytea":
|
|
10111
|
-
return v;
|
|
10112
|
-
default:
|
|
10113
|
-
return datumText(t === UNKNOWN ? "text" : t, v, ctx);
|
|
10114
|
-
}
|
|
10115
|
-
}
|
|
10116
|
-
|
|
10117
10221
|
// src/functions/datetime-fns.ts
|
|
10118
10222
|
function extractDatePart(ctx, field0, src0, asNumeric) {
|
|
10119
10223
|
const field = field0.toLowerCase();
|
|
@@ -10534,6 +10638,8 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
|
|
|
10534
10638
|
case "int2":
|
|
10535
10639
|
case "int4":
|
|
10536
10640
|
case "oid":
|
|
10641
|
+
case "regclass":
|
|
10642
|
+
case "xid":
|
|
10537
10643
|
case "regnamespace":
|
|
10538
10644
|
case "date":
|
|
10539
10645
|
return expectNumber(a, t) - expectNumber(b, t);
|
|
@@ -10653,6 +10759,8 @@ function datumKey(t, v) {
|
|
|
10653
10759
|
case "int2":
|
|
10654
10760
|
case "int4":
|
|
10655
10761
|
case "oid":
|
|
10762
|
+
case "regclass":
|
|
10763
|
+
case "xid":
|
|
10656
10764
|
case "date":
|
|
10657
10765
|
return `i${v}`;
|
|
10658
10766
|
case "float4":
|
|
@@ -11028,71 +11136,6 @@ function getArrayFunctions() {
|
|
|
11028
11136
|
return m;
|
|
11029
11137
|
}
|
|
11030
11138
|
|
|
11031
|
-
// src/types/timezone.ts
|
|
11032
|
-
var intlCache = /* @__PURE__ */ new Map();
|
|
11033
|
-
function intlFor(zone) {
|
|
11034
|
-
const cached = intlCache.get(zone);
|
|
11035
|
-
if (cached) return cached;
|
|
11036
|
-
try {
|
|
11037
|
-
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
11038
|
-
timeZone: zone,
|
|
11039
|
-
timeZoneName: "longOffset",
|
|
11040
|
-
year: "numeric"
|
|
11041
|
-
});
|
|
11042
|
-
intlCache.set(zone, fmt);
|
|
11043
|
-
return fmt;
|
|
11044
|
-
} catch {
|
|
11045
|
-
return null;
|
|
11046
|
-
}
|
|
11047
|
-
}
|
|
11048
|
-
function parseFixedOffset(zone) {
|
|
11049
|
-
const m = /^([+-]?)(\d{1,2})(?::(\d{2}))?(?::(\d{2}))?$/.exec(zone.trim());
|
|
11050
|
-
if (!m) return null;
|
|
11051
|
-
const sign = m[1] === "-" ? -1 : 1;
|
|
11052
|
-
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60 + Number(m[4] ?? 0));
|
|
11053
|
-
}
|
|
11054
|
-
function parsePosixOffset(zone) {
|
|
11055
|
-
const m = /^(?:utc|gmt)([+-])(\d{1,2})(?::(\d{2}))?$/i.exec(zone.trim());
|
|
11056
|
-
if (!m) return null;
|
|
11057
|
-
const sign = m[1] === "-" ? 1 : -1;
|
|
11058
|
-
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60);
|
|
11059
|
-
}
|
|
11060
|
-
function pgMicrosToUnixMs(utcMicros) {
|
|
11061
|
-
return Number((utcMicros - UNIX_EPOCH_MICROS_FROM_PG) / 1000n);
|
|
11062
|
-
}
|
|
11063
|
-
function zoneOffsetAtUtc(zone, utcMicros) {
|
|
11064
|
-
const z = zone.trim();
|
|
11065
|
-
const lower = z.toLowerCase();
|
|
11066
|
-
if (lower === "utc" || lower === "gmt" || lower === "z" || lower === "zulu" || lower === "universal") return 0;
|
|
11067
|
-
const posix = parsePosixOffset(z);
|
|
11068
|
-
if (posix !== null) return posix;
|
|
11069
|
-
const fixed = parseFixedOffset(z);
|
|
11070
|
-
if (fixed !== null) return fixed;
|
|
11071
|
-
const fmt = intlFor(z);
|
|
11072
|
-
if (fmt) {
|
|
11073
|
-
const ms = clampDateMs(pgMicrosToUnixMs(utcMicros));
|
|
11074
|
-
const parts = fmt.formatToParts(new Date(ms));
|
|
11075
|
-
const tzName = parts.find((p) => p.type === "timeZoneName")?.value ?? "GMT";
|
|
11076
|
-
const m = /GMT([+-])(\d{2}):(\d{2})(?::(\d{2}))?/.exec(tzName);
|
|
11077
|
-
if (!m) return 0;
|
|
11078
|
-
const sign = m[1] === "-" ? -1 : 1;
|
|
11079
|
-
return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60 + Number(m[4] ?? 0));
|
|
11080
|
-
}
|
|
11081
|
-
throw pgError("invalid_parameter_value", `time zone "${zone}" not recognized`);
|
|
11082
|
-
}
|
|
11083
|
-
function clampDateMs(ms) {
|
|
11084
|
-
const MAX = 864e13;
|
|
11085
|
-
return Math.max(-MAX, Math.min(MAX, ms));
|
|
11086
|
-
}
|
|
11087
|
-
function zoneOffsetForNaive(zone, naiveMicros) {
|
|
11088
|
-
const first = zoneOffsetAtUtc(zone, naiveMicros);
|
|
11089
|
-
const second = zoneOffsetAtUtc(zone, naiveMicros - BigInt(first) * 1000000n);
|
|
11090
|
-
return second;
|
|
11091
|
-
}
|
|
11092
|
-
function validateZone(zone) {
|
|
11093
|
-
zoneOffsetAtUtc(zone, 0n);
|
|
11094
|
-
}
|
|
11095
|
-
|
|
11096
11139
|
// src/functions/datetime-registry.ts
|
|
11097
11140
|
function getDatetimeFunctions() {
|
|
11098
11141
|
const m = /* @__PURE__ */ new Map();
|
|
@@ -11601,8 +11644,8 @@ function toCharTimestamp(ctx, localMicros, fmt, tzOffsetSec) {
|
|
|
11601
11644
|
else if (tryPat("TH") || tryPat("th")) {
|
|
11602
11645
|
const prev = /(\d+)$/.exec(out);
|
|
11603
11646
|
const n = prev ? Number.parseInt(prev[1], 10) : 0;
|
|
11604
|
-
const
|
|
11605
|
-
out += rest.startsWith("TH") ?
|
|
11647
|
+
const suffix2 = ordinalSuffix(n);
|
|
11648
|
+
out += rest.startsWith("TH") ? suffix2.toUpperCase() : suffix2;
|
|
11606
11649
|
} else {
|
|
11607
11650
|
out += fmt[i];
|
|
11608
11651
|
i++;
|
|
@@ -12692,6 +12735,28 @@ function exactDegTan(x) {
|
|
|
12692
12735
|
return Math.tan(x * Math.PI / 180);
|
|
12693
12736
|
}
|
|
12694
12737
|
|
|
12738
|
+
// src/storage/indexable-relation.ts
|
|
12739
|
+
function materializedTable(view) {
|
|
12740
|
+
const table = new TableData(
|
|
12741
|
+
view.schema,
|
|
12742
|
+
view.name,
|
|
12743
|
+
(view.matColumns ?? []).map((c) => ({
|
|
12744
|
+
name: c.name,
|
|
12745
|
+
type: { id: c.type, mod: null },
|
|
12746
|
+
notNull: false,
|
|
12747
|
+
defaultExpr: null,
|
|
12748
|
+
identity: null,
|
|
12749
|
+
generated: null,
|
|
12750
|
+
collate: null,
|
|
12751
|
+
domain: null
|
|
12752
|
+
})),
|
|
12753
|
+
view.oid,
|
|
12754
|
+
view.temp
|
|
12755
|
+
);
|
|
12756
|
+
table.rows = view.matRows ?? [];
|
|
12757
|
+
return table;
|
|
12758
|
+
}
|
|
12759
|
+
|
|
12695
12760
|
// src/schema/index-catalog.ts
|
|
12696
12761
|
var isKeyConstraint = (constraint) => constraint.kind === "primary_key" || constraint.kind === "unique";
|
|
12697
12762
|
var ACCESS_METHODS = /* @__PURE__ */ new Map([
|
|
@@ -12720,6 +12785,8 @@ function syncIndexCatalog(state) {
|
|
|
12720
12785
|
const tables = /* @__PURE__ */ new Map();
|
|
12721
12786
|
for (const schema of state.schemas.values()) {
|
|
12722
12787
|
for (const table of schema.tables.values()) tables.set(table.oid, { schema, table });
|
|
12788
|
+
for (const view of schema.views.values())
|
|
12789
|
+
if (view.materialized) tables.set(view.oid, { schema, table: materializedTable(view) });
|
|
12723
12790
|
}
|
|
12724
12791
|
const backing = /* @__PURE__ */ new Map();
|
|
12725
12792
|
for (const { table } of tables.values()) {
|
|
@@ -12797,7 +12864,7 @@ function claimConstraintIndexName(schema, constraint, explicit, reserved = /* @_
|
|
|
12797
12864
|
if (used(constraint.name)) {
|
|
12798
12865
|
if (explicit) throw pgError("duplicate_table", `relation "${constraint.name}" already exists`, "42P07");
|
|
12799
12866
|
const base = constraint.name;
|
|
12800
|
-
for (let
|
|
12867
|
+
for (let suffix2 = 1; used(constraint.name); suffix2++) constraint.name = `${base}${suffix2}`;
|
|
12801
12868
|
}
|
|
12802
12869
|
reserved.add(constraint.name);
|
|
12803
12870
|
}
|
|
@@ -12917,6 +12984,55 @@ function deparseExpr(e) {
|
|
|
12917
12984
|
}
|
|
12918
12985
|
}
|
|
12919
12986
|
|
|
12987
|
+
// src/types/resolve.ts
|
|
12988
|
+
var SERIALS = {
|
|
12989
|
+
smallserial: "int2",
|
|
12990
|
+
serial2: "int2",
|
|
12991
|
+
serial: "int4",
|
|
12992
|
+
serial4: "int4",
|
|
12993
|
+
bigserial: "int8",
|
|
12994
|
+
serial8: "int8"
|
|
12995
|
+
};
|
|
12996
|
+
function modOf(t, mods) {
|
|
12997
|
+
if (mods.length === 0) return null;
|
|
12998
|
+
if (t === "numeric") return { a: mods[0], b: mods[1] ?? 0 };
|
|
12999
|
+
return { a: mods[0] };
|
|
13000
|
+
}
|
|
13001
|
+
function resolveTypeName(state, tn) {
|
|
13002
|
+
const joined = tn.parts.join(".");
|
|
13003
|
+
const bare = tn.parts.length === 1 ? tn.parts[0] : tn.parts.length === 2 && tn.parts[0] === "pg_catalog" ? tn.parts[1] : null;
|
|
13004
|
+
if (bare !== null) {
|
|
13005
|
+
const serial = SERIALS[bare];
|
|
13006
|
+
if (serial !== void 0 && tn.arrayDims === 0) {
|
|
13007
|
+
return { column: { id: serial, mod: null }, domain: null, serial };
|
|
13008
|
+
}
|
|
13009
|
+
const builtin = normalizeTypeName(bare);
|
|
13010
|
+
if (builtin !== null) {
|
|
13011
|
+
const id = tn.arrayDims > 0 ? arrayTypeOf(builtin) : builtin;
|
|
13012
|
+
return { column: { id, mod: modOf(builtin, tn.mods) }, domain: null, serial: null };
|
|
13013
|
+
}
|
|
13014
|
+
}
|
|
13015
|
+
const enumData = state.findEnum(tn.parts);
|
|
13016
|
+
if (enumData) {
|
|
13017
|
+
const elem = `enum:${enumData.schema}.${enumData.name}`;
|
|
13018
|
+
const id = tn.arrayDims > 0 ? arrayTypeOf(elem) : elem;
|
|
13019
|
+
return { column: { id, mod: null }, domain: null, serial: null };
|
|
13020
|
+
}
|
|
13021
|
+
const domainData = state.findDomain(tn.parts);
|
|
13022
|
+
if (domainData) {
|
|
13023
|
+
if (tn.arrayDims > 0) {
|
|
13024
|
+
const id = arrayTypeOf(domainData.baseType.id);
|
|
13025
|
+
return { column: { id, mod: domainData.baseType.mod }, domain: null, serial: null };
|
|
13026
|
+
}
|
|
13027
|
+
return {
|
|
13028
|
+
column: domainData.baseType,
|
|
13029
|
+
domain: `${domainData.schema}.${domainData.name}`,
|
|
13030
|
+
serial: null
|
|
13031
|
+
};
|
|
13032
|
+
}
|
|
13033
|
+
throw pgError("undefined_object", `type "${joined}" does not exist`);
|
|
13034
|
+
}
|
|
13035
|
+
|
|
12920
13036
|
// src/sql/ruleutils.ts
|
|
12921
13037
|
var BOOL = "bool";
|
|
12922
13038
|
var TEXT = "text";
|
|
@@ -13553,7 +13669,7 @@ function setDatabaseCatalogContext(state, context) {
|
|
|
13553
13669
|
var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
|
|
13554
13670
|
function findSequenceForCall(ctx, name2) {
|
|
13555
13671
|
const parts = parseQualifiedName(name2);
|
|
13556
|
-
const seq = ctx.state.findSequence(parts);
|
|
13672
|
+
const seq = /^\d+$/.test(name2) ? [...ctx.state.schemas.values()].flatMap((schema) => [...schema.sequences.values()]).find((sequence) => sequence.oid === Number(name2)) : ctx.state.findSequence(parts);
|
|
13557
13673
|
if (!seq) {
|
|
13558
13674
|
throw pgError("undefined_table", `relation "${name2}" does not exist`, "42P01");
|
|
13559
13675
|
}
|
|
@@ -13714,7 +13830,11 @@ function getMiscFunctions() {
|
|
|
13714
13830
|
}
|
|
13715
13831
|
const name2 = argText(ctx, args2[0]).toLowerCase();
|
|
13716
13832
|
const value = args2[1].v === null ? "" : argText(ctx, args2[1]);
|
|
13717
|
-
ctx.state.settings.
|
|
13833
|
+
if (!ctx.state.settings.has(name2) && !name2.includes("."))
|
|
13834
|
+
throw pgError("undefined_object", `unrecognized configuration parameter "${name2}"`, "42704");
|
|
13835
|
+
validateStorageSetting(name2, value);
|
|
13836
|
+
const local = args2[2]?.v === true;
|
|
13837
|
+
if (!local || ctx.state.inTransaction) (local ? ctx.state.localSettings : ctx.state.settings).set(name2, value);
|
|
13718
13838
|
return tv("text", value);
|
|
13719
13839
|
});
|
|
13720
13840
|
m.set(
|
|
@@ -13773,17 +13893,16 @@ function getMiscFunctions() {
|
|
|
13773
13893
|
"pg_get_serial_sequence",
|
|
13774
13894
|
strict("text", (ctx, args2) => {
|
|
13775
13895
|
const tableName2 = argText(ctx, args2[0]);
|
|
13776
|
-
const column = argText(ctx, args2[1])
|
|
13896
|
+
const column = argText(ctx, args2[1]);
|
|
13777
13897
|
const table = ctx.state.findTable(parseQualifiedName(tableName2));
|
|
13778
13898
|
if (!table) throw pgError("undefined_table", `relation "${tableName2}" does not exist`, "42P01");
|
|
13779
13899
|
const col = table.columns.find((c) => c.name === column);
|
|
13780
13900
|
if (!col)
|
|
13781
13901
|
throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
|
|
13782
|
-
|
|
13783
|
-
|
|
13784
|
-
"text",
|
|
13785
|
-
col.identity.sequence.split(".").map(quoteIdent).join(".")
|
|
13902
|
+
const seq = [...ctx.state.schemas.get(table.schema)?.sequences.values() ?? []].find(
|
|
13903
|
+
(candidate) => candidate.ownedBy?.table === table.name && candidate.ownedBy.column === column
|
|
13786
13904
|
);
|
|
13905
|
+
return tv("text", seq ? [seq.schema, seq.name].map(quoteIdent).join(".") : null);
|
|
13787
13906
|
})
|
|
13788
13907
|
);
|
|
13789
13908
|
m.set("format_type", (ctx, args2) => {
|
|
@@ -18707,6 +18826,146 @@ function isSrfName(name2) {
|
|
|
18707
18826
|
return SRFS.has(name2);
|
|
18708
18827
|
}
|
|
18709
18828
|
|
|
18829
|
+
// src/executor/relation.ts
|
|
18830
|
+
var RowScope = class {
|
|
18831
|
+
constructor(columns, row, parent = null, rangeVars = /* @__PURE__ */ new Set()) {
|
|
18832
|
+
this.columns = columns;
|
|
18833
|
+
this.row = row;
|
|
18834
|
+
this.parent = parent;
|
|
18835
|
+
this.rangeVars = rangeVars;
|
|
18836
|
+
}
|
|
18837
|
+
columns;
|
|
18838
|
+
row;
|
|
18839
|
+
parent;
|
|
18840
|
+
rangeVars;
|
|
18841
|
+
/** Resolve a (possibly qualified) column reference. undefined = not found. */
|
|
18842
|
+
lookup(parts) {
|
|
18843
|
+
if (parts.length === 1) {
|
|
18844
|
+
const name3 = parts[0];
|
|
18845
|
+
let found2;
|
|
18846
|
+
let count2 = 0;
|
|
18847
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
18848
|
+
const c = this.columns[i];
|
|
18849
|
+
if (c.name === name3 && (!c.hidden || c.system)) {
|
|
18850
|
+
count2++;
|
|
18851
|
+
if (count2 > 1) {
|
|
18852
|
+
throw pgError("ambiguous_column", `column reference "${name3}" is ambiguous`);
|
|
18853
|
+
}
|
|
18854
|
+
found2 = tv(c.type, this.row[i] ?? null);
|
|
18855
|
+
}
|
|
18856
|
+
}
|
|
18857
|
+
if (found2 !== void 0) return found2;
|
|
18858
|
+
if (this.rangeVars.has(name3)) {
|
|
18859
|
+
return this.wholeRow(name3);
|
|
18860
|
+
}
|
|
18861
|
+
return this.parent?.lookup(parts);
|
|
18862
|
+
}
|
|
18863
|
+
const table = parts[parts.length - 2];
|
|
18864
|
+
const name2 = parts[parts.length - 1];
|
|
18865
|
+
let found;
|
|
18866
|
+
let count = 0;
|
|
18867
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
18868
|
+
const c = this.columns[i];
|
|
18869
|
+
if (c.table === table && c.name === name2) {
|
|
18870
|
+
count++;
|
|
18871
|
+
if (count > 1) {
|
|
18872
|
+
throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
|
|
18873
|
+
}
|
|
18874
|
+
found = tv(c.type, this.row[i] ?? null);
|
|
18875
|
+
}
|
|
18876
|
+
}
|
|
18877
|
+
if (found !== void 0) return found;
|
|
18878
|
+
return this.parent?.lookup(parts);
|
|
18879
|
+
}
|
|
18880
|
+
/** Build a record value from all columns belonging to a range variable. */
|
|
18881
|
+
wholeRow(rangeVar) {
|
|
18882
|
+
const types = [];
|
|
18883
|
+
const values = [];
|
|
18884
|
+
const names = [];
|
|
18885
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
18886
|
+
const c = this.columns[i];
|
|
18887
|
+
if (c.table === rangeVar && !c.system) {
|
|
18888
|
+
types.push(c.type);
|
|
18889
|
+
values.push(this.row[i] ?? null);
|
|
18890
|
+
names.push(c.name);
|
|
18891
|
+
}
|
|
18892
|
+
}
|
|
18893
|
+
if (types.length === 0) return void 0;
|
|
18894
|
+
return tv("record", { kind: "pgrecord", types, values, names });
|
|
18895
|
+
}
|
|
18896
|
+
hasRangeVar(name2) {
|
|
18897
|
+
if (this.rangeVars.has(name2)) return true;
|
|
18898
|
+
return this.parent?.hasRangeVar(name2) ?? false;
|
|
18899
|
+
}
|
|
18900
|
+
};
|
|
18901
|
+
function childEnv(env, outer) {
|
|
18902
|
+
return {
|
|
18903
|
+
ctx: env.ctx,
|
|
18904
|
+
params: env.params,
|
|
18905
|
+
ctes: env.ctes,
|
|
18906
|
+
outer,
|
|
18907
|
+
allowUnpopulatedMatviews: env.allowUnpopulatedMatviews
|
|
18908
|
+
};
|
|
18909
|
+
}
|
|
18910
|
+
function relationResult(rel3, command2) {
|
|
18911
|
+
const visible = rel3.columns.map((c, i) => ({ i, c })).filter(({ c }) => !c.hidden);
|
|
18912
|
+
return {
|
|
18913
|
+
columns: visible.map(({ c }) => ({ name: c.name, type: c.type })),
|
|
18914
|
+
rows: rel3.rows.map((r) => visible.map(({ i }) => r[i] ?? null)),
|
|
18915
|
+
command: command2,
|
|
18916
|
+
rowCount: rel3.rows.length
|
|
18917
|
+
};
|
|
18918
|
+
}
|
|
18919
|
+
function commandResult(command2, rowCount) {
|
|
18920
|
+
return { columns: [], rows: [], command: command2, rowCount };
|
|
18921
|
+
}
|
|
18922
|
+
function inferColumnName(e) {
|
|
18923
|
+
switch (e.type) {
|
|
18924
|
+
case "colref":
|
|
18925
|
+
return e.parts[e.parts.length - 1];
|
|
18926
|
+
case "func":
|
|
18927
|
+
return e.name[e.name.length - 1];
|
|
18928
|
+
case "cast": {
|
|
18929
|
+
const inner = inferColumnName(e.expr);
|
|
18930
|
+
if (inner !== "?column?") return inner;
|
|
18931
|
+
return e.target.parts[e.target.parts.length - 1];
|
|
18932
|
+
}
|
|
18933
|
+
case "collate":
|
|
18934
|
+
return inferColumnName(e.expr);
|
|
18935
|
+
case "case":
|
|
18936
|
+
return "case";
|
|
18937
|
+
case "array_ctor":
|
|
18938
|
+
case "array_query":
|
|
18939
|
+
return "array";
|
|
18940
|
+
case "row":
|
|
18941
|
+
return "row";
|
|
18942
|
+
case "subquery_expr":
|
|
18943
|
+
return e.kind === "exists" ? "exists" : "?column?";
|
|
18944
|
+
case "bool_lit":
|
|
18945
|
+
return "bool";
|
|
18946
|
+
case "extract":
|
|
18947
|
+
return "extract";
|
|
18948
|
+
case "position":
|
|
18949
|
+
return "position";
|
|
18950
|
+
case "substring_sql":
|
|
18951
|
+
return "substring";
|
|
18952
|
+
case "overlay":
|
|
18953
|
+
return "overlay";
|
|
18954
|
+
case "trim":
|
|
18955
|
+
return e.side === "leading" ? "ltrim" : e.side === "trailing" ? "rtrim" : "btrim";
|
|
18956
|
+
case "field_select":
|
|
18957
|
+
return e.field === "*" ? "?column?" : e.field;
|
|
18958
|
+
case "at_time_zone":
|
|
18959
|
+
return "timezone";
|
|
18960
|
+
case "grouping_func":
|
|
18961
|
+
return "grouping";
|
|
18962
|
+
case "subscript":
|
|
18963
|
+
return inferColumnName(e.base);
|
|
18964
|
+
default:
|
|
18965
|
+
return "?column?";
|
|
18966
|
+
}
|
|
18967
|
+
}
|
|
18968
|
+
|
|
18710
18969
|
// src/indexes/index.ts
|
|
18711
18970
|
var IndexStore = class _IndexStore {
|
|
18712
18971
|
name;
|
|
@@ -18818,6 +19077,181 @@ function rebuildTableIndexes(env, table) {
|
|
|
18818
19077
|
ensureIndexStores(env, table);
|
|
18819
19078
|
}
|
|
18820
19079
|
|
|
19080
|
+
// src/constraints/enforce.ts
|
|
19081
|
+
function tableScope(table, row) {
|
|
19082
|
+
const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
|
|
19083
|
+
return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
|
|
19084
|
+
}
|
|
19085
|
+
function checkNotNull(env, table, row) {
|
|
19086
|
+
void env;
|
|
19087
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
19088
|
+
const c = table.columns[i];
|
|
19089
|
+
if (c.notNull && (row[i] ?? null) === null) {
|
|
19090
|
+
throw pgError(
|
|
19091
|
+
"not_null_violation",
|
|
19092
|
+
`null value in column "${c.name}" of relation "${table.name}" violates not-null constraint`,
|
|
19093
|
+
"23502"
|
|
19094
|
+
);
|
|
19095
|
+
}
|
|
19096
|
+
}
|
|
19097
|
+
}
|
|
19098
|
+
function checkChecks(env, table, row) {
|
|
19099
|
+
for (const con of table.constraints) {
|
|
19100
|
+
if (con.kind !== "check") continue;
|
|
19101
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
19102
|
+
const v = evalExpr(env.ctx, scope, con.expr);
|
|
19103
|
+
if (v.v === null) continue;
|
|
19104
|
+
const b = castTo(env.ctx, v, "bool", {});
|
|
19105
|
+
if (b.v !== true) {
|
|
19106
|
+
throw pgError(
|
|
19107
|
+
"check_violation",
|
|
19108
|
+
`new row for relation "${table.name}" violates check constraint "${con.name}"`,
|
|
19109
|
+
"23514"
|
|
19110
|
+
);
|
|
19111
|
+
}
|
|
19112
|
+
}
|
|
19113
|
+
}
|
|
19114
|
+
function uniqueSpecsFor(env, table) {
|
|
19115
|
+
const specs = [];
|
|
19116
|
+
for (const con of table.constraints) {
|
|
19117
|
+
if (con.kind !== "primary_key" && con.kind !== "unique") continue;
|
|
19118
|
+
specs.push({
|
|
19119
|
+
name: con.name,
|
|
19120
|
+
keys: con.columns.map((c) => ({ colIdx: table.columnIndex(c), expr: null })),
|
|
19121
|
+
columnNames: con.columns,
|
|
19122
|
+
nullsNotDistinct: con.kind === "unique" ? con.nullsNotDistinct : false,
|
|
19123
|
+
where: null,
|
|
19124
|
+
isPrimary: con.kind === "primary_key"
|
|
19125
|
+
});
|
|
19126
|
+
}
|
|
19127
|
+
const schema = env.ctx.state.schemas.get(table.schema);
|
|
19128
|
+
if (schema) {
|
|
19129
|
+
for (const idx of schema.indexes.values()) {
|
|
19130
|
+
if (idx.table !== table.name || !idx.unique || idx.isConstraint || idx.valid === false) continue;
|
|
19131
|
+
specs.push(uniqueSpecOfIndex(table, idx));
|
|
19132
|
+
}
|
|
19133
|
+
}
|
|
19134
|
+
return specs;
|
|
19135
|
+
}
|
|
19136
|
+
function uniqueSpecOfIndex(table, idx) {
|
|
19137
|
+
return {
|
|
19138
|
+
name: idx.name,
|
|
19139
|
+
keys: idx.columns.map((c) => ({
|
|
19140
|
+
colIdx: c.column !== null ? table.columnIndex(c.column) : -1,
|
|
19141
|
+
expr: c.expr
|
|
19142
|
+
})),
|
|
19143
|
+
columnNames: idx.columns.map((c) => c.column ?? "expr"),
|
|
19144
|
+
nullsNotDistinct: idx.nullsNotDistinct,
|
|
19145
|
+
where: idx.where,
|
|
19146
|
+
isPrimary: false
|
|
19147
|
+
};
|
|
19148
|
+
}
|
|
19149
|
+
function uniqueKeyOf(env, table, spec, row) {
|
|
19150
|
+
if (spec.where) {
|
|
19151
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
19152
|
+
const v = evalExpr(env.ctx, scope, spec.where);
|
|
19153
|
+
if (v.v !== true) return null;
|
|
19154
|
+
}
|
|
19155
|
+
const parts = [];
|
|
19156
|
+
let hasNull = false;
|
|
19157
|
+
for (const k of spec.keys) {
|
|
19158
|
+
let value;
|
|
19159
|
+
let type;
|
|
19160
|
+
if (k.expr) {
|
|
19161
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
19162
|
+
const v = evalExpr(env.ctx, scope, k.expr);
|
|
19163
|
+
value = v.v;
|
|
19164
|
+
type = v.t === "unknown" ? "text" : v.t;
|
|
19165
|
+
} else {
|
|
19166
|
+
value = row[k.colIdx] ?? null;
|
|
19167
|
+
type = table.columns[k.colIdx].type.id;
|
|
19168
|
+
}
|
|
19169
|
+
if (value === null) {
|
|
19170
|
+
hasNull = true;
|
|
19171
|
+
parts.push("\0N");
|
|
19172
|
+
} else {
|
|
19173
|
+
parts.push(datumKey(type, value));
|
|
19174
|
+
}
|
|
19175
|
+
}
|
|
19176
|
+
if (hasNull && !spec.nullsNotDistinct) return null;
|
|
19177
|
+
return parts.join("");
|
|
19178
|
+
}
|
|
19179
|
+
function checkUnique(env, table, row, selfIdx) {
|
|
19180
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
19181
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
19182
|
+
if (key === null) continue;
|
|
19183
|
+
indexStoreFor(env, table, spec).checkUnique(key, selfIdx);
|
|
19184
|
+
}
|
|
19185
|
+
}
|
|
19186
|
+
function findConflict(env, table, spec, row) {
|
|
19187
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
19188
|
+
if (key === null) return null;
|
|
19189
|
+
const hits = indexStoreFor(env, table, spec).lookup(key);
|
|
19190
|
+
return hits.length > 0 ? hits[0] : null;
|
|
19191
|
+
}
|
|
19192
|
+
function checkForeignKeys(env, table, row) {
|
|
19193
|
+
const state = env.ctx.state;
|
|
19194
|
+
for (const con of table.constraints) {
|
|
19195
|
+
if (con.kind !== "foreign_key") continue;
|
|
19196
|
+
const values = con.columns.map((c) => row[table.columnIndex(c)] ?? null);
|
|
19197
|
+
const nulls = values.filter((v) => v === null).length;
|
|
19198
|
+
if (con.match === "simple" && nulls > 0) continue;
|
|
19199
|
+
if (con.match === "full") {
|
|
19200
|
+
if (nulls === values.length) continue;
|
|
19201
|
+
if (nulls > 0) {
|
|
19202
|
+
throw pgError(
|
|
19203
|
+
"constraint_foreign_key",
|
|
19204
|
+
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
19205
|
+
"23503"
|
|
19206
|
+
);
|
|
19207
|
+
}
|
|
19208
|
+
}
|
|
19209
|
+
const refTable = state.schemas.get(con.refSchema)?.tables.get(con.refTable);
|
|
19210
|
+
if (!refTable) {
|
|
19211
|
+
throw pgError("undefined_table", `relation "${con.refSchema}.${con.refTable}" does not exist`, "42P01");
|
|
19212
|
+
}
|
|
19213
|
+
const refIdxs = con.refColumns.map((c) => refTable.columnIndex(c));
|
|
19214
|
+
const keyTypes = con.refColumns.map((_c, i) => refTable.columns[refIdxs[i]].type.id);
|
|
19215
|
+
const wanted = values.map((v, i) => {
|
|
19216
|
+
const localT = table.columns[table.columnIndex(con.columns[i])].type.id;
|
|
19217
|
+
const cast = castTo(env.ctx, tv(localT, v), keyTypes[i], {});
|
|
19218
|
+
return cast.v === null ? "\0N" : datumKey(keyTypes[i], cast.v);
|
|
19219
|
+
}).join("");
|
|
19220
|
+
let found = false;
|
|
19221
|
+
for (let i = 0; i < refTable.rowCount(); i++) {
|
|
19222
|
+
const r = refTable.rowAt(i);
|
|
19223
|
+
const key = refIdxs.map((ri, j) => {
|
|
19224
|
+
const v = r[ri] ?? null;
|
|
19225
|
+
return v === null ? "\0N" : datumKey(keyTypes[j], v);
|
|
19226
|
+
}).join("");
|
|
19227
|
+
if (key === wanted) {
|
|
19228
|
+
found = true;
|
|
19229
|
+
break;
|
|
19230
|
+
}
|
|
19231
|
+
}
|
|
19232
|
+
if (!found) {
|
|
19233
|
+
throw pgError(
|
|
19234
|
+
"constraint_foreign_key",
|
|
19235
|
+
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
19236
|
+
"23503"
|
|
19237
|
+
);
|
|
19238
|
+
}
|
|
19239
|
+
}
|
|
19240
|
+
}
|
|
19241
|
+
function referencingConstraints(env, table) {
|
|
19242
|
+
const out = [];
|
|
19243
|
+
for (const schema of env.ctx.state.schemas.values()) {
|
|
19244
|
+
for (const t of schema.tables.values()) {
|
|
19245
|
+
for (const con of t.constraints) {
|
|
19246
|
+
if (con.kind === "foreign_key" && con.refSchema === table.schema && con.refTable === table.name) {
|
|
19247
|
+
out.push({ table: t, constraint: con });
|
|
19248
|
+
}
|
|
19249
|
+
}
|
|
19250
|
+
}
|
|
19251
|
+
}
|
|
19252
|
+
return out;
|
|
19253
|
+
}
|
|
19254
|
+
|
|
18821
19255
|
// src/planner/access.ts
|
|
18822
19256
|
function isRowIndependentExpr(expr) {
|
|
18823
19257
|
return expr.type !== "colref";
|
|
@@ -18893,7 +19327,7 @@ function tryIndexedFromItem(env, item, where) {
|
|
|
18893
19327
|
if (!table) return null;
|
|
18894
19328
|
const alias = item.alias ?? item.name[item.name.length - 1];
|
|
18895
19329
|
table.materializeSlab();
|
|
18896
|
-
return tryIndexedTableRows(env, table, alias, where);
|
|
19330
|
+
return tryIndexedTableRows(env, table, alias, where)?.map((row) => [...row, table.rowXmins.get(row) ?? 2]) ?? null;
|
|
18897
19331
|
}
|
|
18898
19332
|
function joinKeyFromRow(row, colIdxs, srcTypes, unifiedTypes, ctx) {
|
|
18899
19333
|
const parts = [];
|
|
@@ -20701,10 +21135,9 @@ var Parser = class {
|
|
|
20701
21135
|
return this.parseCreateFunction(orReplace);
|
|
20702
21136
|
}
|
|
20703
21137
|
if (this.atKw("trigger") || this.atKw("constraint") && this.atKw("trigger", 1)) {
|
|
20704
|
-
|
|
20705
|
-
}
|
|
21138
|
+
const constraint = this.eatKw("constraint");
|
|
20706
21139
|
this.expectKw("trigger");
|
|
20707
|
-
return this.parseCreateTrigger(orReplace);
|
|
21140
|
+
return this.parseCreateTrigger(orReplace, constraint);
|
|
20708
21141
|
}
|
|
20709
21142
|
if (this.atKw("extension")) {
|
|
20710
21143
|
this.pos++;
|
|
@@ -21384,6 +21817,7 @@ var Parser = class {
|
|
|
21384
21817
|
let sqlBody = null;
|
|
21385
21818
|
let volatility = null;
|
|
21386
21819
|
let strict2 = false;
|
|
21820
|
+
const settings = {};
|
|
21387
21821
|
for (; ; ) {
|
|
21388
21822
|
if (this.eatKw("language")) {
|
|
21389
21823
|
language = this.peek().type === "string" ? this.next().value : this.ident(true);
|
|
@@ -21441,8 +21875,23 @@ var Parser = class {
|
|
|
21441
21875
|
continue;
|
|
21442
21876
|
}
|
|
21443
21877
|
if (this.eatKw("set")) {
|
|
21444
|
-
this.ident(true);
|
|
21445
|
-
if (this.
|
|
21878
|
+
const key = this.ident(true).toLowerCase();
|
|
21879
|
+
if (this.eatKw("from")) {
|
|
21880
|
+
this.expectKw("current");
|
|
21881
|
+
settings[key] = "__from_current__";
|
|
21882
|
+
} else {
|
|
21883
|
+
if (!this.eatOp("=")) this.expectKw("to");
|
|
21884
|
+
const values = [];
|
|
21885
|
+
do {
|
|
21886
|
+
const value = this.next();
|
|
21887
|
+
if (!["string", "ident", "quoted_ident", "number"].includes(value.type))
|
|
21888
|
+
this.errorAt(value, "expected setting value");
|
|
21889
|
+
values.push(
|
|
21890
|
+
key === "search_path" && /[^a-z0-9_]/.test(value.value) ? `"${value.value.replaceAll('"', '""')}"` : value.value
|
|
21891
|
+
);
|
|
21892
|
+
} while (this.eatPunct(","));
|
|
21893
|
+
settings[key] = values.join(", ");
|
|
21894
|
+
}
|
|
21446
21895
|
continue;
|
|
21447
21896
|
}
|
|
21448
21897
|
if (this.eatKw("window")) throw unsupported("window functions via CREATE FUNCTION");
|
|
@@ -21522,10 +21971,11 @@ var Parser = class {
|
|
|
21522
21971
|
body,
|
|
21523
21972
|
sqlBody,
|
|
21524
21973
|
volatility,
|
|
21525
|
-
strict: strict2
|
|
21974
|
+
strict: strict2,
|
|
21975
|
+
settings
|
|
21526
21976
|
};
|
|
21527
21977
|
}
|
|
21528
|
-
parseCreateTrigger(orReplace) {
|
|
21978
|
+
parseCreateTrigger(orReplace, constraint) {
|
|
21529
21979
|
const name2 = this.ident();
|
|
21530
21980
|
let timing;
|
|
21531
21981
|
if (this.eatKw("before")) timing = "before";
|
|
@@ -21555,9 +22005,18 @@ var Parser = class {
|
|
|
21555
22005
|
this.expectKw("on");
|
|
21556
22006
|
const table = this.qualifiedName();
|
|
21557
22007
|
if (this.eatKw("referencing")) throw unsupported("trigger transition tables");
|
|
21558
|
-
|
|
21559
|
-
|
|
21560
|
-
|
|
22008
|
+
let deferrable = false;
|
|
22009
|
+
let initiallyDeferred = false;
|
|
22010
|
+
if (this.eatKw("not")) this.expectKw("deferrable");
|
|
22011
|
+
else if (this.eatKw("deferrable")) deferrable = true;
|
|
22012
|
+
if (this.eatKw("initially")) {
|
|
22013
|
+
if (this.eatKw("deferred")) initiallyDeferred = true;
|
|
22014
|
+
else this.expectKw("immediate");
|
|
22015
|
+
}
|
|
22016
|
+
if ((deferrable || initiallyDeferred) && !constraint)
|
|
22017
|
+
this.errorAt(this.peek(), "only constraint triggers can be deferred");
|
|
22018
|
+
if (initiallyDeferred && !deferrable)
|
|
22019
|
+
this.errorAt(this.peek(), "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
|
|
21561
22020
|
let forEachRow = false;
|
|
21562
22021
|
if (this.eatKw("for")) {
|
|
21563
22022
|
this.eatKw("each");
|
|
@@ -21582,7 +22041,21 @@ var Parser = class {
|
|
|
21582
22041
|
} while (this.eatPunct(","));
|
|
21583
22042
|
}
|
|
21584
22043
|
this.expectPunct(")");
|
|
21585
|
-
return {
|
|
22044
|
+
return {
|
|
22045
|
+
type: "create_trigger",
|
|
22046
|
+
constraint,
|
|
22047
|
+
deferrable,
|
|
22048
|
+
initiallyDeferred,
|
|
22049
|
+
orReplace,
|
|
22050
|
+
name: name2,
|
|
22051
|
+
timing,
|
|
22052
|
+
events,
|
|
22053
|
+
table,
|
|
22054
|
+
forEachRow,
|
|
22055
|
+
when,
|
|
22056
|
+
funcName,
|
|
22057
|
+
funcArgs
|
|
22058
|
+
};
|
|
21586
22059
|
}
|
|
21587
22060
|
// --- ALTER --------------------------------------------------------------------
|
|
21588
22061
|
parseAlter() {
|
|
@@ -21608,8 +22081,8 @@ var Parser = class {
|
|
|
21608
22081
|
type: "alter_sequence",
|
|
21609
22082
|
name: name2,
|
|
21610
22083
|
ifExists,
|
|
21611
|
-
options: {
|
|
21612
|
-
|
|
22084
|
+
options: {},
|
|
22085
|
+
renameTo: to
|
|
21613
22086
|
};
|
|
21614
22087
|
}
|
|
21615
22088
|
if (this.atKw("set") && (this.atKw("logged", 1) || this.atKw("unlogged", 1))) {
|
|
@@ -21927,9 +22400,15 @@ var Parser = class {
|
|
|
21927
22400
|
this.skipToStatementEnd();
|
|
21928
22401
|
return { type: "no_op", what: "SET TRANSACTION" };
|
|
21929
22402
|
}
|
|
21930
|
-
if (this.
|
|
21931
|
-
this.
|
|
21932
|
-
|
|
22403
|
+
if (this.eatKw("constraints")) {
|
|
22404
|
+
const names = this.eatKw("all") ? null : [];
|
|
22405
|
+
if (names)
|
|
22406
|
+
do {
|
|
22407
|
+
names.push(this.qualifiedName());
|
|
22408
|
+
} while (this.eatPunct(","));
|
|
22409
|
+
const deferred = this.eatKw("deferred");
|
|
22410
|
+
if (!deferred) this.expectKw("immediate");
|
|
22411
|
+
return { type: "set_constraints", names, deferred };
|
|
21933
22412
|
}
|
|
21934
22413
|
if (this.atKw("role") || this.atKw("session", 0) && this.atKw("authorization", 1)) {
|
|
21935
22414
|
this.skipToStatementEnd();
|
|
@@ -24179,7 +24658,20 @@ function runFunctionBody(env, fn, args2) {
|
|
|
24179
24658
|
}
|
|
24180
24659
|
return last;
|
|
24181
24660
|
}
|
|
24661
|
+
function withFunctionSettings(env, fn, run) {
|
|
24662
|
+
const state = env.ctx.state;
|
|
24663
|
+
const saved = new Map(state.localSettings);
|
|
24664
|
+
for (const [name2, value] of Object.entries(fn.settings ?? {})) state.localSettings.set(name2, value);
|
|
24665
|
+
try {
|
|
24666
|
+
return run();
|
|
24667
|
+
} finally {
|
|
24668
|
+
state.localSettings = saved;
|
|
24669
|
+
}
|
|
24670
|
+
}
|
|
24182
24671
|
function callSqlFunctionScalar(env, fn, args2) {
|
|
24672
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionScalarBody(env, fn, args2));
|
|
24673
|
+
}
|
|
24674
|
+
function callSqlFunctionScalarBody(env, fn, args2) {
|
|
24183
24675
|
const retT = fn.returns ?? "text";
|
|
24184
24676
|
if (fn.language === "plpgsql") {
|
|
24185
24677
|
return callPlpgsqlScalar(env, fn, args2);
|
|
@@ -24209,6 +24701,9 @@ function callSqlFunctionScalar(env, fn, args2) {
|
|
|
24209
24701
|
return castTo(env.ctx, tv(rawT, raw), retT, {});
|
|
24210
24702
|
}
|
|
24211
24703
|
function callSqlFunctionSet(env, fn, args2) {
|
|
24704
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionSetBody(env, fn, args2));
|
|
24705
|
+
}
|
|
24706
|
+
function callSqlFunctionSetBody(env, fn, args2) {
|
|
24212
24707
|
if (fn.language === "plpgsql") {
|
|
24213
24708
|
return callPlpgsqlSet(env, fn, args2);
|
|
24214
24709
|
}
|
|
@@ -24304,12 +24799,12 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
24304
24799
|
table: null
|
|
24305
24800
|
}));
|
|
24306
24801
|
const seen = /* @__PURE__ */ new Set();
|
|
24307
|
-
const
|
|
24802
|
+
const keyOf2 = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(columns[i].type, v)).join("");
|
|
24308
24803
|
let result = [];
|
|
24309
24804
|
let working = [];
|
|
24310
24805
|
for (const row of base.rows) {
|
|
24311
24806
|
if (!body.all) {
|
|
24312
|
-
const k =
|
|
24807
|
+
const k = keyOf2(row);
|
|
24313
24808
|
if (seen.has(k)) continue;
|
|
24314
24809
|
seen.add(k);
|
|
24315
24810
|
}
|
|
@@ -24342,7 +24837,7 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
24342
24837
|
return castTo(env.ctx, tv(srcT === UNKNOWN ? "text" : srcT, v), columns[i].type, {}).v;
|
|
24343
24838
|
});
|
|
24344
24839
|
if (!body.all) {
|
|
24345
|
-
const k =
|
|
24840
|
+
const k = keyOf2(row);
|
|
24346
24841
|
if (seen.has(k)) continue;
|
|
24347
24842
|
seen.add(k);
|
|
24348
24843
|
}
|
|
@@ -24363,15 +24858,17 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
24363
24858
|
return rel3;
|
|
24364
24859
|
}
|
|
24365
24860
|
function renameWithAliases(rel3, label, colAliases, what) {
|
|
24366
|
-
|
|
24861
|
+
const visibleWidth = rel3.columns.filter((column) => !column.system).length;
|
|
24862
|
+
if (colAliases && colAliases.length > visibleWidth) {
|
|
24367
24863
|
throw pgError(
|
|
24368
24864
|
"invalid_column_reference",
|
|
24369
|
-
`table "${what}" has ${
|
|
24865
|
+
`table "${what}" has ${visibleWidth} columns available but ${colAliases.length} columns specified`,
|
|
24370
24866
|
"42P10"
|
|
24371
24867
|
);
|
|
24372
24868
|
}
|
|
24373
24869
|
const columns = rel3.columns.map((c, i) => ({
|
|
24374
|
-
|
|
24870
|
+
...c,
|
|
24871
|
+
name: c.system ? c.name : colAliases?.[i] ?? c.name,
|
|
24375
24872
|
type: c.type === UNKNOWN ? "text" : c.type,
|
|
24376
24873
|
table: label
|
|
24377
24874
|
}));
|
|
@@ -24392,8 +24889,11 @@ function materializeItem(env, item, scope) {
|
|
|
24392
24889
|
if (table) {
|
|
24393
24890
|
table.materializeSlab();
|
|
24394
24891
|
const rel3 = {
|
|
24395
|
-
columns:
|
|
24396
|
-
|
|
24892
|
+
columns: [
|
|
24893
|
+
...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
|
|
24894
|
+
{ name: "xmin", type: "xid", table: label, hidden: true, system: true }
|
|
24895
|
+
],
|
|
24896
|
+
rows: table.rows.map((row) => [...row, table.rowXmins.get(row) ?? 2])
|
|
24397
24897
|
};
|
|
24398
24898
|
return { rel: renameWithAliases(rel3, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
|
|
24399
24899
|
}
|
|
@@ -25023,7 +25523,7 @@ function resolveColIdx(columns, parts) {
|
|
|
25023
25523
|
let found = -1;
|
|
25024
25524
|
for (let i = 0; i < columns.length; i++) {
|
|
25025
25525
|
const c = columns[i];
|
|
25026
|
-
if (!c.hidden && c.name === name3) {
|
|
25526
|
+
if ((!c.hidden || c.system) && c.name === name3) {
|
|
25027
25527
|
if (found !== -1) return null;
|
|
25028
25528
|
found = i;
|
|
25029
25529
|
}
|
|
@@ -25522,7 +26022,7 @@ function setOpRelation(env, op) {
|
|
|
25522
26022
|
);
|
|
25523
26023
|
const lrows = normalize2(left);
|
|
25524
26024
|
const rrows = normalize2(right);
|
|
25525
|
-
const
|
|
26025
|
+
const keyOf2 = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(types[i], v)).join("");
|
|
25526
26026
|
let rows;
|
|
25527
26027
|
switch (op.op) {
|
|
25528
26028
|
case "union": {
|
|
@@ -25530,7 +26030,7 @@ function setOpRelation(env, op) {
|
|
|
25530
26030
|
if (!op.all) {
|
|
25531
26031
|
const seen = /* @__PURE__ */ new Set();
|
|
25532
26032
|
rows = rows.filter((r) => {
|
|
25533
|
-
const k =
|
|
26033
|
+
const k = keyOf2(r);
|
|
25534
26034
|
if (seen.has(k)) return false;
|
|
25535
26035
|
seen.add(k);
|
|
25536
26036
|
return true;
|
|
@@ -25541,13 +26041,13 @@ function setOpRelation(env, op) {
|
|
|
25541
26041
|
case "intersect": {
|
|
25542
26042
|
const rightCounts = /* @__PURE__ */ new Map();
|
|
25543
26043
|
for (const r of rrows) {
|
|
25544
|
-
const k =
|
|
26044
|
+
const k = keyOf2(r);
|
|
25545
26045
|
rightCounts.set(k, (rightCounts.get(k) ?? 0) + 1);
|
|
25546
26046
|
}
|
|
25547
26047
|
rows = [];
|
|
25548
26048
|
const emitted = /* @__PURE__ */ new Set();
|
|
25549
26049
|
for (const r of lrows) {
|
|
25550
|
-
const k =
|
|
26050
|
+
const k = keyOf2(r);
|
|
25551
26051
|
const avail = rightCounts.get(k) ?? 0;
|
|
25552
26052
|
if (avail <= 0) continue;
|
|
25553
26053
|
if (op.all) {
|
|
@@ -25563,13 +26063,13 @@ function setOpRelation(env, op) {
|
|
|
25563
26063
|
case "except": {
|
|
25564
26064
|
const rightCounts = /* @__PURE__ */ new Map();
|
|
25565
26065
|
for (const r of rrows) {
|
|
25566
|
-
const k =
|
|
26066
|
+
const k = keyOf2(r);
|
|
25567
26067
|
rightCounts.set(k, (rightCounts.get(k) ?? 0) + 1);
|
|
25568
26068
|
}
|
|
25569
26069
|
rows = [];
|
|
25570
26070
|
const emitted = /* @__PURE__ */ new Set();
|
|
25571
26071
|
for (const r of lrows) {
|
|
25572
|
-
const k =
|
|
26072
|
+
const k = keyOf2(r);
|
|
25573
26073
|
if (op.all) {
|
|
25574
26074
|
const avail = rightCounts.get(k) ?? 0;
|
|
25575
26075
|
if (avail > 0) {
|
|
@@ -25607,7 +26107,7 @@ function expandTargets(core, columns) {
|
|
|
25607
26107
|
let any = false;
|
|
25608
26108
|
for (let i = 0; i < columns.length; i++) {
|
|
25609
26109
|
const c = columns[i];
|
|
25610
|
-
if (c.table === label) {
|
|
26110
|
+
if (c.table === label && !c.system) {
|
|
25611
26111
|
any = true;
|
|
25612
26112
|
items.push({ name: c.name, kind: "col", colIdx: i, expr: null, hidden: false });
|
|
25613
26113
|
}
|
|
@@ -26045,179 +26545,26 @@ function executeSelectStmt(env0, stmt) {
|
|
|
26045
26545
|
return applyLimitOffset(env, rel3, stmt.limit, stmt.offset);
|
|
26046
26546
|
}
|
|
26047
26547
|
|
|
26048
|
-
// src/
|
|
26049
|
-
function
|
|
26050
|
-
const cols =
|
|
26051
|
-
|
|
26052
|
-
|
|
26053
|
-
|
|
26054
|
-
|
|
26055
|
-
|
|
26056
|
-
|
|
26057
|
-
|
|
26058
|
-
throw pgError(
|
|
26059
|
-
"not_null_violation",
|
|
26060
|
-
`null value in column "${c.name}" of relation "${table.name}" violates not-null constraint`,
|
|
26061
|
-
"23502"
|
|
26062
|
-
);
|
|
26063
|
-
}
|
|
26064
|
-
}
|
|
26065
|
-
}
|
|
26066
|
-
function checkChecks(env, table, row) {
|
|
26067
|
-
for (const con of table.constraints) {
|
|
26068
|
-
if (con.kind !== "check") continue;
|
|
26069
|
-
const scope = makeEvalScope(env, tableScope(table, row));
|
|
26070
|
-
const v = evalExpr(env.ctx, scope, con.expr);
|
|
26071
|
-
if (v.v === null) continue;
|
|
26072
|
-
const b = castTo(env.ctx, v, "bool", {});
|
|
26073
|
-
if (b.v !== true) {
|
|
26074
|
-
throw pgError(
|
|
26075
|
-
"check_violation",
|
|
26076
|
-
`new row for relation "${table.name}" violates check constraint "${con.name}"`,
|
|
26077
|
-
"23514"
|
|
26078
|
-
);
|
|
26079
|
-
}
|
|
26080
|
-
}
|
|
26081
|
-
}
|
|
26082
|
-
function uniqueSpecsFor(env, table) {
|
|
26083
|
-
const specs = [];
|
|
26084
|
-
for (const con of table.constraints) {
|
|
26085
|
-
if (con.kind !== "primary_key" && con.kind !== "unique") continue;
|
|
26086
|
-
specs.push({
|
|
26087
|
-
name: con.name,
|
|
26088
|
-
keys: con.columns.map((c) => ({ colIdx: table.columnIndex(c), expr: null })),
|
|
26089
|
-
columnNames: con.columns,
|
|
26090
|
-
nullsNotDistinct: con.kind === "unique" ? con.nullsNotDistinct : false,
|
|
26091
|
-
where: null,
|
|
26092
|
-
isPrimary: con.kind === "primary_key"
|
|
26093
|
-
});
|
|
26094
|
-
}
|
|
26095
|
-
const schema = env.ctx.state.schemas.get(table.schema);
|
|
26096
|
-
if (schema) {
|
|
26097
|
-
for (const idx of schema.indexes.values()) {
|
|
26098
|
-
if (idx.table !== table.name || !idx.unique || idx.isConstraint || idx.valid === false) continue;
|
|
26099
|
-
specs.push(uniqueSpecOfIndex(table, idx));
|
|
26100
|
-
}
|
|
26101
|
-
}
|
|
26102
|
-
return specs;
|
|
26103
|
-
}
|
|
26104
|
-
function uniqueSpecOfIndex(table, idx) {
|
|
26105
|
-
return {
|
|
26106
|
-
name: idx.name,
|
|
26107
|
-
keys: idx.columns.map((c) => ({
|
|
26108
|
-
colIdx: c.column !== null ? table.columnIndex(c.column) : -1,
|
|
26109
|
-
expr: c.expr
|
|
26110
|
-
})),
|
|
26111
|
-
columnNames: idx.columns.map((c) => c.column ?? "expr"),
|
|
26112
|
-
nullsNotDistinct: idx.nullsNotDistinct,
|
|
26113
|
-
where: idx.where,
|
|
26114
|
-
isPrimary: false
|
|
26115
|
-
};
|
|
26116
|
-
}
|
|
26117
|
-
function uniqueKeyOf(env, table, spec, row) {
|
|
26118
|
-
if (spec.where) {
|
|
26119
|
-
const scope = makeEvalScope(env, tableScope(table, row));
|
|
26120
|
-
const v = evalExpr(env.ctx, scope, spec.where);
|
|
26121
|
-
if (v.v !== true) return null;
|
|
26122
|
-
}
|
|
26123
|
-
const parts = [];
|
|
26124
|
-
let hasNull = false;
|
|
26125
|
-
for (const k of spec.keys) {
|
|
26126
|
-
let value;
|
|
26127
|
-
let type;
|
|
26128
|
-
if (k.expr) {
|
|
26129
|
-
const scope = makeEvalScope(env, tableScope(table, row));
|
|
26130
|
-
const v = evalExpr(env.ctx, scope, k.expr);
|
|
26131
|
-
value = v.v;
|
|
26132
|
-
type = v.t === "unknown" ? "text" : v.t;
|
|
26133
|
-
} else {
|
|
26134
|
-
value = row[k.colIdx] ?? null;
|
|
26135
|
-
type = table.columns[k.colIdx].type.id;
|
|
26136
|
-
}
|
|
26137
|
-
if (value === null) {
|
|
26138
|
-
hasNull = true;
|
|
26139
|
-
parts.push("\0N");
|
|
26140
|
-
} else {
|
|
26141
|
-
parts.push(datumKey(type, value));
|
|
26142
|
-
}
|
|
26143
|
-
}
|
|
26144
|
-
if (hasNull && !spec.nullsNotDistinct) return null;
|
|
26145
|
-
return parts.join("");
|
|
26146
|
-
}
|
|
26147
|
-
function checkUnique(env, table, row, selfIdx) {
|
|
26148
|
-
for (const spec of uniqueSpecsFor(env, table)) {
|
|
26149
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
26150
|
-
if (key === null) continue;
|
|
26151
|
-
indexStoreFor(env, table, spec).checkUnique(key, selfIdx);
|
|
26152
|
-
}
|
|
26153
|
-
}
|
|
26154
|
-
function findConflict(env, table, spec, row) {
|
|
26155
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
26156
|
-
if (key === null) return null;
|
|
26157
|
-
const hits = indexStoreFor(env, table, spec).lookup(key);
|
|
26158
|
-
return hits.length > 0 ? hits[0] : null;
|
|
26159
|
-
}
|
|
26160
|
-
function checkForeignKeys(env, table, row) {
|
|
26161
|
-
const state = env.ctx.state;
|
|
26162
|
-
for (const con of table.constraints) {
|
|
26163
|
-
if (con.kind !== "foreign_key") continue;
|
|
26164
|
-
const values = con.columns.map((c) => row[table.columnIndex(c)] ?? null);
|
|
26165
|
-
const nulls = values.filter((v) => v === null).length;
|
|
26166
|
-
if (con.match === "simple" && nulls > 0) continue;
|
|
26167
|
-
if (con.match === "full") {
|
|
26168
|
-
if (nulls === values.length) continue;
|
|
26169
|
-
if (nulls > 0) {
|
|
26170
|
-
throw pgError(
|
|
26171
|
-
"constraint_foreign_key",
|
|
26172
|
-
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
26173
|
-
"23503"
|
|
26174
|
-
);
|
|
26175
|
-
}
|
|
26176
|
-
}
|
|
26177
|
-
const refTable = state.schemas.get(con.refSchema)?.tables.get(con.refTable);
|
|
26178
|
-
if (!refTable) {
|
|
26179
|
-
throw pgError("undefined_table", `relation "${con.refSchema}.${con.refTable}" does not exist`, "42P01");
|
|
26180
|
-
}
|
|
26181
|
-
const refIdxs = con.refColumns.map((c) => refTable.columnIndex(c));
|
|
26182
|
-
const keyTypes = con.refColumns.map((_c, i) => refTable.columns[refIdxs[i]].type.id);
|
|
26183
|
-
const wanted = values.map((v, i) => {
|
|
26184
|
-
const localT = table.columns[table.columnIndex(con.columns[i])].type.id;
|
|
26185
|
-
const cast = castTo(env.ctx, tv(localT, v), keyTypes[i], {});
|
|
26186
|
-
return cast.v === null ? "\0N" : datumKey(keyTypes[i], cast.v);
|
|
26187
|
-
}).join("");
|
|
26188
|
-
let found = false;
|
|
26189
|
-
for (let i = 0; i < refTable.rowCount(); i++) {
|
|
26190
|
-
const r = refTable.rowAt(i);
|
|
26191
|
-
const key = refIdxs.map((ri, j) => {
|
|
26192
|
-
const v = r[ri] ?? null;
|
|
26193
|
-
return v === null ? "\0N" : datumKey(keyTypes[j], v);
|
|
26194
|
-
}).join("");
|
|
26195
|
-
if (key === wanted) {
|
|
26196
|
-
found = true;
|
|
26197
|
-
break;
|
|
26198
|
-
}
|
|
26199
|
-
}
|
|
26200
|
-
if (!found) {
|
|
26201
|
-
throw pgError(
|
|
26202
|
-
"constraint_foreign_key",
|
|
26203
|
-
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
26204
|
-
"23503"
|
|
26205
|
-
);
|
|
26548
|
+
// src/executor/triggers-scope.ts
|
|
26549
|
+
function triggerScope(table, newRow, oldRow) {
|
|
26550
|
+
const cols = [];
|
|
26551
|
+
const row = [];
|
|
26552
|
+
const rangeVars = /* @__PURE__ */ new Set();
|
|
26553
|
+
if (newRow) {
|
|
26554
|
+
rangeVars.add("new");
|
|
26555
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
26556
|
+
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "new" });
|
|
26557
|
+
row.push(newRow[i] ?? null);
|
|
26206
26558
|
}
|
|
26207
26559
|
}
|
|
26208
|
-
|
|
26209
|
-
|
|
26210
|
-
|
|
26211
|
-
|
|
26212
|
-
|
|
26213
|
-
for (const con of t.constraints) {
|
|
26214
|
-
if (con.kind === "foreign_key" && con.refSchema === table.schema && con.refTable === table.name) {
|
|
26215
|
-
out.push({ table: t, constraint: con });
|
|
26216
|
-
}
|
|
26217
|
-
}
|
|
26560
|
+
if (oldRow) {
|
|
26561
|
+
rangeVars.add("old");
|
|
26562
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
26563
|
+
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "old" });
|
|
26564
|
+
row.push(oldRow[i] ?? null);
|
|
26218
26565
|
}
|
|
26219
26566
|
}
|
|
26220
|
-
return
|
|
26567
|
+
return new RowScope(cols, row, null, rangeVars);
|
|
26221
26568
|
}
|
|
26222
26569
|
|
|
26223
26570
|
// src/executor/triggers.ts
|
|
@@ -26233,6 +26580,18 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
26233
26580
|
for (const t of table.triggers) {
|
|
26234
26581
|
if (t.timing !== timing || !matches(t, event) || !t.forEachRow) continue;
|
|
26235
26582
|
if (!executor) throw unsupported(`trigger "${t.name}" execution`);
|
|
26583
|
+
if (t.constraint && timing === "after") {
|
|
26584
|
+
if (t.when && !evalPredicate(env, triggerScope(table, newRow, oldRow), t.when)) continue;
|
|
26585
|
+
env.ctx.state.pendingTriggers.push({
|
|
26586
|
+
schema: table.schema,
|
|
26587
|
+
table: table.name,
|
|
26588
|
+
trigger: t.name,
|
|
26589
|
+
event,
|
|
26590
|
+
oldRow: oldRow?.slice() ?? null,
|
|
26591
|
+
newRow: newRow?.slice() ?? null
|
|
26592
|
+
});
|
|
26593
|
+
continue;
|
|
26594
|
+
}
|
|
26236
26595
|
const result = executor(env, table, t, event, oldRow, timing === "before" ? row : newRow);
|
|
26237
26596
|
if (timing === "before") {
|
|
26238
26597
|
if (result === null) return { row: null };
|
|
@@ -26241,6 +26600,170 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
26241
26600
|
}
|
|
26242
26601
|
return { row };
|
|
26243
26602
|
}
|
|
26603
|
+
var keyOf = (schema, name2) => JSON.stringify([schema, name2]);
|
|
26604
|
+
function flushConstraintTriggers(state, all = false) {
|
|
26605
|
+
const env = { ctx: new EngineCtx(state), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
|
|
26606
|
+
for (let i = 0; i < state.pendingTriggers.length; ) {
|
|
26607
|
+
const pending2 = state.pendingTriggers[i];
|
|
26608
|
+
const table = state.schemas.get(pending2.schema)?.tables.get(pending2.table);
|
|
26609
|
+
const trigger = table?.triggers.find((t) => t.name === pending2.trigger);
|
|
26610
|
+
if (!table || !trigger) {
|
|
26611
|
+
state.pendingTriggers.splice(i, 1);
|
|
26612
|
+
continue;
|
|
26613
|
+
}
|
|
26614
|
+
const deferred = trigger.deferrable && (state.constraintModes.get(keyOf(table.schema, trigger.name)) ?? trigger.initiallyDeferred);
|
|
26615
|
+
if (!all && state.inTransaction && deferred) {
|
|
26616
|
+
i++;
|
|
26617
|
+
continue;
|
|
26618
|
+
}
|
|
26619
|
+
if (!executor) throw unsupported(`trigger "${trigger.name}" execution`);
|
|
26620
|
+
state.pendingTriggers.splice(i, 1);
|
|
26621
|
+
const changes = state.changes;
|
|
26622
|
+
try {
|
|
26623
|
+
executor(env, table, { ...trigger, when: null }, pending2.event, pending2.oldRow, pending2.newRow);
|
|
26624
|
+
} catch (error) {
|
|
26625
|
+
state.pendingTriggers.splice(i, 0, pending2);
|
|
26626
|
+
throw error;
|
|
26627
|
+
} finally {
|
|
26628
|
+
state.changes = changes;
|
|
26629
|
+
}
|
|
26630
|
+
}
|
|
26631
|
+
}
|
|
26632
|
+
function setConstraints(state, stmt) {
|
|
26633
|
+
if (!state.inTransaction) return;
|
|
26634
|
+
const matches2 = [];
|
|
26635
|
+
if (stmt.names) {
|
|
26636
|
+
for (const name2 of stmt.names) {
|
|
26637
|
+
const schemas = name2.length > 1 ? [name2[name2.length - 2]] : state.effectiveSearchPath();
|
|
26638
|
+
let found = false;
|
|
26639
|
+
for (const schema of schemas) {
|
|
26640
|
+
const items = [...state.schemas.get(schema)?.tables.values() ?? []].flatMap(
|
|
26641
|
+
(table) => table.triggers.filter((t) => t.constraint && t.name === name2[name2.length - 1])
|
|
26642
|
+
);
|
|
26643
|
+
if (items.length) {
|
|
26644
|
+
for (const trigger of items) matches2.push({ schema, trigger });
|
|
26645
|
+
found = true;
|
|
26646
|
+
break;
|
|
26647
|
+
}
|
|
26648
|
+
}
|
|
26649
|
+
if (!found) throw pgError("undefined_object", `constraint "${name2.join(".")}" does not exist`, "42704");
|
|
26650
|
+
}
|
|
26651
|
+
} else {
|
|
26652
|
+
for (const schema of state.schemas.values())
|
|
26653
|
+
for (const table of schema.tables.values())
|
|
26654
|
+
for (const trigger of table.triggers)
|
|
26655
|
+
if (trigger.constraint && trigger.deferrable) matches2.push({ schema: schema.name, trigger });
|
|
26656
|
+
}
|
|
26657
|
+
for (const { trigger } of matches2)
|
|
26658
|
+
if (stmt.deferred && !trigger.deferrable)
|
|
26659
|
+
throw pgError("misuse", `constraint "${trigger.name}" is not deferrable`, "55000");
|
|
26660
|
+
const previous = new Map(state.constraintModes);
|
|
26661
|
+
for (const { schema, trigger } of matches2) state.constraintModes.set(keyOf(schema, trigger.name), stmt.deferred);
|
|
26662
|
+
try {
|
|
26663
|
+
if (!stmt.deferred) flushConstraintTriggers(state);
|
|
26664
|
+
} catch (error) {
|
|
26665
|
+
state.constraintModes = previous;
|
|
26666
|
+
throw error;
|
|
26667
|
+
}
|
|
26668
|
+
}
|
|
26669
|
+
|
|
26670
|
+
// src/transactions/manager.ts
|
|
26671
|
+
var TransactionManager = class {
|
|
26672
|
+
constructor(state) {
|
|
26673
|
+
this.state = state;
|
|
26674
|
+
}
|
|
26675
|
+
state;
|
|
26676
|
+
base = null;
|
|
26677
|
+
savepoints = [];
|
|
26678
|
+
freezeDepth = 0;
|
|
26679
|
+
get inTransaction() {
|
|
26680
|
+
return this.base !== null;
|
|
26681
|
+
}
|
|
26682
|
+
takeSnapshot() {
|
|
26683
|
+
this.state.freezeShared();
|
|
26684
|
+
this.freezeDepth++;
|
|
26685
|
+
return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
|
|
26686
|
+
}
|
|
26687
|
+
restore(snap) {
|
|
26688
|
+
this.state.restoreFrom(snap.state);
|
|
26689
|
+
this.state.prng.setState(snap.prngState);
|
|
26690
|
+
}
|
|
26691
|
+
thawOnce() {
|
|
26692
|
+
if (this.freezeDepth > 0) {
|
|
26693
|
+
this.state.thawShared();
|
|
26694
|
+
this.freezeDepth--;
|
|
26695
|
+
}
|
|
26696
|
+
}
|
|
26697
|
+
begin() {
|
|
26698
|
+
if (this.base !== null) {
|
|
26699
|
+
return;
|
|
26700
|
+
}
|
|
26701
|
+
this.base = this.takeSnapshot();
|
|
26702
|
+
this.state.inTransaction = true;
|
|
26703
|
+
assert(this.freezeDepth === 1, "BEGIN freeze depth");
|
|
26704
|
+
}
|
|
26705
|
+
commit() {
|
|
26706
|
+
try {
|
|
26707
|
+
flushConstraintTriggers(this.state, true);
|
|
26708
|
+
} catch (error) {
|
|
26709
|
+
this.rollback();
|
|
26710
|
+
throw error;
|
|
26711
|
+
}
|
|
26712
|
+
this.base = null;
|
|
26713
|
+
this.savepoints = [];
|
|
26714
|
+
this.state.inTransaction = false;
|
|
26715
|
+
this.state.transactionXid = null;
|
|
26716
|
+
this.state.localSettings.clear();
|
|
26717
|
+
this.state.pendingTriggers = [];
|
|
26718
|
+
this.state.constraintModes.clear();
|
|
26719
|
+
while (this.freezeDepth > 0) this.thawOnce();
|
|
26720
|
+
}
|
|
26721
|
+
rollback() {
|
|
26722
|
+
if (this.base !== null) {
|
|
26723
|
+
this.restore(this.base);
|
|
26724
|
+
}
|
|
26725
|
+
this.base = null;
|
|
26726
|
+
this.savepoints = [];
|
|
26727
|
+
this.state.inTransaction = false;
|
|
26728
|
+
this.state.transactionXid = null;
|
|
26729
|
+
this.state.localSettings.clear();
|
|
26730
|
+
this.state.pendingTriggers = [];
|
|
26731
|
+
this.state.constraintModes.clear();
|
|
26732
|
+
while (this.freezeDepth > 0) this.thawOnce();
|
|
26733
|
+
}
|
|
26734
|
+
savepoint(name2) {
|
|
26735
|
+
if (this.base === null) {
|
|
26736
|
+
throw pgError("transaction_state", "SAVEPOINT can only be used in transaction blocks", "25P01");
|
|
26737
|
+
}
|
|
26738
|
+
this.savepoints.push({ name: name2, snap: this.takeSnapshot() });
|
|
26739
|
+
}
|
|
26740
|
+
releaseSavepoint(name2) {
|
|
26741
|
+
const idx = this.findSavepoint(name2);
|
|
26742
|
+
this.savepoints.splice(idx);
|
|
26743
|
+
}
|
|
26744
|
+
rollbackToSavepoint(name2) {
|
|
26745
|
+
const idx = this.findSavepoint(name2);
|
|
26746
|
+
const sp = this.savepoints[idx];
|
|
26747
|
+
this.restore(sp.snap);
|
|
26748
|
+
this.savepoints.splice(idx + 1);
|
|
26749
|
+
}
|
|
26750
|
+
findSavepoint(name2) {
|
|
26751
|
+
if (this.base === null) {
|
|
26752
|
+
throw pgError("transaction_state", `SAVEPOINT can only be used in transaction blocks`, "25P01");
|
|
26753
|
+
}
|
|
26754
|
+
for (let i = this.savepoints.length - 1; i >= 0; i--) {
|
|
26755
|
+
if (this.savepoints[i].name === name2) return i;
|
|
26756
|
+
}
|
|
26757
|
+
throw pgError("invalid_savepoint_specification", `savepoint "${name2}" does not exist`, "3B001");
|
|
26758
|
+
}
|
|
26759
|
+
reset() {
|
|
26760
|
+
this.base = null;
|
|
26761
|
+
this.savepoints = [];
|
|
26762
|
+
this.state.inTransaction = false;
|
|
26763
|
+
this.state.transactionXid = null;
|
|
26764
|
+
this.freezeDepth = 0;
|
|
26765
|
+
}
|
|
26766
|
+
};
|
|
26244
26767
|
|
|
26245
26768
|
// src/executor/dml.ts
|
|
26246
26769
|
function withStatementRollback(env, fn) {
|
|
@@ -26441,6 +26964,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
|
|
|
26441
26964
|
const updated = existing.slice();
|
|
26442
26965
|
applyUpdateSets(env, table, sets, scope, updated);
|
|
26443
26966
|
computeGeneratedColumns(env, table, updated);
|
|
26967
|
+
table.rowXmins.set(updated, env.ctx.rowVersionXid());
|
|
26444
26968
|
rows[existingIdx] = updated;
|
|
26445
26969
|
indexUpdateRow(env, table, existingIdx, existing, updated);
|
|
26446
26970
|
checkNotNull(env, table, updated);
|
|
@@ -26526,6 +27050,7 @@ function executeInsert(env0, stmt) {
|
|
|
26526
27050
|
checkChecks(env, table, newRow);
|
|
26527
27051
|
checkUnique(env, table, newRow, rows.length);
|
|
26528
27052
|
checkForeignKeys(env, table, newRow);
|
|
27053
|
+
table.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
26529
27054
|
rows.push(newRow);
|
|
26530
27055
|
indexInsertRow(env, table, rows.length - 1, newRow);
|
|
26531
27056
|
insertedCount++;
|
|
@@ -26643,6 +27168,7 @@ function executeUpdate(env0, stmt) {
|
|
|
26643
27168
|
if (fired.row === null) continue;
|
|
26644
27169
|
const finalRow = fired.row;
|
|
26645
27170
|
computeGeneratedColumns(env, table, finalRow);
|
|
27171
|
+
table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
|
|
26646
27172
|
rows[ri] = finalRow;
|
|
26647
27173
|
try {
|
|
26648
27174
|
checkNotNull(env, table, finalRow);
|
|
@@ -26762,6 +27288,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
26762
27288
|
for (const c of con.columns) {
|
|
26763
27289
|
newRow[child.columnIndex(c)] = null;
|
|
26764
27290
|
}
|
|
27291
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
26765
27292
|
childRows[i] = newRow;
|
|
26766
27293
|
checkNotNull(env, child, newRow);
|
|
26767
27294
|
checkChecks(env, child, newRow);
|
|
@@ -26775,6 +27302,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
26775
27302
|
const ci = child.columnIndex(c);
|
|
26776
27303
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
26777
27304
|
}
|
|
27305
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
26778
27306
|
childRows[i] = newRow;
|
|
26779
27307
|
checkNotNull(env, child, newRow);
|
|
26780
27308
|
checkChecks(env, child, newRow);
|
|
@@ -26812,6 +27340,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
26812
27340
|
const refIdx = table.columnIndex(con.refColumns[c]);
|
|
26813
27341
|
newRow[localIdx] = newRows[r][refIdx] ?? null;
|
|
26814
27342
|
}
|
|
27343
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
26815
27344
|
childRows[i] = newRow;
|
|
26816
27345
|
checkChecks(env, child, newRow);
|
|
26817
27346
|
}
|
|
@@ -26821,6 +27350,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
26821
27350
|
for (const i of idxs) {
|
|
26822
27351
|
const newRow = childRows[i].slice();
|
|
26823
27352
|
for (const c of con.columns) newRow[child.columnIndex(c)] = null;
|
|
27353
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
26824
27354
|
childRows[i] = newRow;
|
|
26825
27355
|
checkNotNull(env, child, newRow);
|
|
26826
27356
|
}
|
|
@@ -26833,6 +27363,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
26833
27363
|
const ci = child.columnIndex(c);
|
|
26834
27364
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
26835
27365
|
}
|
|
27366
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
26836
27367
|
childRows[i] = newRow;
|
|
26837
27368
|
checkForeignKeys(env, child, newRow);
|
|
26838
27369
|
}
|
|
@@ -26930,6 +27461,7 @@ function executeSet(env, stmt) {
|
|
|
26930
27461
|
else target.delete(name2);
|
|
26931
27462
|
return commandResult("SET", 0);
|
|
26932
27463
|
}
|
|
27464
|
+
validateStorageSetting(name2, stmt.value);
|
|
26933
27465
|
target.set(name2, stmt.value);
|
|
26934
27466
|
return commandResult("SET", 0);
|
|
26935
27467
|
}
|
|
@@ -27235,64 +27767,6 @@ function executeCopyFromData(env, stmt, data) {
|
|
|
27235
27767
|
};
|
|
27236
27768
|
}
|
|
27237
27769
|
|
|
27238
|
-
// src/expressions/context.ts
|
|
27239
|
-
var EngineCtx = class {
|
|
27240
|
-
state;
|
|
27241
|
-
/** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
|
|
27242
|
-
txNow;
|
|
27243
|
-
/** statement timestamp */
|
|
27244
|
-
stmtNow;
|
|
27245
|
-
constructor(state, txNow) {
|
|
27246
|
-
this.state = state;
|
|
27247
|
-
const nowMs = state.clock().getTime();
|
|
27248
|
-
const nowMicros = BigInt(Math.round(nowMs)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG;
|
|
27249
|
-
this.txNow = txNow ?? nowMicros;
|
|
27250
|
-
this.stmtNow = nowMicros;
|
|
27251
|
-
}
|
|
27252
|
-
timezone() {
|
|
27253
|
-
return this.state.getSetting("timezone") ?? "UTC";
|
|
27254
|
-
}
|
|
27255
|
-
namespaceOid(name2) {
|
|
27256
|
-
const oid = builtinNamespaceOid(name2) ?? this.state.schemas.get(name2)?.oid;
|
|
27257
|
-
if (oid === void 0) throw pgError("undefined_object", `schema "${name2}" does not exist`, "3F000");
|
|
27258
|
-
return oid;
|
|
27259
|
-
}
|
|
27260
|
-
namespaceName(oid) {
|
|
27261
|
-
const builtin = builtinNamespaceName(oid);
|
|
27262
|
-
if (builtin !== void 0) return builtin;
|
|
27263
|
-
for (const schema of this.state.schemas.values()) {
|
|
27264
|
-
if (schema.oid === oid) return schema.name;
|
|
27265
|
-
}
|
|
27266
|
-
return null;
|
|
27267
|
-
}
|
|
27268
|
-
zoneOffsetAt(utcMicros) {
|
|
27269
|
-
return zoneOffsetAtUtc(this.timezone(), utcMicros);
|
|
27270
|
-
}
|
|
27271
|
-
zoneOffsetForNaive(naiveMicros) {
|
|
27272
|
-
return zoneOffsetForNaive(this.timezone(), naiveMicros);
|
|
27273
|
-
}
|
|
27274
|
-
enumLabels(enumType) {
|
|
27275
|
-
if (!isEnumType(enumType)) return null;
|
|
27276
|
-
const e = this.state.findEnumByKey(enumType.slice(5));
|
|
27277
|
-
return e?.labels ?? null;
|
|
27278
|
-
}
|
|
27279
|
-
enumHasLabel(enumType, label) {
|
|
27280
|
-
const labels = this.enumLabels(enumType);
|
|
27281
|
-
return labels === null ? true : labels.includes(label);
|
|
27282
|
-
}
|
|
27283
|
-
enumOrder(enumType, label) {
|
|
27284
|
-
const labels = this.enumLabels(enumType);
|
|
27285
|
-
if (!labels) return 0;
|
|
27286
|
-
const idx = labels.indexOf(label);
|
|
27287
|
-
return idx === -1 ? labels.length : idx;
|
|
27288
|
-
}
|
|
27289
|
-
requireEnum(enumType) {
|
|
27290
|
-
const labels = this.enumLabels(enumType);
|
|
27291
|
-
if (!labels) throw pgError("undefined_object", `type "${enumType.slice(5)}" does not exist`);
|
|
27292
|
-
return labels;
|
|
27293
|
-
}
|
|
27294
|
-
};
|
|
27295
|
-
|
|
27296
27770
|
// src/runtime/clock.ts
|
|
27297
27771
|
var DEFAULT_NOW = /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z");
|
|
27298
27772
|
function fixedClock(instant = DEFAULT_NOW) {
|
|
@@ -28260,7 +28734,7 @@ function pgClass(ctx) {
|
|
|
28260
28734
|
v.materialized ? "m" : "v",
|
|
28261
28735
|
v.columns?.length ?? 0,
|
|
28262
28736
|
v.matRows?.length ?? 0,
|
|
28263
|
-
|
|
28737
|
+
v.materialized && [...schemaData.indexes.values()].some((i) => i.tableOid === v.oid),
|
|
28264
28738
|
!v.materialized || v.matRows !== null,
|
|
28265
28739
|
relPersistence(v)
|
|
28266
28740
|
);
|
|
@@ -28526,7 +29000,7 @@ function pgIndex(ctx) {
|
|
|
28526
29000
|
const valid = i.valid !== false;
|
|
28527
29001
|
rows.push([
|
|
28528
29002
|
i.oid ?? 0,
|
|
28529
|
-
table?.oid ?? 0,
|
|
29003
|
+
table?.oid ?? i.tableOid ?? 0,
|
|
28530
29004
|
indexAttributeCount(i),
|
|
28531
29005
|
i.columns.length,
|
|
28532
29006
|
i.unique,
|
|
@@ -28698,7 +29172,7 @@ function pgStatUserIndexes(ctx) {
|
|
|
28698
29172
|
for (const index of schema.indexes.values()) {
|
|
28699
29173
|
const table = schema.tables.get(index.table);
|
|
28700
29174
|
rows.push([
|
|
28701
|
-
table?.oid ?? 0,
|
|
29175
|
+
table?.oid ?? index.tableOid ?? 0,
|
|
28702
29176
|
index.oid ?? 0,
|
|
28703
29177
|
schema.name,
|
|
28704
29178
|
index.table,
|
|
@@ -29293,26 +29767,6 @@ function runTriggerBody(env, table, stmts, vars) {
|
|
|
29293
29767
|
}
|
|
29294
29768
|
}
|
|
29295
29769
|
}
|
|
29296
|
-
function triggerScope(table, newRow, oldRow) {
|
|
29297
|
-
const cols = [];
|
|
29298
|
-
const row = [];
|
|
29299
|
-
const rangeVars = /* @__PURE__ */ new Set();
|
|
29300
|
-
if (newRow) {
|
|
29301
|
-
rangeVars.add("new");
|
|
29302
|
-
for (let i = 0; i < table.columns.length; i++) {
|
|
29303
|
-
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "new" });
|
|
29304
|
-
row.push(newRow[i] ?? null);
|
|
29305
|
-
}
|
|
29306
|
-
}
|
|
29307
|
-
if (oldRow) {
|
|
29308
|
-
rangeVars.add("old");
|
|
29309
|
-
for (let i = 0; i < table.columns.length; i++) {
|
|
29310
|
-
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "old" });
|
|
29311
|
-
row.push(oldRow[i] ?? null);
|
|
29312
|
-
}
|
|
29313
|
-
}
|
|
29314
|
-
return new RowScope(cols, row, null, rangeVars);
|
|
29315
|
-
}
|
|
29316
29770
|
function executeTrigger(env, table, trigger, _event, oldRow, newRow) {
|
|
29317
29771
|
const state = env.ctx.state;
|
|
29318
29772
|
if (trigger.when !== null && !evalPredicate(env, triggerScope(table, newRow, oldRow), trigger.when)) {
|
|
@@ -29957,13 +30411,63 @@ function executeCreateSequence(env, stmt) {
|
|
|
29957
30411
|
schema.sequences.set(name2, seq);
|
|
29958
30412
|
return commandResult("CREATE SEQUENCE", 0);
|
|
29959
30413
|
}
|
|
30414
|
+
function renameSequenceReferences(env, seq, newName) {
|
|
30415
|
+
const state = env.ctx.state;
|
|
30416
|
+
const matches2 = (value) => {
|
|
30417
|
+
try {
|
|
30418
|
+
const input = parseRelationInput(value);
|
|
30419
|
+
if ("oid" in input) return input.oid === seq.oid;
|
|
30420
|
+
return state.findSequence(input.parts)?.oid === seq.oid;
|
|
30421
|
+
} catch {
|
|
30422
|
+
return false;
|
|
30423
|
+
}
|
|
30424
|
+
};
|
|
30425
|
+
const rewrite = (value) => {
|
|
30426
|
+
if (Array.isArray(value)) return value.map(rewrite);
|
|
30427
|
+
if (value === null || typeof value !== "object") return value;
|
|
30428
|
+
const node = value;
|
|
30429
|
+
const updated = Object.fromEntries(Object.entries(node).map(([key, child]) => [key, rewrite(child)]));
|
|
30430
|
+
const rewriteLiteral = (literal2) => {
|
|
30431
|
+
if (literal2 && typeof literal2 === "object" && "type" in literal2 && literal2.type === "string_lit" && "value" in literal2 && typeof literal2.value === "string" && matches2(literal2.value)) {
|
|
30432
|
+
return { ...literal2, value: [seq.schema, newName].map(quoteIdent).join(".") };
|
|
30433
|
+
}
|
|
30434
|
+
return literal2;
|
|
30435
|
+
};
|
|
30436
|
+
if (node.type === "func" && Array.isArray(node.name) && ["nextval", "currval", "setval"].includes(String(node.name.at(-1))) && Array.isArray(updated.args))
|
|
30437
|
+
updated.args[0] = rewriteLiteral(updated.args[0]);
|
|
30438
|
+
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")
|
|
30439
|
+
updated.expr = rewriteLiteral(updated.expr);
|
|
30440
|
+
return updated;
|
|
30441
|
+
};
|
|
30442
|
+
for (const schema of state.schemas.values()) {
|
|
30443
|
+
for (const table of [...schema.tables.values()]) {
|
|
30444
|
+
const writable = state.ensureWritableTable(table);
|
|
30445
|
+
for (const column of writable.columns) {
|
|
30446
|
+
if (column.defaultExpr) column.defaultExpr = rewrite(column.defaultExpr);
|
|
30447
|
+
if (column.identity?.sequence === `${seq.schema}.${seq.name}`)
|
|
30448
|
+
column.identity = { ...column.identity, sequence: `${seq.schema}.${newName}` };
|
|
30449
|
+
}
|
|
30450
|
+
}
|
|
30451
|
+
}
|
|
30452
|
+
}
|
|
29960
30453
|
function executeAlterSequence(env, stmt) {
|
|
29961
30454
|
const state = env.ctx.state;
|
|
29962
|
-
const
|
|
29963
|
-
if (!
|
|
30455
|
+
const foundSequence = state.findSequence(stmt.name);
|
|
30456
|
+
if (!foundSequence) {
|
|
29964
30457
|
if (stmt.ifExists) return commandResult("ALTER SEQUENCE", 0);
|
|
29965
30458
|
throw pgError("undefined_table", `relation "${stmt.name.join(".")}" does not exist`, "42P01");
|
|
29966
30459
|
}
|
|
30460
|
+
const seq = state.ensureWritableSequence(foundSequence);
|
|
30461
|
+
if (stmt.renameTo) {
|
|
30462
|
+
const schema = state.getSchema(seq.schema);
|
|
30463
|
+
if (schema.hasRelation(stmt.renameTo))
|
|
30464
|
+
throw pgError("duplicate_table", `relation "${stmt.renameTo}" already exists`, "42P07");
|
|
30465
|
+
renameSequenceReferences(env, seq, stmt.renameTo);
|
|
30466
|
+
schema.sequences.delete(seq.name);
|
|
30467
|
+
seq.name = stmt.renameTo;
|
|
30468
|
+
schema.sequences.set(seq.name, seq);
|
|
30469
|
+
return commandResult("ALTER SEQUENCE", 0);
|
|
30470
|
+
}
|
|
29967
30471
|
const o = stmt.options;
|
|
29968
30472
|
if (o.logged !== void 0) {
|
|
29969
30473
|
setSequenceLogged(state, seq, o.logged);
|
|
@@ -30021,7 +30525,7 @@ function buildColumn(env, schema, tableName2, def, out, taken) {
|
|
|
30021
30525
|
col.defaultExpr = {
|
|
30022
30526
|
type: "func",
|
|
30023
30527
|
name: ["nextval"],
|
|
30024
|
-
args: [{ type: "string_lit", value:
|
|
30528
|
+
args: [{ type: "string_lit", value: [schema.name, seqName].map(quoteIdent).join(".") }]
|
|
30025
30529
|
};
|
|
30026
30530
|
}
|
|
30027
30531
|
for (const c of def.constraints) {
|
|
@@ -30274,7 +30778,11 @@ function executeCreateTableAs(env, stmt) {
|
|
|
30274
30778
|
const table = new TableData(schema.name, name2, columns, state.nextOid(), stmt.temp);
|
|
30275
30779
|
table.unlogged = stmt.unlogged === true;
|
|
30276
30780
|
if (stmt.withData) {
|
|
30277
|
-
for (const row of rel3.rows)
|
|
30781
|
+
for (const row of rel3.rows) {
|
|
30782
|
+
const stored = row.slice();
|
|
30783
|
+
table.rowXmins.set(stored, env.ctx.rowVersionXid());
|
|
30784
|
+
table.mutableRows().push(stored);
|
|
30785
|
+
}
|
|
30278
30786
|
}
|
|
30279
30787
|
schema.tables.set(name2, table);
|
|
30280
30788
|
const count = stmt.withData ? table.rowCount() : 0;
|
|
@@ -30282,7 +30790,8 @@ function executeCreateTableAs(env, stmt) {
|
|
|
30282
30790
|
}
|
|
30283
30791
|
function executeCreateIndex(env, stmt) {
|
|
30284
30792
|
const state = env.ctx.state;
|
|
30285
|
-
const
|
|
30793
|
+
const view = state.findView(stmt.table);
|
|
30794
|
+
const table = state.findTable(stmt.table) ?? (view?.materialized ? materializedTable(view) : void 0);
|
|
30286
30795
|
if (!table) {
|
|
30287
30796
|
throw pgError("undefined_table", `relation "${stmt.table.join(".")}" does not exist`, "42P01");
|
|
30288
30797
|
}
|
|
@@ -30394,13 +30903,22 @@ function executeRefreshMatView(env, stmt) {
|
|
|
30394
30903
|
if (!found?.materialized) {
|
|
30395
30904
|
throw pgError("undefined_table", `materialized view "${stmt.name.join(".")}" does not exist`, "42P01");
|
|
30396
30905
|
}
|
|
30906
|
+
const rel3 = executeSelectStmt(matviewQueryEnv(env, !stmt.withData), found.query);
|
|
30907
|
+
const next = {
|
|
30908
|
+
...found,
|
|
30909
|
+
matColumns: rel3.columns.map((c, i) => ({
|
|
30910
|
+
name: found.columns?.[i] ?? c.name,
|
|
30911
|
+
type: c.type === UNKNOWN ? "text" : c.type
|
|
30912
|
+
})),
|
|
30913
|
+
matRows: stmt.withData ? rel3.rows : null
|
|
30914
|
+
};
|
|
30915
|
+
const table = materializedTable(next);
|
|
30916
|
+
for (const index of env.ctx.state.getSchema(found.schema).indexes.values()) {
|
|
30917
|
+
if (index.tableOid === found.oid && index.valid !== false) assertUniqueIndexBuildable(env, table, index);
|
|
30918
|
+
}
|
|
30397
30919
|
const view = env.ctx.state.ensureWritableView(found);
|
|
30398
|
-
|
|
30399
|
-
view.
|
|
30400
|
-
name: view.columns?.[i] ?? c.name,
|
|
30401
|
-
type: c.type === UNKNOWN ? "text" : c.type
|
|
30402
|
-
}));
|
|
30403
|
-
view.matRows = stmt.withData ? rel3.rows : null;
|
|
30920
|
+
view.matColumns = next.matColumns;
|
|
30921
|
+
view.matRows = next.matRows;
|
|
30404
30922
|
return commandResult("REFRESH MATERIALIZED VIEW", 0);
|
|
30405
30923
|
}
|
|
30406
30924
|
function executeCreateSchema(env, stmt) {
|
|
@@ -30533,6 +31051,12 @@ function executeCreateFunction(env, stmt) {
|
|
|
30533
31051
|
language: lang,
|
|
30534
31052
|
body,
|
|
30535
31053
|
rawBody: stmt.body,
|
|
31054
|
+
settings: Object.fromEntries(
|
|
31055
|
+
Object.entries(stmt.settings ?? {}).map(([key, value]) => [
|
|
31056
|
+
key,
|
|
31057
|
+
value === "__from_current__" ? state.getSetting(key) ?? "" : value
|
|
31058
|
+
])
|
|
31059
|
+
),
|
|
30536
31060
|
strict: stmt.strict,
|
|
30537
31061
|
oid: state.nextOid()
|
|
30538
31062
|
};
|
|
@@ -30542,6 +31066,8 @@ function executeCreateFunction(env, stmt) {
|
|
|
30542
31066
|
return commandResult("CREATE FUNCTION", 0);
|
|
30543
31067
|
}
|
|
30544
31068
|
function executeCreateTrigger(env, stmt) {
|
|
31069
|
+
if (stmt.constraint && (stmt.timing !== "after" || !stmt.forEachRow))
|
|
31070
|
+
throw pgError("syntax", "constraint triggers must be AFTER ROW triggers", "42601");
|
|
30545
31071
|
const state = env.ctx.state;
|
|
30546
31072
|
const found = state.findTable(stmt.table);
|
|
30547
31073
|
if (!found) {
|
|
@@ -30560,6 +31086,9 @@ function executeCreateTrigger(env, stmt) {
|
|
|
30560
31086
|
}
|
|
30561
31087
|
const meta = {
|
|
30562
31088
|
name: stmt.name,
|
|
31089
|
+
constraint: stmt.constraint,
|
|
31090
|
+
deferrable: stmt.deferrable,
|
|
31091
|
+
initiallyDeferred: stmt.initiallyDeferred,
|
|
30563
31092
|
timing: stmt.timing,
|
|
30564
31093
|
events: stmt.events,
|
|
30565
31094
|
forEachRow: stmt.forEachRow,
|
|
@@ -30712,6 +31241,7 @@ function executeAlterTable(env, stmt) {
|
|
|
30712
31241
|
}
|
|
30713
31242
|
const next = row.slice();
|
|
30714
31243
|
next[idx] = nv;
|
|
31244
|
+
table.rowXmins.set(next, table.rowXmins.get(rows[i]) ?? 2);
|
|
30715
31245
|
rows[i] = next;
|
|
30716
31246
|
}
|
|
30717
31247
|
col.type = resolved.column;
|
|
@@ -30813,6 +31343,11 @@ function executeAlterTable(env, stmt) {
|
|
|
30813
31343
|
);
|
|
30814
31344
|
}
|
|
30815
31345
|
table.columns[idx].name = action.to;
|
|
31346
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
31347
|
+
if (seq.ownedBy?.table === table.name && seq.ownedBy.column === action.from) {
|
|
31348
|
+
state.ensureWritableSequence(seq).ownedBy = { table: table.name, column: action.to };
|
|
31349
|
+
}
|
|
31350
|
+
}
|
|
30816
31351
|
for (const con of table.constraints) {
|
|
30817
31352
|
if (con.kind === "primary_key" || con.kind === "unique" || con.kind === "foreign_key") {
|
|
30818
31353
|
con.columns = con.columns.map((c) => c === action.from ? action.to : c);
|
|
@@ -30849,6 +31384,11 @@ function executeAlterTable(env, stmt) {
|
|
|
30849
31384
|
throw pgError("duplicate_table", `relation "${action.to}" already exists`, "42P07");
|
|
30850
31385
|
}
|
|
30851
31386
|
const oldName = table.name;
|
|
31387
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
31388
|
+
if (seq.ownedBy?.table === oldName) {
|
|
31389
|
+
state.ensureWritableSequence(seq).ownedBy = { ...seq.ownedBy, table: action.to };
|
|
31390
|
+
}
|
|
31391
|
+
}
|
|
30852
31392
|
schema.tables.delete(table.name);
|
|
30853
31393
|
table.name = action.to;
|
|
30854
31394
|
schema.tables.set(action.to, table);
|
|
@@ -31328,7 +31868,16 @@ function alterTableIsSelfContained(stmt) {
|
|
|
31328
31868
|
return stmt.actions.length === 1 && action !== void 0 && SELF_CONTAINED_ALTER_ACTIONS.has(action.kind);
|
|
31329
31869
|
}
|
|
31330
31870
|
function executeStatement(env, stmt) {
|
|
31331
|
-
if (!RESHAPES_TABLES.has(stmt.type))
|
|
31871
|
+
if (!RESHAPES_TABLES.has(stmt.type)) {
|
|
31872
|
+
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))) {
|
|
31873
|
+
return withStatementRollback(env, () => {
|
|
31874
|
+
const result = dispatchStatement(env, stmt);
|
|
31875
|
+
flushConstraintTriggers(env.ctx.state);
|
|
31876
|
+
return result;
|
|
31877
|
+
});
|
|
31878
|
+
}
|
|
31879
|
+
return dispatchStatement(env, stmt);
|
|
31880
|
+
}
|
|
31332
31881
|
try {
|
|
31333
31882
|
return dispatchStatement(env, stmt);
|
|
31334
31883
|
} finally {
|
|
@@ -31387,6 +31936,9 @@ function dispatchStatement(env, stmt) {
|
|
|
31387
31936
|
return executeRefreshMatView(env, stmt);
|
|
31388
31937
|
case "transaction":
|
|
31389
31938
|
return executeTransaction(env, stmt);
|
|
31939
|
+
case "set_constraints":
|
|
31940
|
+
setConstraints(env.ctx.state, stmt);
|
|
31941
|
+
return commandResult("SET CONSTRAINTS", 0);
|
|
31390
31942
|
case "set":
|
|
31391
31943
|
return executeSet(env, stmt);
|
|
31392
31944
|
case "show":
|
|
@@ -32710,6 +33262,7 @@ function encodeDatabaseState(state, runtime) {
|
|
|
32710
33262
|
writeBjv(
|
|
32711
33263
|
w,
|
|
32712
33264
|
{
|
|
33265
|
+
xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
|
|
32713
33266
|
name: table.name,
|
|
32714
33267
|
schema: table.schema,
|
|
32715
33268
|
columns: table.columns,
|
|
@@ -32807,8 +33360,14 @@ function decodeInner(snapshot, prng, clock) {
|
|
|
32807
33360
|
table.constraints = meta.constraints;
|
|
32808
33361
|
table.triggers = meta.triggers;
|
|
32809
33362
|
table.unlogged = meta.unlogged === true;
|
|
33363
|
+
table.slabXmins = meta.xmins ?? null;
|
|
33364
|
+
state.xidCounter = Math.max(
|
|
33365
|
+
state.xidCounter,
|
|
33366
|
+
(meta.xmins ?? []).reduce((max, xid) => Math.max(max, xid + 1), 3)
|
|
33367
|
+
);
|
|
32810
33368
|
if (meta.stats) state.tableStats.set(table.oid, meta.stats);
|
|
32811
33369
|
const rowCount = readVarintU32(r);
|
|
33370
|
+
if (meta.xmins && meta.xmins.length !== rowCount) throw snapshotError();
|
|
32812
33371
|
const slabColumns = [];
|
|
32813
33372
|
for (let c = 0; c < meta.columns.length; c++)
|
|
32814
33373
|
slabColumns.push(readPackedColumn(r, rowCount, intern, meta.columns[c].type.id));
|
|
@@ -33252,6 +33811,8 @@ function validateTableMetaBjv(value) {
|
|
|
33252
33811
|
if (!isRecord2(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
|
|
33253
33812
|
if (!Array.isArray(value.columns)) throw snapshotError();
|
|
33254
33813
|
for (const col of value.columns) validateColumnMeta(col);
|
|
33814
|
+
if (value.xmins !== void 0 && (!Array.isArray(value.xmins) || value.xmins.some((xid) => !Number.isInteger(xid) || xid < 2 || xid > 4294967295)))
|
|
33815
|
+
throw snapshotError();
|
|
33255
33816
|
}
|
|
33256
33817
|
function validateViewMetaBjv(value) {
|
|
33257
33818
|
if (!isRecord2(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
|
|
@@ -33345,6 +33906,7 @@ function forceSchemaIntern(pool, state, schemas) {
|
|
|
33345
33906
|
pool.forceId(table.name);
|
|
33346
33907
|
pool.forceId(table.schema);
|
|
33347
33908
|
forceBjvStrings(pool, {
|
|
33909
|
+
xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
|
|
33348
33910
|
name: table.name,
|
|
33349
33911
|
schema: table.schema,
|
|
33350
33912
|
columns: table.columns,
|
|
@@ -33825,11 +34387,13 @@ var ScramServer = class {
|
|
|
33825
34387
|
var splitStatements = (script) => {
|
|
33826
34388
|
const out = [];
|
|
33827
34389
|
let start3 = 0;
|
|
34390
|
+
let hasSql = false;
|
|
33828
34391
|
let i = 0;
|
|
33829
34392
|
const n = script.length;
|
|
33830
34393
|
const push = (end) => {
|
|
33831
34394
|
const text = script.slice(start3, end).trim();
|
|
33832
|
-
if (
|
|
34395
|
+
if (hasSql) out.push(text);
|
|
34396
|
+
hasSql = false;
|
|
33833
34397
|
};
|
|
33834
34398
|
while (i < n) {
|
|
33835
34399
|
const c = script[i];
|
|
@@ -33851,9 +34415,11 @@ var splitStatements = (script) => {
|
|
|
33851
34415
|
i += 2;
|
|
33852
34416
|
} else i++;
|
|
33853
34417
|
}
|
|
34418
|
+
if (depth > 0) hasSql = true;
|
|
33854
34419
|
continue;
|
|
33855
34420
|
}
|
|
33856
34421
|
if (c === "'" || c === '"') {
|
|
34422
|
+
hasSql = true;
|
|
33857
34423
|
const escaped = c === "'" && /[eE]/.test(script[i - 1] ?? "") && !/[\w$]/.test(script[i - 2] ?? "");
|
|
33858
34424
|
i++;
|
|
33859
34425
|
while (i < n) {
|
|
@@ -33876,6 +34442,7 @@ var splitStatements = (script) => {
|
|
|
33876
34442
|
if (c === "$") {
|
|
33877
34443
|
const m = /^\$([A-Za-z_][A-Za-z0-9_]*)?\$/.exec(script.slice(i, i + 64));
|
|
33878
34444
|
if (m) {
|
|
34445
|
+
hasSql = true;
|
|
33879
34446
|
const tag = m[0];
|
|
33880
34447
|
const end = script.indexOf(tag, i + tag.length);
|
|
33881
34448
|
i = end === -1 ? n : end + tag.length;
|
|
@@ -33886,6 +34453,7 @@ var splitStatements = (script) => {
|
|
|
33886
34453
|
push(i);
|
|
33887
34454
|
start3 = i + 1;
|
|
33888
34455
|
}
|
|
34456
|
+
if (c !== ";" && !/\s/.test(c)) hasSql = true;
|
|
33889
34457
|
i++;
|
|
33890
34458
|
}
|
|
33891
34459
|
push(n);
|
|
@@ -34318,7 +34886,16 @@ var binaryValue = (type, text) => {
|
|
|
34318
34886
|
}
|
|
34319
34887
|
};
|
|
34320
34888
|
var binaryEncodable = (type) => TEXT_TYPES2.has(type) || ["bool", "int2", "int4", "oid", "int8", "float4", "float8", "bytea", "uuid"].includes(type);
|
|
34321
|
-
var
|
|
34889
|
+
var setsSessionConfig = (node) => {
|
|
34890
|
+
if (Array.isArray(node)) return node.some(setsSessionConfig);
|
|
34891
|
+
if (typeof node !== "object" || node === null) return false;
|
|
34892
|
+
const call = node;
|
|
34893
|
+
if (call.type === "func" && call.name?.at(-1) === "set_config") return true;
|
|
34894
|
+
return Object.values(node).some(setsSessionConfig);
|
|
34895
|
+
};
|
|
34896
|
+
var mutatesDatabase = (sql) => parse(sql).some(
|
|
34897
|
+
(stmt) => !["select", "show", "explain", "transaction", "no_op"].includes(stmt.type) || stmt.type === "select" && setsSessionConfig(stmt)
|
|
34898
|
+
);
|
|
34322
34899
|
var NEVER_WRITES = /* @__PURE__ */ new Set(["show", "set", "reset", "transaction", "no_op", "prepare", "deallocate"]);
|
|
34323
34900
|
var WRITE_NODES = /* @__PURE__ */ new Set(["insert", "update", "delete"]);
|
|
34324
34901
|
var containsWrite = (db, node) => {
|
|
@@ -34943,6 +35520,7 @@ var Connection = class {
|
|
|
34943
35520
|
}
|
|
34944
35521
|
return outcome;
|
|
34945
35522
|
} finally {
|
|
35523
|
+
workspace?.transactions.rollback();
|
|
34946
35524
|
workspace?.close();
|
|
34947
35525
|
}
|
|
34948
35526
|
}
|
|
@@ -34959,7 +35537,7 @@ var Connection = class {
|
|
|
34959
35537
|
if (stmt?.type !== "transaction") throw pgError2("syntax", "invalid transaction command", "42601");
|
|
34960
35538
|
switch (stmt.action) {
|
|
34961
35539
|
case "begin":
|
|
34962
|
-
this.transaction ??= { statements: [], savepoints: [] };
|
|
35540
|
+
this.transaction ??= { statements: [], savepoints: [], xid: this.database.state.allocateXid() };
|
|
34963
35541
|
return command("BEGIN");
|
|
34964
35542
|
case "commit": {
|
|
34965
35543
|
const transaction = this.transaction;
|
|
@@ -34968,6 +35546,7 @@ var Connection = class {
|
|
|
34968
35546
|
this.inSession(
|
|
34969
35547
|
this.database,
|
|
34970
35548
|
() => this.database.transaction(() => {
|
|
35549
|
+
this.database.state.transactionXid = transaction.xid;
|
|
34971
35550
|
for (const logged of transaction.statements) this.replay(this.database, logged);
|
|
34972
35551
|
})
|
|
34973
35552
|
);
|
|
@@ -35017,8 +35596,10 @@ var Connection = class {
|
|
|
35017
35596
|
});
|
|
35018
35597
|
workspace.state.settings = new Map(this.settings);
|
|
35019
35598
|
workspace.state.settingDefaults = this.settingDefaults;
|
|
35599
|
+
workspace.transactions.begin();
|
|
35600
|
+
workspace.state.transactionXid = this.transaction?.xid ?? null;
|
|
35020
35601
|
for (const logged of this.transaction?.statements ?? []) {
|
|
35021
|
-
|
|
35602
|
+
this.replay(workspace, logged);
|
|
35022
35603
|
}
|
|
35023
35604
|
return workspace;
|
|
35024
35605
|
}
|