@dbsp/adapter-pgsql 3.4.0 → 3.5.1

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/index.d.ts CHANGED
@@ -960,6 +960,10 @@ declare class PgsqlTransactionTimeoutError extends Error {
960
960
  /**
961
961
  * Options for PgsqlAdapter.
962
962
  */
963
+ interface PgsqlPreparedStatementsOptions {
964
+ /** Maximum distinct compiled statements admitted per executor (default: 500). */
965
+ readonly maxStatements?: number;
966
+ }
963
967
  interface PgsqlAdapterOptions {
964
968
  /** Schema name for multi-tenant queries */
965
969
  readonly schemaName?: string;
@@ -978,6 +982,11 @@ interface PgsqlAdapterOptions {
978
982
  readonly defaultPkColumnName?: string;
979
983
  /** Convention for deriving FK column names: (tableName, pkName) => fkColumnName */
980
984
  readonly deriveFkColumnName?: FkColumnDerivation;
985
+ /**
986
+ * Opt in to node-postgres named prepared statements for compiled queries with
987
+ * parameters. `true` uses the default statement cap; an object overrides it.
988
+ */
989
+ readonly preparedStatements?: boolean | PgsqlPreparedStatementsOptions;
981
990
  }
982
991
  interface PgsqlPoolAdapterOptions extends PgsqlAdapterOptions {
983
992
  readonly borrowedClient?: false;
@@ -1042,6 +1051,8 @@ declare class PgsqlAdapter<DB = unknown> implements Adapter<DB> {
1042
1051
  private readonly naming;
1043
1052
  private readonly model;
1044
1053
  private readonly logger;
1054
+ private readonly preparedStatements;
1055
+ private readonly preparedStatementRegistry;
1045
1056
  private readonly _capabilities;
1046
1057
  private readonly defaultPk;
1047
1058
  private readonly deriveFk;
@@ -3585,4 +3596,4 @@ declare function escapeDiagnosticText(value: string): string;
3585
3596
  */
3586
3597
  declare function validateSqlExpression(sql: string, context: string): void;
3587
3598
 
3588
- export { ADD_CHECK_RULE_ID, ALTER_AUTHORITY_OBSERVATION, ALTER_COLUMN_SET_NOT_NULL_OPERATION_KIND, ALTER_TYPE_ADD_VALUE_OPERATION_KIND, ATTACH_LOGICAL_IDENTITY_OPERATION_KIND, type AddedEnumValue, type AlterColumnSetNotNullPayload, type AlterTypeAddValuePayload, type AttachLogicalIdentityPayload, type BatchValuesJoinDecision, COLUMN_EXISTS_OBSERVATION, CamelCaseNamingPlugin, type CanonicalizeCheckConstraintsOptions, type ChangeKind, CheckConstraintCanonicalizationError, type CheckConstraintCanonicalizationWarning, CheckConstraintNewEnumValueError, ColumnDefaultCanonicalizationError, type ColumnDefaultCanonicalizationWarning, type ComparePgsqlDatabaseSchemaOptions, type CompareSchemataOptions, type CompiledResult, type CompilerContext, type CompilerOptions, type CompilerState, type ConflictAction, type ConflictTarget, type CursorHoldOption, type CursorOptions, type CursorScrollOption, DBSP_LOGICAL_IDENTITY_TABLE, DBSP_META_SCHEMA, DBSP_TRANSITION_JOURNAL_TABLE, DBSP_TRANSITION_RUN_PLAN_TABLE, DBSP_TRANSITION_RUN_TABLE, DEFAULT_PK_COLUMN, DEFAULT_REDACTION_PATTERNS, type Decision, type DeleteConfig, type DetectedHierarchy, type DiffSummary, ENGINE_VERSION_OBSERVATION, ENUM_ADD_VALUE_RULE_ID, ENUM_LABEL_VISIBLE_OBSERVATION, ENUM_TYPE_EXISTS_OBSERVATION, type EnumAddValueMatch, type EnumAddValueRuleOptions, type ExplainFormat, type ExplainOptions, type ExplainPlan, ExpressionCanonicalizationUnavailableError, type ExpressionCanonicalizationWarning, type ExpressionHandler, type FetchDirection, type FetchOptions, type FkColumnDerivation, type GenerateDDLOptions, type IdentityAdoptionAsserter, IdentityNamingPlugin, type IncludeHandler, type IncludeResult, type IndexCapabilityContext, IndexFeatureUnsupportedError, type IndexRenderSpec, type InsertConfig, type IntrospectedModelIR, type IntrospectionOptions, InvalidIdentifierError, type JoinDecision, LOGICAL_IDENTITY_ADOPTION_RULE_ID, LOGICAL_IDENTITY_CARRIER_OBSERVATION, type LeafCompileFn, type LogicalIdentityAdoptionMatch, type LogicalIdentityAdoptionRuleOptions, MANUAL_SQL_OPERATION_KIND, type ManualSqlPayload, type MigrationRecord, type MigrationSQLOptions, NO_NULLS_GUARD, type NamingPlugin, NonConvergentSchemaDiffError, type NonConvergentSchemaDiffSurface, PG_INTROSPECTION_ARTIFACT, PG_OPERATION_PACK_ARTIFACT, PG_RULE_PACK_ARTIFACT, type ParamRefValidationResult, type ParsedMigrationFile, type PgAdvisoryLockKey, type PgAdvisoryLockResult, PgExecutionContractDerivationError, type PgTransitionClientLease, type PgTransitionPackOptions, PgsqlAdapter, type PgsqlAdapterOptions, PgsqlAdvisoryLockOptionsError, type PgsqlBorrowedClientAdapterOptions, PgsqlPinnedConnectionAbortSignalError, type PgsqlPoolAdapterOptions, PgsqlRawSqlTransactionControlError, PgsqlTransactionAbortSignalError, PgsqlTransactionAbortedCommitError, PgsqlTransactionAbortedError, PgsqlTransactionOptionsError, PgsqlTransactionTimeoutError, PlanCompiler, type PlanDecision, type PrecompiledJoinDecision, type RedactionConfig, type RedactionPattern, type RollbackOnlyPgsqlScope, SET_NOT_NULL_RULE_ID, type SchemaChange, type SchemaDiff, type SchemaScopeOptions, type SetNotNullMatch, type SetNotNullRuleOptions, type SetOperationResult, type SimplifiedPlanReport, type StreamConfig, type UpdateConfig, type UpsertConfig, type WhereDispatcher, type WhereHandler, acquirePgTransitionClient, assertCreateIndexSupported, assertCreateIndexesSupported, assertNoRepeatedExpressionSurfaceDrift, bm25Search, booleanSearch, boost, buildCloseCursor, buildDeclareCursor, buildExplain, buildExplainAnalyzeJson, buildExplainPlan, buildExplainVerbose, buildFetch, buildFetchAll, buildFetchFirst, buildFetchForward, buildFetchNext, buildOnConflictClause, buildStreamingStatements, camelCaseNaming, canGenerateCreateIndex, canonicalizeCheckConstraints, collectAndValidateParamRefs, comparePgsqlDatabaseSchema, compareSchemata, compileDelete, compileInsert, compileMutation, compilePlan, compileSetOperation, compileUpdate, compileUpsert, conditionalUpdate, cosineDistance, createAlterColumnSetNotNullOperationRuntime, createAlterTypeAddValueOperationRuntime, createAnyExpr, createAttachLogicalIdentityOperationRuntime, createEnumAddValueRule, createEqualityExpr, createLeafCompileFn, createLogicalIdentityAdoptionRule, createManualSqlOperationRuntime, createParamRef, createPgExecutionContract, createPgObservationIssuer, createPgTransitionLessor, createPgTransitionPack, createPgTransitionRunPersister, createPgsqlAdapter, createPgsqlCompileOnlyAdapter, createSetNotNullRule, createTypeCastParamRef, defaultFkDerivation, derivePostgresqlCapabilitiesForVersion, ensureMigrationsTable, ensureTransitionJournal, escapeDiagnosticText, evaluatePgExecutionContract, excludedRef, executePgObservationFromLessor, generateCreateIndex, generateCursorName, generateDDL, generateDownSQL, generateMigrationFile, generateMigrationSQL, generateSeries, getAppliedMigrations, getNamingPluginForDbCasing, getNextSchemaVersion, getRowEstimates, getTotalExecutionTime, identityNaming, innerProduct, introspect, isBatchValuesJoinDecision, isDestructiveDown, isJoinDecision, isMigrationApplied, isPrecompiledJoinDecision, isReservedKeyword, l2Distance, mapColumnType, mapOnDeleteAction, nextval, normalizeManualSqlPayload, parse, parseExplainJson, parseMigrationFile, pgTargetIdentityMismatch, rawDistance, readPgExecutionTargetFromClient, readPgObservationContextFromLessor, readTransitionJournal, recordMigration, redactParams, removeMigrationRecord, renderAlterColumnSetNotNullSql, renderAlterTypeAddValueSql, renderAttachLogicalIdentityLockSql, renderCreateDbspMetaSchemaSql, renderCreateIndex, renderCreateLogicalIdentityIndexesSql, renderCreateLogicalIdentitySideTableSql, renderCreateTransitionJournalTableSql, renderCreateTransitionRunPlanTableSql, renderCreateTransitionRunTableSql, renderInsertLogicalIdentitySql, renderNoNullsCheckSql, renderSetNotNullLockSql, resolveLogicalName, sanitizeForDisplay, score, validateIdentifier, validateIdentifiers, validateParamRef, validateQualifiedIdentifier, validateSqlExpression, vectorDims, withMigrationLock };
3599
+ export { ADD_CHECK_RULE_ID, ALTER_AUTHORITY_OBSERVATION, ALTER_COLUMN_SET_NOT_NULL_OPERATION_KIND, ALTER_TYPE_ADD_VALUE_OPERATION_KIND, ATTACH_LOGICAL_IDENTITY_OPERATION_KIND, type AddedEnumValue, type AlterColumnSetNotNullPayload, type AlterTypeAddValuePayload, type AttachLogicalIdentityPayload, type BatchValuesJoinDecision, COLUMN_EXISTS_OBSERVATION, CamelCaseNamingPlugin, type CanonicalizeCheckConstraintsOptions, type ChangeKind, CheckConstraintCanonicalizationError, type CheckConstraintCanonicalizationWarning, CheckConstraintNewEnumValueError, ColumnDefaultCanonicalizationError, type ColumnDefaultCanonicalizationWarning, type ComparePgsqlDatabaseSchemaOptions, type CompareSchemataOptions, type CompiledResult, type CompilerContext, type CompilerOptions, type CompilerState, type ConflictAction, type ConflictTarget, type CursorHoldOption, type CursorOptions, type CursorScrollOption, DBSP_LOGICAL_IDENTITY_TABLE, DBSP_META_SCHEMA, DBSP_TRANSITION_JOURNAL_TABLE, DBSP_TRANSITION_RUN_PLAN_TABLE, DBSP_TRANSITION_RUN_TABLE, DEFAULT_PK_COLUMN, DEFAULT_REDACTION_PATTERNS, type Decision, type DeleteConfig, type DetectedHierarchy, type DiffSummary, ENGINE_VERSION_OBSERVATION, ENUM_ADD_VALUE_RULE_ID, ENUM_LABEL_VISIBLE_OBSERVATION, ENUM_TYPE_EXISTS_OBSERVATION, type EnumAddValueMatch, type EnumAddValueRuleOptions, type ExplainFormat, type ExplainOptions, type ExplainPlan, ExpressionCanonicalizationUnavailableError, type ExpressionCanonicalizationWarning, type ExpressionHandler, type FetchDirection, type FetchOptions, type FkColumnDerivation, type GenerateDDLOptions, type IdentityAdoptionAsserter, IdentityNamingPlugin, type IncludeHandler, type IncludeResult, type IndexCapabilityContext, IndexFeatureUnsupportedError, type IndexRenderSpec, type InsertConfig, type IntrospectedModelIR, type IntrospectionOptions, InvalidIdentifierError, type JoinDecision, LOGICAL_IDENTITY_ADOPTION_RULE_ID, LOGICAL_IDENTITY_CARRIER_OBSERVATION, type LeafCompileFn, type LogicalIdentityAdoptionMatch, type LogicalIdentityAdoptionRuleOptions, MANUAL_SQL_OPERATION_KIND, type ManualSqlPayload, type MigrationRecord, type MigrationSQLOptions, NO_NULLS_GUARD, type NamingPlugin, NonConvergentSchemaDiffError, type NonConvergentSchemaDiffSurface, PG_INTROSPECTION_ARTIFACT, PG_OPERATION_PACK_ARTIFACT, PG_RULE_PACK_ARTIFACT, type ParamRefValidationResult, type ParsedMigrationFile, type PgAdvisoryLockKey, type PgAdvisoryLockResult, PgExecutionContractDerivationError, type PgTransitionClientLease, type PgTransitionPackOptions, PgsqlAdapter, type PgsqlAdapterOptions, PgsqlAdvisoryLockOptionsError, type PgsqlBorrowedClientAdapterOptions, PgsqlPinnedConnectionAbortSignalError, type PgsqlPoolAdapterOptions, type PgsqlPreparedStatementsOptions, PgsqlRawSqlTransactionControlError, PgsqlTransactionAbortSignalError, PgsqlTransactionAbortedCommitError, PgsqlTransactionAbortedError, PgsqlTransactionOptionsError, PgsqlTransactionTimeoutError, PlanCompiler, type PlanDecision, type PrecompiledJoinDecision, type RedactionConfig, type RedactionPattern, type RollbackOnlyPgsqlScope, SET_NOT_NULL_RULE_ID, type SchemaChange, type SchemaDiff, type SchemaScopeOptions, type SetNotNullMatch, type SetNotNullRuleOptions, type SetOperationResult, type SimplifiedPlanReport, type StreamConfig, type UpdateConfig, type UpsertConfig, type WhereDispatcher, type WhereHandler, acquirePgTransitionClient, assertCreateIndexSupported, assertCreateIndexesSupported, assertNoRepeatedExpressionSurfaceDrift, bm25Search, booleanSearch, boost, buildCloseCursor, buildDeclareCursor, buildExplain, buildExplainAnalyzeJson, buildExplainPlan, buildExplainVerbose, buildFetch, buildFetchAll, buildFetchFirst, buildFetchForward, buildFetchNext, buildOnConflictClause, buildStreamingStatements, camelCaseNaming, canGenerateCreateIndex, canonicalizeCheckConstraints, collectAndValidateParamRefs, comparePgsqlDatabaseSchema, compareSchemata, compileDelete, compileInsert, compileMutation, compilePlan, compileSetOperation, compileUpdate, compileUpsert, conditionalUpdate, cosineDistance, createAlterColumnSetNotNullOperationRuntime, createAlterTypeAddValueOperationRuntime, createAnyExpr, createAttachLogicalIdentityOperationRuntime, createEnumAddValueRule, createEqualityExpr, createLeafCompileFn, createLogicalIdentityAdoptionRule, createManualSqlOperationRuntime, createParamRef, createPgExecutionContract, createPgObservationIssuer, createPgTransitionLessor, createPgTransitionPack, createPgTransitionRunPersister, createPgsqlAdapter, createPgsqlCompileOnlyAdapter, createSetNotNullRule, createTypeCastParamRef, defaultFkDerivation, derivePostgresqlCapabilitiesForVersion, ensureMigrationsTable, ensureTransitionJournal, escapeDiagnosticText, evaluatePgExecutionContract, excludedRef, executePgObservationFromLessor, generateCreateIndex, generateCursorName, generateDDL, generateDownSQL, generateMigrationFile, generateMigrationSQL, generateSeries, getAppliedMigrations, getNamingPluginForDbCasing, getNextSchemaVersion, getRowEstimates, getTotalExecutionTime, identityNaming, innerProduct, introspect, isBatchValuesJoinDecision, isDestructiveDown, isJoinDecision, isMigrationApplied, isPrecompiledJoinDecision, isReservedKeyword, l2Distance, mapColumnType, mapOnDeleteAction, nextval, normalizeManualSqlPayload, parse, parseExplainJson, parseMigrationFile, pgTargetIdentityMismatch, rawDistance, readPgExecutionTargetFromClient, readPgObservationContextFromLessor, readTransitionJournal, recordMigration, redactParams, removeMigrationRecord, renderAlterColumnSetNotNullSql, renderAlterTypeAddValueSql, renderAttachLogicalIdentityLockSql, renderCreateDbspMetaSchemaSql, renderCreateIndex, renderCreateLogicalIdentityIndexesSql, renderCreateLogicalIdentitySideTableSql, renderCreateTransitionJournalTableSql, renderCreateTransitionRunPlanTableSql, renderCreateTransitionRunTableSql, renderInsertLogicalIdentitySql, renderNoNullsCheckSql, renderSetNotNullLockSql, resolveLogicalName, sanitizeForDisplay, score, validateIdentifier, validateIdentifiers, validateParamRef, validateQualifiedIdentifier, validateSqlExpression, vectorDims, withMigrationLock };
package/dist/index.js CHANGED
@@ -23010,6 +23010,125 @@ function matchGlob(pattern, value) {
23010
23010
 
23011
23011
  // src/pgsql-adapter.ts
23012
23012
  init_naming_plugin();
23013
+
23014
+ // src/prepared-statements.ts
23015
+ import { createHash as createHash2 } from "crypto";
23016
+ var DEFAULT_MAX_PREPARED_STATEMENTS = 500;
23017
+ var PREPARED_STATEMENT_NAMESPACE = "dbsp_ps_";
23018
+ function derivePreparedStatementFingerprint(sql) {
23019
+ return createHash2("sha256").update(sql).digest("hex");
23020
+ }
23021
+ function derivePreparedStatementName(sql) {
23022
+ return `${PREPARED_STATEMENT_NAMESPACE}${derivePreparedStatementFingerprint(sql).slice(0, 32)}`;
23023
+ }
23024
+ var PreparedStatementRegistry = class {
23025
+ constructor(maxStatements, hashName = derivePreparedStatementName) {
23026
+ this.maxStatements = maxStatements;
23027
+ this.hashName = hashName;
23028
+ }
23029
+ maxStatements;
23030
+ hashName;
23031
+ candidates = /* @__PURE__ */ new Set();
23032
+ namesByFingerprint = /* @__PURE__ */ new Map();
23033
+ fingerprintsByName = /* @__PURE__ */ new Map();
23034
+ pendingByFingerprint = /* @__PURE__ */ new Map();
23035
+ collisionRejectedFingerprints = /* @__PURE__ */ new Set();
23036
+ nextGeneration = 0;
23037
+ /**
23038
+ * Reserves a name only from the second sighting onward. Call confirm to commit
23039
+ * executor-scoped admission after a successful named execution or a
23040
+ * caller-classified positionless protocol-shaped failure. Call abort for a
23041
+ * local, position-bearing, collision, or verified infrastructure failure.
23042
+ */
23043
+ admit(sql) {
23044
+ const fingerprint = derivePreparedStatementFingerprint(sql);
23045
+ if (this.collisionRejectedFingerprints.has(fingerprint)) return void 0;
23046
+ const knownName = this.namesByFingerprint.get(fingerprint);
23047
+ if (knownName !== void 0) return { name: knownName };
23048
+ const pending = this.pendingByFingerprint.get(fingerprint);
23049
+ if (pending !== void 0) {
23050
+ return this.reserveAttempt(fingerprint, pending);
23051
+ }
23052
+ if (!this.candidates.delete(fingerprint)) {
23053
+ if (this.atCapacity()) return void 0;
23054
+ if (this.candidates.size >= this.maxStatements) {
23055
+ const oldest = this.candidates.values().next().value;
23056
+ if (oldest !== void 0) this.candidates.delete(oldest);
23057
+ }
23058
+ this.candidates.add(fingerprint);
23059
+ return void 0;
23060
+ }
23061
+ if (this.atCapacity()) return void 0;
23062
+ const name = this.hashName(sql);
23063
+ const existingFingerprint = this.fingerprintsByName.get(name);
23064
+ if (existingFingerprint !== void 0 && existingFingerprint !== fingerprint) {
23065
+ this.rejectHashCollision(fingerprint);
23066
+ return void 0;
23067
+ }
23068
+ this.fingerprintsByName.set(name, fingerprint);
23069
+ const reservation = this.reserveAttempt(fingerprint, {
23070
+ name,
23071
+ generations: /* @__PURE__ */ new Set()
23072
+ });
23073
+ if (this.atCapacity()) this.candidates.clear();
23074
+ return reservation;
23075
+ }
23076
+ /** Commits executor-scoped admission after a successful named execution or a caller-classified server-reported failure. */
23077
+ confirm(reservation) {
23078
+ const pending = this.pendingByFingerprint.get(reservation.fingerprint);
23079
+ if (pending === void 0 || pending.name !== reservation.name || !pending.generations.has(reservation.generation))
23080
+ return;
23081
+ this.pendingByFingerprint.delete(reservation.fingerprint);
23082
+ this.namesByFingerprint.set(reservation.fingerprint, reservation.name);
23083
+ }
23084
+ /** Aborts only this still-pending attempt after a caller-classified failure that never reached server acceptance, never a later confirmation. */
23085
+ abort(reservation) {
23086
+ const pending = this.pendingByFingerprint.get(reservation.fingerprint);
23087
+ if (pending === void 0 || pending.name !== reservation.name || !pending.generations.delete(reservation.generation))
23088
+ return;
23089
+ if (pending.generations.size !== 0) return;
23090
+ this.pendingByFingerprint.delete(reservation.fingerprint);
23091
+ if (this.fingerprintsByName.get(reservation.name) === reservation.fingerprint) {
23092
+ this.fingerprintsByName.delete(reservation.name);
23093
+ }
23094
+ }
23095
+ atCapacity() {
23096
+ return this.namesByFingerprint.size + this.pendingByFingerprint.size >= this.maxStatements;
23097
+ }
23098
+ reserveAttempt(fingerprint, pending) {
23099
+ this.pendingByFingerprint.set(fingerprint, pending);
23100
+ const reservation = {
23101
+ fingerprint,
23102
+ name: pending.name,
23103
+ generation: this.nextGeneration++
23104
+ };
23105
+ pending.generations.add(reservation.generation);
23106
+ return { name: pending.name, reservation };
23107
+ }
23108
+ /** Keeps a colliding full fingerprint unnamed within a bounded registry. */
23109
+ rejectHashCollision(fingerprint) {
23110
+ if (this.collisionRejectedFingerprints.size >= this.maxStatements) {
23111
+ const oldest = this.collisionRejectedFingerprints.values().next().value;
23112
+ if (oldest !== void 0)
23113
+ this.collisionRejectedFingerprints.delete(oldest);
23114
+ }
23115
+ this.collisionRejectedFingerprints.add(fingerprint);
23116
+ this.candidates.delete(fingerprint);
23117
+ }
23118
+ };
23119
+ function normalizeMaxPreparedStatements(maxStatements) {
23120
+ const resolved = maxStatements === void 0 ? DEFAULT_MAX_PREPARED_STATEMENTS : maxStatements;
23121
+ if (!Number.isSafeInteger(resolved))
23122
+ throw new Error("preparedStatements.maxStatements must be a safe integer.");
23123
+ const normalized = resolved;
23124
+ if (normalized < 1)
23125
+ throw new Error(
23126
+ "preparedStatements.maxStatements must be greater than zero."
23127
+ );
23128
+ return normalized;
23129
+ }
23130
+
23131
+ // src/pgsql-adapter.ts
23013
23132
  init_cte_compiler();
23014
23133
 
23015
23134
  // src/set-operation.ts
@@ -23264,6 +23383,8 @@ var pgsqlAdapterInternalOptionsKey = /* @__PURE__ */ Symbol(
23264
23383
  "dbsp-pgsql-adapter-internal-options"
23265
23384
  );
23266
23385
  var activeClientScopes = /* @__PURE__ */ new WeakMap();
23386
+ var preparedStatementRegistries = /* @__PURE__ */ new WeakMap();
23387
+ var preparedStatementQuarantines = /* @__PURE__ */ new WeakMap();
23267
23388
  var PgsqlRawSqlTransactionControlError = class extends Error {
23268
23389
  dbspRawSqlTransactionControl = true;
23269
23390
  constructor(cause) {
@@ -23334,6 +23455,62 @@ function poolClientTransactionOpen(client) {
23334
23455
  function isPgErrorWithCode(error, code) {
23335
23456
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
23336
23457
  }
23458
+ function isDriverLocalPreparedStatementNameCollision(error, attemptedName) {
23459
+ const message = `Prepared statements must be unique - '${attemptedName}' was used for a different statement`;
23460
+ return error instanceof Error && !("code" in error) && error.message === message;
23461
+ }
23462
+ function isVerifiedPreparedStatementInfrastructureError(error) {
23463
+ if (!hasPostgresSqlStateCode(error)) return false;
23464
+ if (typeof error !== "object" || error === null) return false;
23465
+ const { code, routine } = error;
23466
+ return code === "0A000" && routine === "RevalidateCachedQuery" || code === "26000" && routine === "FetchPreparedStatement" || code === "42P05" && routine === "StorePreparedStatement";
23467
+ }
23468
+ function isPositionlessProtocolShapedFailure(error) {
23469
+ return hasPostgresSqlStateCode(error) && error.position === void 0 && !isVerifiedPreparedStatementInfrastructureError(error);
23470
+ }
23471
+ function hasPostgresSqlStateCode(error) {
23472
+ if (typeof error !== "object" || error === null) return false;
23473
+ const { code, severity } = error;
23474
+ return typeof severity === "string" && typeof code === "string" && /^[0-9A-Z]{5}$/.test(code);
23475
+ }
23476
+ function shouldAbortPreparedStatementReservation(error, executor, attemptedName) {
23477
+ if (typeof error === "object" && error !== null && "position" in error && error.position !== void 0)
23478
+ return true;
23479
+ if (isDriverLocalPreparedStatementNameCollision(error, attemptedName))
23480
+ return true;
23481
+ if (!isPoolClientLike(executor)) return !hasPostgresSqlStateCode(error);
23482
+ if (isPositionlessProtocolShapedFailure(error)) return false;
23483
+ return true;
23484
+ }
23485
+ function isVerifiedClientWidePreparedStatementLoss(error) {
23486
+ if (!hasPostgresSqlStateCode(error)) return false;
23487
+ if (typeof error !== "object" || error === null) return false;
23488
+ const { code, routine } = error;
23489
+ return code === "26000" && routine === "FetchPreparedStatement";
23490
+ }
23491
+ function isPreparedStatementQuarantined(client, sql) {
23492
+ const quarantine = preparedStatementQuarantines.get(client);
23493
+ return quarantine?.allStatements === true || quarantine?.fingerprints.has(derivePreparedStatementFingerprint(sql)) === true;
23494
+ }
23495
+ function hasPreparedStatementQuarantine(client) {
23496
+ return preparedStatementQuarantines.has(client);
23497
+ }
23498
+ function quarantinePreparedStatement(client, sql, clientWide) {
23499
+ const quarantine = preparedStatementQuarantines.get(client);
23500
+ if (quarantine !== void 0) {
23501
+ if (clientWide) {
23502
+ quarantine.allStatements = true;
23503
+ quarantine.fingerprints.clear();
23504
+ } else if (!quarantine.allStatements) {
23505
+ quarantine.fingerprints.add(derivePreparedStatementFingerprint(sql));
23506
+ }
23507
+ return;
23508
+ }
23509
+ preparedStatementQuarantines.set(client, {
23510
+ allStatements: clientWide,
23511
+ fingerprints: clientWide ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([derivePreparedStatementFingerprint(sql)])
23512
+ });
23513
+ }
23337
23514
  function describeTransactionOptionValue(value) {
23338
23515
  if (value === null) return "null";
23339
23516
  if (typeof value === "string") return `string ${JSON.stringify(value)}`;
@@ -24357,6 +24534,45 @@ function getDbspScopeTokenOption(options) {
24357
24534
  function getDbspScopeStateOption(options) {
24358
24535
  return isPgsqlAdapterInternalOptions(options) ? options.dbspScopeState : void 0;
24359
24536
  }
24537
+ function getPreparedStatementRegistryOption(options) {
24538
+ return isPgsqlAdapterInternalOptions(options) ? options.preparedStatementRegistry : void 0;
24539
+ }
24540
+ function getOrCreatePreparedStatementRegistry(executor, maxStatements) {
24541
+ const configured = preparedStatementRegistries.get(executor);
24542
+ if (configured === void 0) {
24543
+ const registry = new PreparedStatementRegistry(maxStatements);
24544
+ preparedStatementRegistries.set(executor, { maxStatements, registry });
24545
+ return registry;
24546
+ }
24547
+ if (configured.maxStatements !== maxStatements) {
24548
+ const executorKind = isPoolClientLike(executor) ? "borrowed client" : "pool";
24549
+ throw new Error(
24550
+ `preparedStatements.maxStatements is configured ${executorKind}-wide: expected ${configured.maxStatements}, received ${maxStatements}.`
24551
+ );
24552
+ }
24553
+ return configured.registry;
24554
+ }
24555
+ function normalizePreparedStatements(value) {
24556
+ if (value === void 0 || value === false) return false;
24557
+ if (value === true) {
24558
+ return Object.freeze({
24559
+ maxStatements: normalizeMaxPreparedStatements(void 0)
24560
+ });
24561
+ }
24562
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
24563
+ throw new Error(
24564
+ "preparedStatements must be true, false, or a non-null options object."
24565
+ );
24566
+ }
24567
+ return Object.freeze({
24568
+ maxStatements: normalizeMaxPreparedStatements(
24569
+ value.maxStatements
24570
+ )
24571
+ });
24572
+ }
24573
+ function clonePreparedStatements(config) {
24574
+ return config === false ? false : { maxStatements: config.maxStatements };
24575
+ }
24360
24576
  function createPgsqlAdapterFromConstructionOptions(connection, options) {
24361
24577
  return new PgsqlAdapter(
24362
24578
  connection,
@@ -24378,6 +24594,8 @@ var PgsqlAdapter = class {
24378
24594
  naming;
24379
24595
  model;
24380
24596
  logger;
24597
+ preparedStatements;
24598
+ preparedStatementRegistry;
24381
24599
  _capabilities;
24382
24600
  defaultPk;
24383
24601
  deriveFk;
@@ -24424,6 +24642,15 @@ var PgsqlAdapter = class {
24424
24642
  this.naming = getNamingPluginForDbCasing(this._dbCasing);
24425
24643
  this.model = options?.model;
24426
24644
  this.logger = options?.logger;
24645
+ this.preparedStatements = normalizePreparedStatements(
24646
+ options?.preparedStatements
24647
+ );
24648
+ if (this.preparedStatements !== false) {
24649
+ const { maxStatements } = this.preparedStatements;
24650
+ this.preparedStatementRegistry = getPreparedStatementRegistryOption(options) ?? (this.pool !== void 0 ? getOrCreatePreparedStatementRegistry(this.pool, maxStatements) : this.client !== void 0 ? getOrCreatePreparedStatementRegistry(this.client, maxStatements) : void 0);
24651
+ } else {
24652
+ this.preparedStatementRegistry = void 0;
24653
+ }
24427
24654
  this.defaultPk = options?.defaultPkColumnName ?? DEFAULT_PK_COLUMN;
24428
24655
  this.deriveFk = options?.deriveFkColumnName ?? defaultFkDerivation;
24429
24656
  const supportsManagedTransactions = this.pool != null || this.client != null && this.managedTransactions;
@@ -24454,7 +24681,8 @@ var PgsqlAdapter = class {
24454
24681
  const scopeToken = overrides.dbspScopeToken ?? this.scopeToken;
24455
24682
  const scopeState = overrides.dbspScopeState ?? this.scopeState;
24456
24683
  const rollbackOnlyScope = overrides.rollbackOnlyScope ?? this.rollbackOnlyScope ? true : void 0;
24457
- const hasInternalOptions = adapterManagedTransaction === true || adapterManagedPinnedConnection === true || rollbackOnlyScope === true || scopeToken !== void 0 || scopeState !== void 0;
24684
+ const preparedStatementRegistry = this.preparedStatementRegistry;
24685
+ const hasInternalOptions = adapterManagedTransaction === true || adapterManagedPinnedConnection === true || rollbackOnlyScope === true || scopeToken !== void 0 || scopeState !== void 0 || preparedStatementRegistry !== void 0;
24458
24686
  return {
24459
24687
  ...hasInternalOptions && {
24460
24688
  [pgsqlAdapterInternalOptionsKey]: true
@@ -24463,6 +24691,9 @@ var PgsqlAdapter = class {
24463
24691
  ...this._dbCasing !== void 0 && { dbCasing: this._dbCasing },
24464
24692
  ...this.model !== void 0 && { model: this.model },
24465
24693
  ...this.logger !== void 0 && { logger: this.logger },
24694
+ ...this.preparedStatements !== false && {
24695
+ preparedStatements: clonePreparedStatements(this.preparedStatements)
24696
+ },
24466
24697
  defaultPkColumnName: this.defaultPk,
24467
24698
  deriveFkColumnName: this.deriveFk,
24468
24699
  ...this.borrowedClient && { borrowedClient: true },
@@ -24474,6 +24705,9 @@ var PgsqlAdapter = class {
24474
24705
  ...rollbackOnlyScope === true && { rollbackOnlyScope },
24475
24706
  ...scopeToken !== void 0 && { dbspScopeToken: scopeToken },
24476
24707
  ...scopeState !== void 0 && { dbspScopeState: scopeState },
24708
+ ...preparedStatementRegistry !== void 0 && {
24709
+ preparedStatementRegistry
24710
+ },
24477
24711
  ...overrides
24478
24712
  };
24479
24713
  }
@@ -25058,7 +25292,7 @@ var PgsqlAdapter = class {
25058
25292
  async executeWithMeta(query) {
25059
25293
  this.requireConnection("execute");
25060
25294
  const guardedQuery = guardCompiledQuery(query, "execute");
25061
- const result = await this.executeQueryProtectingOpenTransaction(guardedQuery.sql, guardedQuery.parameters);
25295
+ const result = await this.executeQueryProtectingOpenTransaction(guardedQuery.sql, guardedQuery.parameters, { prepareEligible: true });
25062
25296
  const metadata = queryResultMetadata(result);
25063
25297
  const rows = this.transformResultRows(result.rows, guardedQuery);
25064
25298
  return {
@@ -26559,11 +26793,11 @@ var PgsqlAdapter = class {
26559
26793
  }
26560
26794
  }
26561
26795
  releaseClient(client, error) {
26562
- if (error === void 0) {
26796
+ if (error === void 0 && !hasPreparedStatementQuarantine(client)) {
26563
26797
  client.release();
26564
26798
  return;
26565
26799
  }
26566
- client.release(error);
26800
+ client.release(error ?? true);
26567
26801
  }
26568
26802
  async rollbackAndReleaseSavepoint(client, savepointName, allowedScopeToken, scopeState, options) {
26569
26803
  const rolledBack = await this.rollbackSavepoint(
@@ -27260,7 +27494,8 @@ var PgsqlAdapter = class {
27260
27494
  const rawResult = await this.issueConnectionQuery(
27261
27495
  executor,
27262
27496
  sql,
27263
- parameters
27497
+ parameters,
27498
+ options.prepareEligible ?? false
27264
27499
  );
27265
27500
  if (options.inspectTransactionControl !== false) {
27266
27501
  await this.assertNoTransactionControlCommand(
@@ -27401,7 +27636,58 @@ var PgsqlAdapter = class {
27401
27636
  }
27402
27637
  return result;
27403
27638
  }
27404
- async issueConnectionQuery(executor, sql, parameters) {
27639
+ async issueConnectionQuery(executor, sql, parameters, prepareEligible) {
27640
+ if (this.preparedStatementRegistry !== void 0 && prepareEligible && parameters !== void 0 && parameters.length > 0) {
27641
+ if (isPoolClientLike(executor) && isPreparedStatementQuarantined(executor, sql)) {
27642
+ return executor.query(sql, [...parameters]);
27643
+ }
27644
+ const admission = this.preparedStatementRegistry.admit(sql);
27645
+ if (admission === void 0) {
27646
+ return executor.query(sql, [...parameters]);
27647
+ }
27648
+ try {
27649
+ const result = await executor.query({
27650
+ name: admission.name,
27651
+ text: sql,
27652
+ values: [...parameters]
27653
+ });
27654
+ if (admission.reservation !== void 0)
27655
+ this.preparedStatementRegistry.confirm(admission.reservation);
27656
+ return result;
27657
+ } catch (error) {
27658
+ if (admission.reservation !== void 0) {
27659
+ try {
27660
+ if (shouldAbortPreparedStatementReservation(
27661
+ error,
27662
+ executor,
27663
+ admission.name
27664
+ )) {
27665
+ this.preparedStatementRegistry.abort(admission.reservation);
27666
+ } else
27667
+ this.preparedStatementRegistry.confirm(admission.reservation);
27668
+ } catch {
27669
+ try {
27670
+ this.preparedStatementRegistry.abort(admission.reservation);
27671
+ } catch {
27672
+ }
27673
+ }
27674
+ }
27675
+ try {
27676
+ if (isPoolClientLike(executor) && (isVerifiedPreparedStatementInfrastructureError(error) || isDriverLocalPreparedStatementNameCollision(
27677
+ error,
27678
+ admission.name
27679
+ ))) {
27680
+ quarantinePreparedStatement(
27681
+ executor,
27682
+ sql,
27683
+ isVerifiedClientWidePreparedStatementLoss(error)
27684
+ );
27685
+ }
27686
+ } catch {
27687
+ }
27688
+ throw error;
27689
+ }
27690
+ }
27405
27691
  if (parameters === void 0) {
27406
27692
  return executor.query(sql);
27407
27693
  }
@@ -30596,7 +30882,7 @@ function createPgObservationIssuer() {
30596
30882
  }
30597
30883
 
30598
30884
  // src/transition/operations/alter-column-set-not-null.ts
30599
- import { createHash as createHash2 } from "crypto";
30885
+ import { createHash as createHash3 } from "crypto";
30600
30886
  import { createEvidenceView } from "@dbsp/core";
30601
30887
  init_validate();
30602
30888
 
@@ -31869,7 +32155,7 @@ function operationPackSemanticsAssumption(payload, context) {
31869
32155
  };
31870
32156
  }
31871
32157
  function digest(value) {
31872
- return createHash2("sha256").update(stableJson(value)).digest("hex");
32158
+ return createHash3("sha256").update(stableJson(value)).digest("hex");
31873
32159
  }
31874
32160
  function fact(key, value) {
31875
32161
  return {
@@ -32541,7 +32827,7 @@ function createAlterColumnSetNotNullOperationRuntime() {
32541
32827
  }
32542
32828
 
32543
32829
  // src/transition/operations/alter-table-add-check.ts
32544
- import { createHash as createHash3 } from "crypto";
32830
+ import { createHash as createHash4 } from "crypto";
32545
32831
  init_validate();
32546
32832
  var GUARD_STATEMENT_TIMEOUT_MS2 = 5e3;
32547
32833
  var RENDERER_SESSION_REQUIREMENTS = [
@@ -32772,7 +33058,7 @@ function operationPackSemanticsAssumption2(payload, context) {
32772
33058
  };
32773
33059
  }
32774
33060
  function digest2(value) {
32775
- return createHash3("sha256").update(stableJson(value)).digest("hex");
33061
+ return createHash4("sha256").update(stableJson(value)).digest("hex");
32776
33062
  }
32777
33063
  function fact2(key, value) {
32778
33064
  return {
@@ -33246,7 +33532,7 @@ function createAlterTableAddCheckOperationRuntime() {
33246
33532
  }
33247
33533
 
33248
33534
  // src/transition/operations/alter-type-add-value.ts
33249
- import { createHash as createHash4 } from "crypto";
33535
+ import { createHash as createHash5 } from "crypto";
33250
33536
  init_validate();
33251
33537
  var MAX_PG_ENUM_LABEL_BYTES = 63;
33252
33538
  var RENDERER_SESSION_REQUIREMENTS2 = [
@@ -33414,7 +33700,7 @@ function operationPackSemanticsAssumption3(payload, context) {
33414
33700
  };
33415
33701
  }
33416
33702
  function digest3(value) {
33417
- return createHash4("sha256").update(stableJson(value)).digest("hex");
33703
+ return createHash5("sha256").update(stableJson(value)).digest("hex");
33418
33704
  }
33419
33705
  function fact3(key, value) {
33420
33706
  return {
@@ -33814,7 +34100,7 @@ function createAlterTypeAddValueOperationRuntime() {
33814
34100
  }
33815
34101
 
33816
34102
  // src/transition/operations/attach-logical-identity.ts
33817
- import { createHash as createHash5 } from "crypto";
34103
+ import { createHash as createHash6 } from "crypto";
33818
34104
  init_validate();
33819
34105
  function isRecord11(value) {
33820
34106
  return value != null && typeof value === "object" && !Array.isArray(value);
@@ -33957,7 +34243,7 @@ function renderInsertLogicalIdentitySql(_schema) {
33957
34243
  return `INSERT INTO ${qualifiedSideTable()} (logical_id, schema_name, table_name, column_name, carrier_kind) VALUES ($1, $2, $3, $4, $5)`;
33958
34244
  }
33959
34245
  function digest4(value) {
33960
- return createHash5("sha256").update(stableJson(value)).digest("hex");
34246
+ return createHash6("sha256").update(stableJson(value)).digest("hex");
33961
34247
  }
33962
34248
  function fact4(key, value) {
33963
34249
  return {
@@ -34360,7 +34646,7 @@ function createAttachLogicalIdentityOperationRuntime() {
34360
34646
  }
34361
34647
 
34362
34648
  // src/transition/operations/create-unique-index-concurrently.ts
34363
- import { createHash as createHash6 } from "crypto";
34649
+ import { createHash as createHash7 } from "crypto";
34364
34650
  init_validate();
34365
34651
  var DEFAULT_LOCK_TIMEOUT_MS = 5e3;
34366
34652
  function isRecord12(value) {
@@ -34472,7 +34758,7 @@ function operationPackSemanticsAssumption5(payload, context) {
34472
34758
  };
34473
34759
  }
34474
34760
  function digest5(value) {
34475
- return createHash6("sha256").update(stableJson(value)).digest("hex");
34761
+ return createHash7("sha256").update(stableJson(value)).digest("hex");
34476
34762
  }
34477
34763
  function fact5(key, value) {
34478
34764
  return {
@@ -35151,7 +35437,7 @@ function createCreateUniqueIndexConcurrentlyOperationRuntime() {
35151
35437
  }
35152
35438
 
35153
35439
  // src/transition/operations/manual-sql.ts
35154
- import { createHash as createHash7 } from "crypto";
35440
+ import { createHash as createHash8 } from "crypto";
35155
35441
  import { resourceScopeCovers } from "@dbsp/core";
35156
35442
  function isRecord13(value) {
35157
35443
  return value != null && typeof value === "object" && !Array.isArray(value);
@@ -35168,7 +35454,7 @@ function clientQuery6(client) {
35168
35454
  return queryable7(client.opaqueClient);
35169
35455
  }
35170
35456
  function digest6(value) {
35171
- return createHash7("sha256").update(stableJson(value)).digest("hex");
35457
+ return createHash8("sha256").update(stableJson(value)).digest("hex");
35172
35458
  }
35173
35459
  function fact6(key, value) {
35174
35460
  return {