@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/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 === "stripe" ? ingressSupport.stripe : ingressSupport.other,
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 = validateArchive(input);
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 !== "stripe")
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.5.0" });
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-tools.js
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: options2.signal ?? AbortSignal.timeout(this.options.timeoutMs ?? 3e4)
4875
+ signal
4779
4876
  });
4780
- const data = await response.json();
4781
- if (!response.ok)
4782
- throw new FleetClientError(response.status, data);
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
- result[variable] = new URL(template.replace("{name}", encodeURIComponent(namespace)), secret.url).href;
5010
+ endpoint = new URL(template.replace("{name}", encodeURIComponent(namespace)), secret.url).href;
4853
5011
  } else {
4854
- const endpoint = secret.namespaces?.[namespace];
4855
- if (!endpoint)
5012
+ const selected = secret.namespaces?.[namespace];
5013
+ if (!selected)
4856
5014
  throw new Error(`missing namespace mapping ${namespace}/${entry.service}`);
4857
- result[variable] = endpoint;
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 = createRequire2(resolve2(process.cwd(), "package.json"));
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 = validateArchive(input);
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, { load: options2.load });
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 = async (name2, own2) => {
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 suffix of ["ingly", "edly", "ing", "ed"]) {
5783
- if (w.endsWith(suffix)) {
5784
- const stem = w.slice(0, -suffix.length);
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 [suffix, repl] of step2) {
5823
- if (w.endsWith(suffix)) {
5824
- if (w.length - suffix.length >= r1) w = w.slice(0, -suffix.length) + repl;
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 [suffix, repl] of step3) {
5844
- if (w.endsWith(suffix)) {
5845
- if (w.length - suffix.length >= r1) w = w.slice(0, -suffix.length) + repl;
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 suffix of step4) {
5872
- if (w.endsWith(suffix)) {
5873
- if (w.length - suffix.length >= r2) w = w.slice(0, -suffix.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 !== 1) invalidName();
8117
- return { name: names[0] };
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/transactions/manager.ts
9304
- var TransactionManager = class {
9305
- constructor(state) {
9306
- this.state = state;
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
- base = null;
9310
- savepoints = [];
9311
- freezeDepth = 0;
9312
- get inTransaction() {
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
- takeSnapshot() {
9316
- this.state.freezeShared();
9317
- this.freezeDepth++;
9318
- return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
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
- restore(snap) {
9321
- this.state.restoreFrom(snap.state);
9322
- this.state.prng.setState(snap.prngState);
9620
+ timezone() {
9621
+ return this.state.getSetting("timezone") ?? "UTC";
9323
9622
  }
9324
- thawOnce() {
9325
- if (this.freezeDepth > 0) {
9326
- this.state.thawShared();
9327
- this.freezeDepth--;
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
- begin() {
9331
- if (this.base !== null) {
9332
- return;
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
- this.base = this.takeSnapshot();
9335
- this.state.inTransaction = true;
9336
- assert(this.freezeDepth === 1, "BEGIN freeze depth");
9638
+ return null;
9337
9639
  }
9338
- commit() {
9339
- this.base = null;
9340
- this.savepoints = [];
9341
- this.state.inTransaction = false;
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
- rollback() {
9346
- if (this.base !== null) {
9347
- this.restore(this.base);
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
- this.base = null;
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
- savepoint(name2) {
9356
- if (this.base === null) {
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
- releaseSavepoint(name2) {
9362
- const idx = this.findSavepoint(name2);
9363
- this.savepoints.splice(idx);
9656
+ zoneOffsetForNaive(naiveMicros) {
9657
+ return zoneOffsetForNaive(this.timezone(), naiveMicros);
9364
9658
  }
9365
- rollbackToSavepoint(name2) {
9366
- const idx = this.findSavepoint(name2);
9367
- const sp = this.savepoints[idx];
9368
- this.restore(sp.snap);
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
- findSavepoint(name2) {
9372
- if (this.base === null) {
9373
- throw pgError("transaction_state", `SAVEPOINT can only be used in transaction blocks`, "25P01");
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
- reset() {
9381
- this.base = null;
9382
- this.savepoints = [];
9383
- this.state.inTransaction = false;
9384
- this.freezeDepth = 0;
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 suffix = ordinalSuffix(n);
11605
- out += rest.startsWith("TH") ? suffix.toUpperCase() : suffix;
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 suffix = 1; used(constraint.name); suffix++) constraint.name = `${base}${suffix}`;
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.set(name2, value);
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]).toLowerCase();
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
- if (!col.identity) return tv("text", null);
13783
- return tv(
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
- if (this.eatKw("constraint")) {
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.eatOp("=") || this.eatKw("to")) this.next();
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
- while (this.atKw("not") || this.atKw("deferrable") || this.atKw("initially")) {
21559
- this.pos++;
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 { type: "create_trigger", orReplace, name: name2, timing, events, table, forEachRow, when, funcName, funcArgs };
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: { ownedBy: void 0 },
21612
- ...{ renameTo: to }
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.atKw("constraints")) {
21931
- this.skipToStatementEnd();
21932
- return { type: "no_op", what: "SET CONSTRAINTS" };
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 keyOf = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(columns[i].type, v)).join("");
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 = keyOf(row);
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 = keyOf(row);
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
- if (colAliases && colAliases.length > rel3.columns.length) {
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 ${rel3.columns.length} columns available but ${colAliases.length} columns specified`,
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
- name: colAliases?.[i] ?? c.name,
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: table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
24396
- rows: table.rows
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 keyOf = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(types[i], v)).join("");
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 = keyOf(r);
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 = keyOf(r);
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 = keyOf(r);
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 = keyOf(r);
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 = keyOf(r);
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/constraints/enforce.ts
26049
- function tableScope(table, row) {
26050
- const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
26051
- return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
26052
- }
26053
- function checkNotNull(env, table, row) {
26054
- void env;
26055
- for (let i = 0; i < table.columns.length; i++) {
26056
- const c = table.columns[i];
26057
- if (c.notNull && (row[i] ?? null) === null) {
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
- function referencingConstraints(env, table) {
26210
- const out = [];
26211
- for (const schema of env.ctx.state.schemas.values()) {
26212
- for (const t of schema.tables.values()) {
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 out;
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
- false,
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 seq = state.findSequence(stmt.name);
29963
- if (!seq) {
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: `${schema.name}.${seqName}` }]
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) table.mutableRows().push(row.slice());
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 table = state.findTable(stmt.table);
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
- const rel3 = executeSelectStmt(matviewQueryEnv(env, !stmt.withData), view.query);
30399
- view.matColumns = rel3.columns.map((c, i) => ({
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)) return dispatchStatement(env, stmt);
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 (text.length > 0) out.push(text);
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 mutatesDatabase = (sql) => parse(sql).some((stmt) => !["select", "show", "explain", "transaction", "no_op"].includes(stmt.type));
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
- workspace.transaction(() => this.replay(workspace, logged));
35602
+ this.replay(workspace, logged);
35022
35603
  }
35023
35604
  return workspace;
35024
35605
  }