1use std::collections::{BTreeMap, BTreeSet};
11use std::error::Error;
12use std::fmt;
13use std::num::TryFromIntError;
14
15use dec::TryFromDecimalError;
16use itertools::Itertools;
17use mz_catalog::builtin::MZ_CATALOG_SERVER_CLUSTER;
18use mz_compute_client::controller::error as compute_error;
19use mz_compute_client::controller::error::InstanceMissing;
20
21use mz_compute_types::ComputeInstanceId;
22use mz_expr::EvalError;
23use mz_ore::error::ErrorExt;
24use mz_ore::stack::RecursionLimitError;
25use mz_ore::str::StrExt;
26use mz_pgwire_common::{ErrorResponse, Severity};
27use mz_repr::adt::timestamp::TimestampError;
28use mz_repr::explain::ExplainError;
29use mz_repr::{ColumnDiff, ColumnName, KeyDiff, NotNullViolation, RelationDescDiff, Timestamp};
30use mz_sql::plan::PlanError;
31use mz_sql::rbac;
32use mz_sql::session::vars::VarError;
33use mz_storage_types::connections::ConnectionValidationError;
34use mz_storage_types::controller::StorageError;
35use mz_storage_types::errors::CollectionMissing;
36use smallvec::SmallVec;
37use timely::progress::Antichain;
38use tokio::sync::oneshot;
39use tokio_postgres::error::SqlState;
40
41use crate::coord::NetworkPolicyError;
42use crate::optimize::OptimizerError;
43use crate::peek_client::CollectionLookupError;
44
45#[derive(Debug)]
47pub enum AdapterError {
48 AbsurdSubscribeBounds {
50 as_of: mz_repr::Timestamp,
51 up_to: mz_repr::Timestamp,
52 },
53 AmbiguousSystemColumnReference,
57 Catalog(mz_catalog::memory::error::Error),
59 ChangedPlan(String),
64 DuplicateCursor(String),
66 Eval(EvalError),
68 Explain(ExplainError),
70 IdExhaustionError,
72 Internal(String),
74 IntrospectionDisabled {
76 log_names: Vec<String>,
77 },
78 InvalidLogDependency {
81 object_type: String,
82 log_names: Vec<String>,
83 },
84 InvalidClusterReplicaAz {
86 az: String,
87 expected: Vec<String>,
88 },
89 InvalidSetIsolationLevel,
91 InvalidSetCluster,
93 InvalidStorageClusterSize {
95 size: String,
96 expected: Vec<String>,
97 },
98 SourceOrSinkSizeRequired {
100 expected: Vec<String>,
101 },
102 InvalidTableMutationSelection {
104 object_name: String,
106 object_type: String,
108 },
109 ConstraintViolation(NotNullViolation),
111 CopyFormatError(String),
113 ConcurrentClusterDrop,
115 ConcurrentDependencyDrop {
117 dependency_kind: &'static str,
118 dependency_id: String,
119 },
120 CollectionUnreadable {
121 id: String,
122 },
123 NoClusterReplicasAvailable {
125 name: String,
126 is_managed: bool,
127 },
128 OperationProhibitsTransaction(String),
130 OperationRequiresTransaction(String),
132 PlanError(PlanError),
134 PreparedStatementExists(String),
136 ParseError(mz_sql_parser::parser::ParserStatementError),
138 ReadOnlyTransaction,
140 ReadWriteUnavailable,
142 RecursionLimit(RecursionLimitError),
144 RelationOutsideTimeDomain {
147 relations: Vec<String>,
148 names: Vec<String>,
149 },
150 ResourceExhaustion {
152 resource_type: String,
153 limit_name: String,
154 desired: String,
155 limit: String,
156 current: String,
157 },
158 ResultSize(String),
160 SafeModeViolation(String),
162 WrongSetOfLocks,
164 StatementTimeout,
168 Canceled,
170 IdleInTransactionSessionTimeout,
172 SubscribeOnlyTransaction,
174 Optimizer(OptimizerError),
176 UnallowedOnCluster {
178 depends_on: SmallVec<[String; 2]>,
179 cluster: String,
180 },
181 Unauthorized(rbac::UnauthorizedError),
183 UnknownCursor(String),
185 UnknownLoginRole(String),
187 UnknownPreparedStatement(String),
188 UnknownClusterReplica {
190 cluster_name: String,
191 replica_name: String,
192 },
193 UnrecognizedConfigurationParam(String),
195 Unstructured(anyhow::Error),
199 Unsupported(&'static str),
201 UnavailableFeature {
205 feature: String,
206 docs: Option<String>,
207 },
208 UntargetedLogRead {
210 log_names: Vec<String>,
211 },
212 WriteOnlyTransaction,
214 SingleStatementTransaction,
216 DDLOnlyTransaction,
218 DDLTransactionRace,
220 Storage(mz_storage_types::controller::StorageError),
222 Compute(anyhow::Error),
224 Orchestrator(anyhow::Error),
226 DependentObject(BTreeMap<String, Vec<String>>),
230 InvalidAlter(&'static str, PlanError),
233 ConnectionValidation(ConnectionValidationError),
235 MaterializedViewWouldNeverRefresh(Timestamp, Timestamp),
239 InputNotReadableAtRefreshAtTime(Timestamp, Antichain<Timestamp>),
242 RtrTimeout(String),
244 RtrDropFailure(String),
246 UnreadableSinkCollection,
248 UserSessionsDisallowed,
250 NetworkPolicyDenied(NetworkPolicyError),
252 ReadOnly,
255 AlterClusterTimeout,
256 AlterClusterWhilePendingReplicas,
257 AuthenticationError(AuthenticationError),
258 ReplacementSchemaMismatch(RelationDescDiff),
260 ReplaceMaterializedViewSealed {
262 name: String,
263 },
264 ImpossibleTimestampConstraints {
266 constraints: String,
267 },
268 OidcGroupSyncFailed(String),
270}
271
272#[derive(Debug, thiserror::Error)]
273pub enum AuthenticationError {
274 #[error("invalid credentials")]
275 InvalidCredentials,
276 #[error("role is not allowed to login")]
277 NonLogin,
278 #[error("role does not exist")]
279 RoleNotFound,
280 #[error("password is required")]
281 PasswordRequired,
282}
283
284impl AdapterError {
285 pub fn into_response(self, severity: Severity) -> ErrorResponse {
286 ErrorResponse {
287 severity,
288 code: self.code(),
289 message: self.to_string(),
290 detail: self.detail(),
291 hint: self.hint(),
292 position: self.position(),
293 }
294 }
295
296 pub fn position(&self) -> Option<usize> {
297 match self {
298 AdapterError::ParseError(err) => Some(err.error.pos),
299 _ => None,
300 }
301 }
302
303 pub fn detail(&self) -> Option<String> {
305 match self {
306 AdapterError::AmbiguousSystemColumnReference => {
307 Some("This is a current limitation in Materialize".into())
308 }
309 AdapterError::Catalog(c) => c.detail(),
310 AdapterError::Eval(e) => e.detail(),
311 AdapterError::RelationOutsideTimeDomain { relations, names } => Some(format!(
312 "The following relations in the query are outside the transaction's time domain:\n{}\n{}",
313 relations
314 .iter()
315 .map(|r| r.quoted().to_string())
316 .collect::<Vec<_>>()
317 .join("\n"),
318 match names.is_empty() {
319 true => "No relations are available.".to_string(),
320 false => format!(
321 "Only the following relations are available:\n{}",
322 names
323 .iter()
324 .map(|name| name.quoted().to_string())
325 .collect::<Vec<_>>()
326 .join("\n")
327 ),
328 }
329 )),
330 AdapterError::SourceOrSinkSizeRequired { .. } => Some(
331 "Either specify the cluster that will maintain this object via IN CLUSTER or \
332 specify size via SIZE option."
333 .into(),
334 ),
335 AdapterError::InvalidTableMutationSelection {
336 object_name,
337 object_type,
338 } => Some(format!(
339 "{object_type} '{}' may not be used in this operation; \
340 the selection may refer to views and materialized views, but transitive \
341 dependencies must not include sources or source-export tables",
342 object_name.quoted()
343 )),
344 AdapterError::SafeModeViolation(_) => Some(
345 "The Materialize server you are connected to is running in \
346 safe mode, which limits the features that are available."
347 .into(),
348 ),
349 AdapterError::IntrospectionDisabled { log_names }
350 | AdapterError::UntargetedLogRead { log_names } => Some(format!(
351 "The query references the following log sources:\n {}",
352 log_names.join("\n "),
353 )),
354 AdapterError::InvalidLogDependency { log_names, .. } => Some(format!(
355 "The object depends on the following log sources:\n {}",
356 log_names.join("\n "),
357 )),
358 AdapterError::PlanError(e) => e.detail(),
359 AdapterError::Unauthorized(unauthorized) => unauthorized.detail(),
360 AdapterError::DependentObject(dependent_objects) => Some(
361 dependent_objects
362 .iter()
363 .map(|(role_name, err_msgs)| {
364 err_msgs
365 .iter()
366 .map(|err_msg| format!("{role_name}: {err_msg}"))
367 .join("\n")
368 })
369 .join("\n"),
370 ),
371 AdapterError::Storage(storage_error) => storage_error
372 .source()
373 .map(|source_error| source_error.to_string_with_causes()),
374 AdapterError::ReadOnlyTransaction => Some(
375 "SELECT queries cannot be combined with other query types, including SUBSCRIBE."
376 .into(),
377 ),
378 AdapterError::InvalidAlter(_, e) => e.detail(),
379 AdapterError::Optimizer(e) => e.detail(),
380 AdapterError::ConnectionValidation(e) => e.detail(),
381 AdapterError::MaterializedViewWouldNeverRefresh(last_refresh, earliest_possible) => {
382 Some(format!(
383 "The specified last refresh is at {}, while the earliest possible time to compute the materialized \
384 view is {}.",
385 last_refresh, earliest_possible,
386 ))
387 }
388 AdapterError::UnallowedOnCluster { cluster, .. } => {
389 (cluster == MZ_CATALOG_SERVER_CLUSTER.name).then(|| {
390 format!(
391 "The transaction is executing on the \
392 {cluster} cluster, maybe having been routed \
393 there by the first statement in the transaction."
394 )
395 })
396 }
397 AdapterError::InputNotReadableAtRefreshAtTime(oracle_read_ts, least_valid_read) => {
398 Some(format!(
399 "The requested REFRESH AT time is {}, \
400 but not all input collections are readable earlier than [{}].",
401 oracle_read_ts,
402 if least_valid_read.len() == 1 {
403 format!(
404 "{}",
405 least_valid_read
406 .as_option()
407 .expect("antichain contains exactly 1 timestamp")
408 )
409 } else {
410 format!("{:?}", least_valid_read)
412 }
413 ))
414 }
415 AdapterError::RtrTimeout(name) => Some(format!(
416 "{name} failed to ingest data up to the real-time recency point"
417 )),
418 AdapterError::RtrDropFailure(name) => Some(format!(
419 "{name} dropped before ingesting data to the real-time recency point"
420 )),
421 AdapterError::UserSessionsDisallowed => {
422 Some("Your organization has been blocked. Please contact support.".to_string())
423 }
424 AdapterError::NetworkPolicyDenied(reason) => Some(format!("{reason}.")),
425 AdapterError::ReplacementSchemaMismatch(diff) => {
426 let mut lines: Vec<_> = diff.column_diffs.iter().map(|(idx, diff)| {
427 let pos = idx + 1;
428 match diff {
429 ColumnDiff::Missing { name } => {
430 let name = name.as_str().quoted();
431 format!("missing column {name} at position {pos}")
432 }
433 ColumnDiff::Extra { name } => {
434 let name = name.as_str().quoted();
435 format!("extra column {name} at position {pos}")
436 }
437 ColumnDiff::TypeMismatch { name, left, right } => {
438 let name = name.as_str().quoted();
439 format!("column {name} at position {pos}: type mismatch (target: {left:?}, replacement: {right:?})")
440 }
441 ColumnDiff::NullabilityMismatch { name, left, right } => {
442 let name = name.as_str().quoted();
443 let left = if *left { "NULL" } else { "NOT NULL" };
444 let right = if *right { "NULL" } else { "NOT NULL" };
445 format!("column {name} at position {pos}: nullability mismatch (target: {left}, replacement: {right})")
446 }
447 ColumnDiff::NameMismatch { left, right } => {
448 let left = left.as_str().quoted();
449 let right = right.as_str().quoted();
450 format!("column at position {pos}: name mismatch (target: {left}, replacement: {right})")
451 }
452 }
453 }).collect();
454
455 if let Some(KeyDiff { left, right }) = &diff.key_diff {
456 let format_keys = |keys: &BTreeSet<Vec<ColumnName>>| {
457 if keys.is_empty() {
458 "(none)".to_string()
459 } else {
460 keys.iter()
461 .map(|key| {
462 let cols = key.iter().map(|c| c.as_str()).join(", ");
463 format!("{{{cols}}}")
464 })
465 .join(", ")
466 }
467 };
468 lines.push(format!(
469 "keys differ (target: {}, replacement: {})",
470 format_keys(left),
471 format_keys(right)
472 ));
473 }
474 Some(lines.join("\n"))
475 }
476 AdapterError::ReplaceMaterializedViewSealed { .. } => Some(
477 "The materialized view has already computed its output until the end of time, \
478 so replacing its definition would have no effect."
479 .into(),
480 ),
481 AdapterError::ImpossibleTimestampConstraints { constraints } => {
482 Some(format!("Constraints:\n{}", constraints))
483 }
484 _ => None,
485 }
486 }
487
488 pub fn hint(&self) -> Option<String> {
490 match self {
491 AdapterError::AmbiguousSystemColumnReference => Some(
492 "Rewrite the view to refer to all columns by name. Expand all wildcards and \
493 convert all NATURAL JOINs to USING joins."
494 .to_string(),
495 ),
496 AdapterError::Catalog(c) => c.hint(),
497 AdapterError::Eval(e) => e.hint(),
498 AdapterError::InvalidClusterReplicaAz { expected, az: _ } => {
499 Some(if expected.is_empty() {
500 "No availability zones configured; do not specify AVAILABILITY ZONE".into()
501 } else {
502 format!("Valid availability zones are: {}", expected.join(", "))
503 })
504 }
505 AdapterError::InvalidStorageClusterSize { expected, .. } => {
506 Some(format!("Valid sizes are: {}", expected.join(", ")))
507 }
508 AdapterError::SourceOrSinkSizeRequired { expected } => Some(format!(
509 "Try choosing one of the smaller sizes to start. Available sizes: {}",
510 expected.join(", ")
511 )),
512 AdapterError::NoClusterReplicasAvailable { is_managed, .. } => {
513 Some(if *is_managed {
514 "Use ALTER CLUSTER to adjust the replication factor of the cluster. \
515 Example:`ALTER CLUSTER <cluster-name> SET (REPLICATION FACTOR 1)`".into()
516 } else {
517 "Use CREATE CLUSTER REPLICA to attach cluster replicas to the cluster".into()
518 })
519 }
520 AdapterError::UntargetedLogRead { .. } => Some(
521 "Use `SET cluster_replica = <replica-name>` to target a specific replica in the \
522 active cluster. Note that subsequent queries will only be answered by \
523 the selected replica, which might reduce availability. To undo the replica \
524 selection, use `RESET cluster_replica`."
525 .into(),
526 ),
527 AdapterError::ResourceExhaustion { resource_type, .. } => Some(format!(
528 "Drop an existing {resource_type} or contact support to request a limit increase."
529 )),
530 AdapterError::StatementTimeout => Some(
531 "Consider increasing the maximum allowed statement duration for this session by \
532 setting the statement_timeout session variable. For example, `SET \
533 statement_timeout = '120s'`."
534 .into(),
535 ),
536 AdapterError::PlanError(e) => e.hint(),
537 AdapterError::UnallowedOnCluster { cluster, .. } => {
538 (cluster != MZ_CATALOG_SERVER_CLUSTER.name).then(||
539 "Use `SET CLUSTER = <cluster-name>` to change your cluster and re-run the query."
540 .to_string()
541 )
542 }
543 AdapterError::InvalidAlter(_, e) => e.hint(),
544 AdapterError::Optimizer(e) => e.hint(),
545 AdapterError::ConnectionValidation(e) => e.hint(),
546 AdapterError::InputNotReadableAtRefreshAtTime(_, _) => Some(
547 "You can use `REFRESH AT greatest(mz_now(), <explicit timestamp>)` to refresh \
548 either at the explicitly specified timestamp, or now if the given timestamp would \
549 be in the past.".to_string()
550 ),
551 AdapterError::AlterClusterTimeout => Some(
552 "Consider increasing the timeout duration in the alter cluster statement.".into(),
553 ),
554 AdapterError::DDLTransactionRace => Some(
555 "Currently, DDL transactions fail when any other DDL happens concurrently, \
556 even on unrelated schemas/clusters.".into()
557 ),
558 AdapterError::CollectionUnreadable { .. } => Some(
559 "This could be because the collection has recently been dropped.".into()
560 ),
561 _ => None,
562 }
563 }
564
565 pub fn code(&self) -> SqlState {
566 const RECURSION_LIMIT_ERROR_CODE: SqlState = SqlState::INTERNAL_ERROR;
568
569 match self {
574 AdapterError::AbsurdSubscribeBounds { .. } => SqlState::DATA_EXCEPTION,
577 AdapterError::AmbiguousSystemColumnReference => SqlState::FEATURE_NOT_SUPPORTED,
578 AdapterError::Catalog(e) => match &e.kind {
579 mz_catalog::memory::error::ErrorKind::VarError(e) => match e {
580 VarError::ConstrainedParameter { .. } => SqlState::INVALID_PARAMETER_VALUE,
581 VarError::FixedValueParameter { .. } => SqlState::INVALID_PARAMETER_VALUE,
582 VarError::InvalidParameterType { .. } => SqlState::INVALID_PARAMETER_VALUE,
583 VarError::InvalidParameterValue { .. } => SqlState::INVALID_PARAMETER_VALUE,
584 VarError::ReadOnlyParameter(_) => SqlState::CANT_CHANGE_RUNTIME_PARAM,
585 VarError::UnknownParameter(_) => SqlState::UNDEFINED_OBJECT,
586 VarError::RequiresUnsafeMode { .. } => SqlState::CANT_CHANGE_RUNTIME_PARAM,
587 VarError::RequiresFeatureFlag { .. } => SqlState::CANT_CHANGE_RUNTIME_PARAM,
588 },
589 _ => SqlState::INTERNAL_ERROR,
590 },
591 AdapterError::ChangedPlan(_) => SqlState::FEATURE_NOT_SUPPORTED,
592 AdapterError::DuplicateCursor(_) => SqlState::DUPLICATE_CURSOR,
593 AdapterError::Eval(EvalError::CharacterNotValidForEncoding(_)) => {
594 SqlState::PROGRAM_LIMIT_EXCEEDED
595 }
596 AdapterError::Eval(EvalError::CharacterTooLargeForEncoding(_)) => {
597 SqlState::PROGRAM_LIMIT_EXCEEDED
598 }
599 AdapterError::Eval(EvalError::LengthTooLarge) => SqlState::PROGRAM_LIMIT_EXCEEDED,
600 AdapterError::Eval(EvalError::NullCharacterNotPermitted) => {
601 SqlState::PROGRAM_LIMIT_EXCEEDED
602 }
603 AdapterError::Eval(_) => SqlState::INTERNAL_ERROR,
604 AdapterError::Explain(_) => SqlState::INTERNAL_ERROR,
605 AdapterError::IdExhaustionError => SqlState::INTERNAL_ERROR,
606 AdapterError::Internal(_) => SqlState::INTERNAL_ERROR,
607 AdapterError::IntrospectionDisabled { .. } => SqlState::FEATURE_NOT_SUPPORTED,
608 AdapterError::InvalidLogDependency { .. } => SqlState::FEATURE_NOT_SUPPORTED,
609 AdapterError::InvalidClusterReplicaAz { .. } => SqlState::FEATURE_NOT_SUPPORTED,
610 AdapterError::InvalidSetIsolationLevel => SqlState::ACTIVE_SQL_TRANSACTION,
611 AdapterError::InvalidSetCluster => SqlState::ACTIVE_SQL_TRANSACTION,
612 AdapterError::InvalidStorageClusterSize { .. } => SqlState::FEATURE_NOT_SUPPORTED,
613 AdapterError::SourceOrSinkSizeRequired { .. } => SqlState::FEATURE_NOT_SUPPORTED,
614 AdapterError::InvalidTableMutationSelection { .. } => {
615 SqlState::INVALID_TRANSACTION_STATE
616 }
617 AdapterError::ConstraintViolation(NotNullViolation(_)) => SqlState::NOT_NULL_VIOLATION,
618 AdapterError::CopyFormatError(_) => SqlState::BAD_COPY_FILE_FORMAT,
619 AdapterError::ConcurrentClusterDrop => SqlState::INVALID_TRANSACTION_STATE,
620 AdapterError::ConcurrentDependencyDrop { .. } => SqlState::UNDEFINED_OBJECT,
621 AdapterError::CollectionUnreadable { .. } => SqlState::NO_DATA_FOUND,
622 AdapterError::NoClusterReplicasAvailable { .. } => SqlState::FEATURE_NOT_SUPPORTED,
623 AdapterError::OperationProhibitsTransaction(_) => SqlState::ACTIVE_SQL_TRANSACTION,
624 AdapterError::OperationRequiresTransaction(_) => SqlState::NO_ACTIVE_SQL_TRANSACTION,
625 AdapterError::ParseError(_) => SqlState::SYNTAX_ERROR,
626 AdapterError::PlanError(PlanError::InvalidSchemaName) => SqlState::INVALID_SCHEMA_NAME,
627 AdapterError::PlanError(PlanError::ColumnAlreadyExists { .. }) => {
628 SqlState::DUPLICATE_COLUMN
629 }
630 AdapterError::PlanError(PlanError::UnknownParameter(_)) => {
631 SqlState::UNDEFINED_PARAMETER
632 }
633 AdapterError::PlanError(PlanError::ParameterNotAllowed(_)) => {
634 SqlState::UNDEFINED_PARAMETER
635 }
636 AdapterError::PlanError(_) => SqlState::INTERNAL_ERROR,
637 AdapterError::PreparedStatementExists(_) => SqlState::DUPLICATE_PSTATEMENT,
638 AdapterError::ReadOnlyTransaction => SqlState::READ_ONLY_SQL_TRANSACTION,
639 AdapterError::ReadWriteUnavailable => SqlState::INVALID_TRANSACTION_STATE,
640 AdapterError::SingleStatementTransaction => SqlState::INVALID_TRANSACTION_STATE,
641 AdapterError::WrongSetOfLocks => SqlState::LOCK_NOT_AVAILABLE,
642 AdapterError::StatementTimeout => SqlState::QUERY_CANCELED,
643 AdapterError::Canceled => SqlState::QUERY_CANCELED,
644 AdapterError::IdleInTransactionSessionTimeout => {
645 SqlState::IDLE_IN_TRANSACTION_SESSION_TIMEOUT
646 }
647 AdapterError::RecursionLimit(_) => RECURSION_LIMIT_ERROR_CODE,
648 AdapterError::RelationOutsideTimeDomain { .. } => SqlState::INVALID_TRANSACTION_STATE,
649 AdapterError::ResourceExhaustion { .. } => SqlState::INSUFFICIENT_RESOURCES,
650 AdapterError::ResultSize(_) => SqlState::OUT_OF_MEMORY,
651 AdapterError::SafeModeViolation(_) => SqlState::INTERNAL_ERROR,
652 AdapterError::SubscribeOnlyTransaction => SqlState::INVALID_TRANSACTION_STATE,
653 AdapterError::Optimizer(e) => match e {
654 OptimizerError::PlanError(PlanError::InvalidSchemaName) => {
655 SqlState::INVALID_SCHEMA_NAME
656 }
657 OptimizerError::PlanError(PlanError::ColumnAlreadyExists { .. }) => {
658 SqlState::DUPLICATE_COLUMN
659 }
660 OptimizerError::PlanError(PlanError::UnknownParameter(_)) => {
661 SqlState::UNDEFINED_PARAMETER
662 }
663 OptimizerError::PlanError(PlanError::ParameterNotAllowed(_)) => {
664 SqlState::UNDEFINED_PARAMETER
665 }
666 OptimizerError::PlanError(_) => SqlState::INTERNAL_ERROR,
667 OptimizerError::RecursionLimitError(_) => RECURSION_LIMIT_ERROR_CODE,
668 OptimizerError::Internal(s) => {
669 AdapterError::Internal(s.clone()).code() }
671 OptimizerError::EvalError(e) => {
672 AdapterError::Eval(e.clone()).code() }
674 OptimizerError::TransformError(_) => SqlState::INTERNAL_ERROR,
675 OptimizerError::UnmaterializableFunction(_) => SqlState::FEATURE_NOT_SUPPORTED,
676 OptimizerError::UncallableFunction { .. } => SqlState::FEATURE_NOT_SUPPORTED,
677 OptimizerError::UnsupportedTemporalExpression(_) => SqlState::FEATURE_NOT_SUPPORTED,
678 OptimizerError::RestrictedFunction(_) => SqlState::INSUFFICIENT_PRIVILEGE,
679 OptimizerError::InternalUnsafeMfpPlan(_) => SqlState::INTERNAL_ERROR,
682 },
683 AdapterError::UnallowedOnCluster { .. } => {
684 SqlState::S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED
685 }
686 AdapterError::Unauthorized(_) => SqlState::INSUFFICIENT_PRIVILEGE,
687 AdapterError::UnknownCursor(_) => SqlState::INVALID_CURSOR_NAME,
688 AdapterError::UnknownPreparedStatement(_) => SqlState::UNDEFINED_PSTATEMENT,
689 AdapterError::UnknownLoginRole(_) => SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
690 AdapterError::UnknownClusterReplica { .. } => SqlState::UNDEFINED_OBJECT,
691 AdapterError::UnrecognizedConfigurationParam(_) => SqlState::UNDEFINED_OBJECT,
692 AdapterError::Unsupported(..) => SqlState::FEATURE_NOT_SUPPORTED,
693 AdapterError::UnavailableFeature { .. } => SqlState::FEATURE_NOT_SUPPORTED,
694 AdapterError::Unstructured(_) => SqlState::INTERNAL_ERROR,
695 AdapterError::UntargetedLogRead { .. } => SqlState::FEATURE_NOT_SUPPORTED,
696 AdapterError::DDLTransactionRace => SqlState::T_R_SERIALIZATION_FAILURE,
697 AdapterError::WriteOnlyTransaction => SqlState::INVALID_TRANSACTION_STATE,
702 AdapterError::DDLOnlyTransaction => SqlState::INVALID_TRANSACTION_STATE,
703 AdapterError::Storage(_) | AdapterError::Compute(_) | AdapterError::Orchestrator(_) => {
704 SqlState::INTERNAL_ERROR
705 }
706 AdapterError::DependentObject(_) => SqlState::DEPENDENT_OBJECTS_STILL_EXIST,
707 AdapterError::InvalidAlter(_, _) => SqlState::FEATURE_NOT_SUPPORTED,
708 AdapterError::ConnectionValidation(_) => SqlState::SYSTEM_ERROR,
709 AdapterError::MaterializedViewWouldNeverRefresh(_, _) => SqlState::DATA_EXCEPTION,
711 AdapterError::InputNotReadableAtRefreshAtTime(_, _) => SqlState::DATA_EXCEPTION,
712 AdapterError::RtrTimeout(_) => SqlState::QUERY_CANCELED,
713 AdapterError::RtrDropFailure(_) => SqlState::UNDEFINED_OBJECT,
714 AdapterError::UnreadableSinkCollection => SqlState::from_code("MZ009"),
715 AdapterError::UserSessionsDisallowed => SqlState::from_code("MZ010"),
716 AdapterError::NetworkPolicyDenied(_) => SqlState::from_code("MZ011"),
717 AdapterError::ReadOnly => SqlState::READ_ONLY_SQL_TRANSACTION,
720 AdapterError::AlterClusterTimeout => SqlState::QUERY_CANCELED,
721 AdapterError::AlterClusterWhilePendingReplicas => SqlState::OBJECT_IN_USE,
722 AdapterError::ReplacementSchemaMismatch(_) => SqlState::FEATURE_NOT_SUPPORTED,
723 AdapterError::AuthenticationError(AuthenticationError::InvalidCredentials) => {
724 SqlState::INVALID_PASSWORD
725 }
726 AdapterError::AuthenticationError(_) => SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
727 AdapterError::ReplaceMaterializedViewSealed { .. } => {
728 SqlState::OBJECT_NOT_IN_PREREQUISITE_STATE
729 }
730 AdapterError::ImpossibleTimestampConstraints { .. } => SqlState::DATA_EXCEPTION,
732 AdapterError::OidcGroupSyncFailed(_) => SqlState::INTERNAL_ERROR,
733 }
734 }
735
736 pub fn internal<E: std::fmt::Display>(context: &str, e: E) -> AdapterError {
737 AdapterError::Internal(format!("{context}: {e}"))
738 }
739
740 pub fn concurrent_dependency_drop_from_instance_missing(e: InstanceMissing) -> Self {
747 AdapterError::ConcurrentDependencyDrop {
748 dependency_kind: "cluster",
749 dependency_id: e.0.to_string(),
750 }
751 }
752
753 pub fn concurrent_dependency_drop_from_collection_missing(e: CollectionMissing) -> Self {
754 AdapterError::ConcurrentDependencyDrop {
755 dependency_kind: "collection",
756 dependency_id: e.0.to_string(),
757 }
758 }
759
760 pub fn concurrent_dependency_drop_from_collection_lookup_error(
761 e: CollectionLookupError,
762 compute_instance: ComputeInstanceId,
763 ) -> Self {
764 match e {
765 CollectionLookupError::InstanceMissing(id) => AdapterError::ConcurrentDependencyDrop {
766 dependency_kind: "cluster",
767 dependency_id: id.to_string(),
768 },
769 CollectionLookupError::CollectionMissing(id) => {
770 AdapterError::ConcurrentDependencyDrop {
771 dependency_kind: "collection",
772 dependency_id: id.to_string(),
773 }
774 }
775 CollectionLookupError::InstanceShutDown => AdapterError::ConcurrentDependencyDrop {
776 dependency_kind: "cluster",
777 dependency_id: compute_instance.to_string(),
778 },
779 }
780 }
781
782 pub fn concurrent_dependency_drop_from_watch_set_install_error(
783 e: compute_error::CollectionLookupError,
784 ) -> Self {
785 match e {
786 compute_error::CollectionLookupError::InstanceMissing(id) => {
787 AdapterError::ConcurrentDependencyDrop {
788 dependency_kind: "cluster",
789 dependency_id: id.to_string(),
790 }
791 }
792 compute_error::CollectionLookupError::CollectionMissing(id) => {
793 AdapterError::ConcurrentDependencyDrop {
794 dependency_kind: "collection",
795 dependency_id: id.to_string(),
796 }
797 }
798 }
799 }
800
801 pub fn concurrent_dependency_drop_from_instance_peek_error(
802 e: mz_compute_client::controller::instance_client::PeekError,
803 compute_instance: ComputeInstanceId,
804 ) -> AdapterError {
805 use mz_compute_client::controller::instance_client::PeekError::*;
806 match e {
807 ReplicaMissing(id) => AdapterError::ConcurrentDependencyDrop {
808 dependency_kind: "replica",
809 dependency_id: id.to_string(),
810 },
811 InstanceShutDown => AdapterError::ConcurrentDependencyDrop {
812 dependency_kind: "cluster",
813 dependency_id: compute_instance.to_string(),
814 },
815 e @ ReadHoldIdMismatch(_) => AdapterError::internal("instance peek error", e),
816 e @ ReadHoldInsufficient(_) => AdapterError::internal("instance peek error", e),
817 }
818 }
819
820 pub fn concurrent_dependency_drop_from_collection_update_error(
821 e: compute_error::CollectionUpdateError,
822 ) -> Self {
823 use compute_error::CollectionUpdateError::*;
824 match e {
825 InstanceMissing(id) => AdapterError::ConcurrentDependencyDrop {
826 dependency_kind: "cluster",
827 dependency_id: id.to_string(),
828 },
829 CollectionMissing(id) => AdapterError::ConcurrentDependencyDrop {
830 dependency_kind: "collection",
831 dependency_id: id.to_string(),
832 },
833 }
834 }
835
836 pub fn concurrent_dependency_drop_from_peek_error(
837 e: mz_compute_client::controller::error::PeekError,
838 ) -> AdapterError {
839 use mz_compute_client::controller::error::PeekError::*;
840 match e {
841 InstanceMissing(id) => AdapterError::ConcurrentDependencyDrop {
842 dependency_kind: "cluster",
843 dependency_id: id.to_string(),
844 },
845 CollectionMissing(id) => AdapterError::ConcurrentDependencyDrop {
846 dependency_kind: "collection",
847 dependency_id: id.to_string(),
848 },
849 ReplicaMissing(id) => AdapterError::ConcurrentDependencyDrop {
850 dependency_kind: "replica",
851 dependency_id: id.to_string(),
852 },
853 e @ (ReadHoldIdMismatch(_) | SinceViolation(_)) => {
854 AdapterError::internal("peek error", e)
855 }
856 }
857 }
858
859 pub fn concurrent_dependency_drop_from_dataflow_creation_error(
860 e: compute_error::DataflowCreationError,
861 ) -> Self {
862 use compute_error::DataflowCreationError::*;
863 match e {
864 InstanceMissing(id) => AdapterError::ConcurrentDependencyDrop {
865 dependency_kind: "cluster",
866 dependency_id: id.to_string(),
867 },
868 CollectionMissing(id) => AdapterError::ConcurrentDependencyDrop {
869 dependency_kind: "collection",
870 dependency_id: id.to_string(),
871 },
872 ReplicaMissing(id) => AdapterError::ConcurrentDependencyDrop {
873 dependency_kind: "replica",
874 dependency_id: id.to_string(),
875 },
876 MissingAsOf | SinceViolation(..) | EmptyAsOfForSubscribe | EmptyAsOfForCopyTo => {
877 AdapterError::internal("dataflow creation error", e)
878 }
879 }
880 }
881}
882
883impl fmt::Display for AdapterError {
884 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
885 match self {
886 AdapterError::AbsurdSubscribeBounds { as_of, up_to } => {
887 write!(
888 f,
889 "subscription lower bound (`AS OF`) is greater than its upper bound (`UP TO`): \
890 {as_of} > {up_to}",
891 )
892 }
893 AdapterError::AmbiguousSystemColumnReference => {
894 write!(
895 f,
896 "cannot use wildcard expansions or NATURAL JOINs in a view that depends on \
897 system objects"
898 )
899 }
900 AdapterError::ChangedPlan(e) => write!(f, "{}", e),
901 AdapterError::Catalog(e) => e.fmt(f),
902 AdapterError::DuplicateCursor(name) => {
903 write!(f, "cursor {} already exists", name.quoted())
904 }
905 AdapterError::Eval(e) => e.fmt(f),
906 AdapterError::Explain(e) => e.fmt(f),
907 AdapterError::IdExhaustionError => f.write_str("ID allocator exhausted all valid IDs"),
908 AdapterError::Internal(e) => write!(f, "internal error: {}", e),
909 AdapterError::IntrospectionDisabled { .. } => write!(
910 f,
911 "cannot read log sources of replica with disabled introspection"
912 ),
913 AdapterError::InvalidLogDependency { object_type, .. } => {
914 write!(f, "{object_type} objects cannot depend on log sources")
915 }
916 AdapterError::InvalidClusterReplicaAz { az, expected: _ } => {
917 write!(f, "unknown cluster replica availability zone {az}",)
918 }
919 AdapterError::InvalidSetIsolationLevel => write!(
920 f,
921 "SET TRANSACTION ISOLATION LEVEL must be called before any query"
922 ),
923 AdapterError::InvalidSetCluster => {
924 write!(f, "SET cluster cannot be called in an active transaction")
925 }
926 AdapterError::InvalidStorageClusterSize { size, .. } => {
927 write!(f, "unknown source size {size}")
928 }
929 AdapterError::SourceOrSinkSizeRequired { .. } => {
930 write!(f, "must specify either cluster or size option")
931 }
932 AdapterError::InvalidTableMutationSelection { .. } => {
933 write!(
934 f,
935 "invalid selection: operation may only (transitively) refer to non-source, non-system tables"
936 )
937 }
938 AdapterError::ReplaceMaterializedViewSealed { name } => {
939 write!(
940 f,
941 "materialized view {name} is sealed and thus cannot be replaced"
942 )
943 }
944 AdapterError::ConstraintViolation(not_null_violation) => {
945 write!(f, "{}", not_null_violation)
946 }
947 AdapterError::CopyFormatError(e) => write!(f, "{e}"),
948 AdapterError::ConcurrentClusterDrop => {
949 write!(f, "the transaction's active cluster has been dropped")
950 }
951 AdapterError::ConcurrentDependencyDrop {
952 dependency_kind,
953 dependency_id,
954 } => {
955 write!(f, "{dependency_kind} '{dependency_id}' was dropped")
956 }
957 AdapterError::CollectionUnreadable { id } => {
958 write!(f, "collection '{id}' is not readable at any timestamp")
959 }
960 AdapterError::NoClusterReplicasAvailable { name, .. } => {
961 write!(
962 f,
963 "CLUSTER {} has no replicas available to service request",
964 name.quoted()
965 )
966 }
967 AdapterError::OperationProhibitsTransaction(op) => {
968 write!(f, "{} cannot be run inside a transaction block", op)
969 }
970 AdapterError::OperationRequiresTransaction(op) => {
971 write!(f, "{} can only be used in transaction blocks", op)
972 }
973 AdapterError::ParseError(e) => e.fmt(f),
974 AdapterError::PlanError(e) => e.fmt(f),
975 AdapterError::PreparedStatementExists(name) => {
976 write!(f, "prepared statement {} already exists", name.quoted())
977 }
978 AdapterError::ReadOnlyTransaction => f.write_str("transaction in read-only mode"),
979 AdapterError::SingleStatementTransaction => {
980 f.write_str("this transaction can only execute a single statement")
981 }
982 AdapterError::ReadWriteUnavailable => {
983 f.write_str("transaction read-write mode must be set before any query")
984 }
985 AdapterError::WrongSetOfLocks => {
986 write!(f, "internal error, wrong set of locks acquired")
987 }
988 AdapterError::StatementTimeout => {
989 write!(f, "canceling statement due to statement timeout")
990 }
991 AdapterError::Canceled => {
992 write!(f, "canceling statement due to user request")
993 }
994 AdapterError::IdleInTransactionSessionTimeout => {
995 write!(
996 f,
997 "terminating connection due to idle-in-transaction timeout"
998 )
999 }
1000 AdapterError::RecursionLimit(e) => e.fmt(f),
1001 AdapterError::RelationOutsideTimeDomain { .. } => {
1002 write!(
1003 f,
1004 "Transactions can only reference objects in the same timedomain. \
1005 See https://materialize.com/docs/sql/begin/#same-timedomain-error",
1006 )
1007 }
1008 AdapterError::ResourceExhaustion {
1009 resource_type,
1010 limit_name,
1011 desired,
1012 limit,
1013 current,
1014 } => {
1015 write!(
1016 f,
1017 "creating {resource_type} would violate {limit_name} limit (desired: {desired}, limit: {limit}, current: {current})"
1018 )
1019 }
1020 AdapterError::ResultSize(e) => write!(f, "{e}"),
1021 AdapterError::SafeModeViolation(feature) => {
1022 write!(f, "cannot create {} in safe mode", feature)
1023 }
1024 AdapterError::SubscribeOnlyTransaction => {
1025 f.write_str("SUBSCRIBE in transactions must be the only read statement")
1026 }
1027 AdapterError::Optimizer(e) => e.fmt(f),
1028 AdapterError::UnallowedOnCluster {
1029 depends_on,
1030 cluster,
1031 } => {
1032 let items = depends_on.into_iter().map(|item| item.quoted()).join(", ");
1033 write!(
1034 f,
1035 "querying the following items {items} is not allowed from the {} cluster",
1036 cluster.quoted()
1037 )
1038 }
1039 AdapterError::Unauthorized(unauthorized) => {
1040 write!(f, "{unauthorized}")
1041 }
1042 AdapterError::UnknownCursor(name) => {
1043 write!(f, "cursor {} does not exist", name.quoted())
1044 }
1045 AdapterError::UnknownLoginRole(name) => {
1046 write!(f, "role {} does not exist", name.quoted())
1047 }
1048 AdapterError::Unsupported(features) => write!(f, "{} are not supported", features),
1049 AdapterError::Unstructured(e) => write!(f, "{}", e.display_with_causes()),
1050 AdapterError::WriteOnlyTransaction => f.write_str("transaction in write-only mode"),
1051 AdapterError::UnknownPreparedStatement(name) => {
1052 write!(f, "prepared statement {} does not exist", name.quoted())
1053 }
1054 AdapterError::UnknownClusterReplica {
1055 cluster_name,
1056 replica_name,
1057 } => write!(
1058 f,
1059 "cluster replica '{cluster_name}.{replica_name}' does not exist"
1060 ),
1061 AdapterError::UnrecognizedConfigurationParam(setting_name) => write!(
1062 f,
1063 "unrecognized configuration parameter {}",
1064 setting_name.quoted()
1065 ),
1066 AdapterError::UntargetedLogRead { .. } => {
1067 f.write_str("log source reads must target a replica")
1068 }
1069 AdapterError::DDLOnlyTransaction => f.write_str(
1070 "transactions which modify objects are restricted to just modifying objects",
1071 ),
1072 AdapterError::DDLTransactionRace => f.write_str(
1073 "another session modified the catalog while this DDL transaction was open",
1074 ),
1075 AdapterError::Storage(e) => e.fmt(f),
1076 AdapterError::Compute(e) => e.fmt(f),
1077 AdapterError::Orchestrator(e) => e.fmt(f),
1078 AdapterError::DependentObject(dependent_objects) => {
1079 let role_str = if dependent_objects.keys().count() == 1 {
1080 "role"
1081 } else {
1082 "roles"
1083 };
1084 write!(
1085 f,
1086 "{role_str} \"{}\" cannot be dropped because some objects depend on it",
1087 dependent_objects.keys().join(", ")
1088 )
1089 }
1090 AdapterError::InvalidAlter(t, e) => {
1091 write!(f, "invalid ALTER {t}: {e}")
1092 }
1093 AdapterError::ConnectionValidation(e) => e.fmt(f),
1094 AdapterError::MaterializedViewWouldNeverRefresh(_, _) => {
1095 write!(
1096 f,
1097 "all the specified refreshes of the materialized view would be too far in the past, and thus they \
1098 would never happen"
1099 )
1100 }
1101 AdapterError::InputNotReadableAtRefreshAtTime(_, _) => {
1102 write!(
1103 f,
1104 "REFRESH AT requested for a time where not all the inputs are readable"
1105 )
1106 }
1107 AdapterError::RtrTimeout(_) => {
1108 write!(
1109 f,
1110 "timed out before ingesting the source's visible frontier when real-time-recency query issued"
1111 )
1112 }
1113 AdapterError::RtrDropFailure(_) => write!(
1114 f,
1115 "real-time source dropped before ingesting the upstream system's visible frontier"
1116 ),
1117 AdapterError::UnreadableSinkCollection => {
1118 write!(f, "collection is not readable at any time")
1119 }
1120 AdapterError::UserSessionsDisallowed => write!(f, "login blocked"),
1121 AdapterError::NetworkPolicyDenied(_) => write!(f, "session denied"),
1122 AdapterError::ReadOnly => write!(f, "cannot write in read-only mode"),
1123 AdapterError::AlterClusterTimeout => {
1124 write!(f, "canceling statement, provided timeout lapsed")
1125 }
1126 AdapterError::AuthenticationError(e) => {
1127 write!(f, "authentication error {e}")
1128 }
1129 AdapterError::UnavailableFeature { feature, docs } => {
1130 write!(f, "{} is not supported in this environment.", feature)?;
1131 if let Some(docs) = docs {
1132 write!(
1133 f,
1134 " For more information consult the documentation at {docs}"
1135 )?;
1136 }
1137 Ok(())
1138 }
1139 AdapterError::AlterClusterWhilePendingReplicas => {
1140 write!(f, "cannot alter clusters with pending updates")
1141 }
1142 AdapterError::ReplacementSchemaMismatch(_) => {
1143 write!(f, "replacement schema differs from target schema")
1144 }
1145 AdapterError::ImpossibleTimestampConstraints { .. } => {
1146 write!(f, "could not find a valid timestamp for the query")
1147 }
1148 AdapterError::OidcGroupSyncFailed(msg) => {
1149 write!(f, "OIDC group-to-role sync failed: {msg}")
1150 }
1151 }
1152 }
1153}
1154
1155impl From<anyhow::Error> for AdapterError {
1156 fn from(e: anyhow::Error) -> AdapterError {
1157 match e.downcast::<PlanError>() {
1158 Ok(plan_error) => AdapterError::PlanError(plan_error),
1159 Err(e) => AdapterError::Unstructured(e),
1160 }
1161 }
1162}
1163
1164impl From<TryFromIntError> for AdapterError {
1165 fn from(e: TryFromIntError) -> AdapterError {
1166 AdapterError::Unstructured(e.into())
1167 }
1168}
1169
1170impl From<TryFromDecimalError> for AdapterError {
1171 fn from(e: TryFromDecimalError) -> AdapterError {
1172 AdapterError::Unstructured(e.into())
1173 }
1174}
1175
1176impl From<mz_catalog::memory::error::Error> for AdapterError {
1177 fn from(e: mz_catalog::memory::error::Error) -> AdapterError {
1178 AdapterError::Catalog(e)
1179 }
1180}
1181
1182impl From<mz_catalog::durable::CatalogError> for AdapterError {
1183 fn from(e: mz_catalog::durable::CatalogError) -> Self {
1184 mz_catalog::memory::error::Error::from(e).into()
1185 }
1186}
1187
1188impl From<mz_catalog::durable::DurableCatalogError> for AdapterError {
1189 fn from(e: mz_catalog::durable::DurableCatalogError) -> Self {
1190 mz_catalog::durable::CatalogError::from(e).into()
1191 }
1192}
1193
1194impl From<EvalError> for AdapterError {
1195 fn from(e: EvalError) -> AdapterError {
1196 AdapterError::Eval(e)
1197 }
1198}
1199
1200impl From<ExplainError> for AdapterError {
1201 fn from(e: ExplainError) -> AdapterError {
1202 match e {
1203 ExplainError::RecursionLimitError(e) => AdapterError::RecursionLimit(e),
1204 e => AdapterError::Explain(e),
1205 }
1206 }
1207}
1208
1209impl From<mz_sql::catalog::CatalogError> for AdapterError {
1210 fn from(e: mz_sql::catalog::CatalogError) -> AdapterError {
1211 AdapterError::Catalog(mz_catalog::memory::error::Error::from(e))
1212 }
1213}
1214
1215impl From<PlanError> for AdapterError {
1216 fn from(e: PlanError) -> AdapterError {
1217 match e {
1218 PlanError::UnknownCursor(name) => AdapterError::UnknownCursor(name),
1219 _ => AdapterError::PlanError(e),
1220 }
1221 }
1222}
1223
1224impl From<OptimizerError> for AdapterError {
1225 fn from(e: OptimizerError) -> AdapterError {
1226 use OptimizerError::*;
1227 match e {
1228 PlanError(e) => Self::PlanError(e),
1229 RecursionLimitError(e) => Self::RecursionLimit(e),
1230 EvalError(e) => Self::Eval(e),
1231 InternalUnsafeMfpPlan(e) => Self::Internal(e),
1232 Internal(e) => Self::Internal(e),
1233 RestrictedFunction(func) => {
1234 Self::Unauthorized(mz_sql::rbac::UnauthorizedError::RestrictedSystemObject {
1235 object_name: format!("function {func}"),
1236 })
1237 }
1238 e => Self::Optimizer(e),
1239 }
1240 }
1241}
1242
1243impl From<NotNullViolation> for AdapterError {
1244 fn from(e: NotNullViolation) -> AdapterError {
1245 AdapterError::ConstraintViolation(e)
1246 }
1247}
1248
1249impl From<RecursionLimitError> for AdapterError {
1250 fn from(e: RecursionLimitError) -> AdapterError {
1251 AdapterError::RecursionLimit(e)
1252 }
1253}
1254
1255impl From<oneshot::error::RecvError> for AdapterError {
1256 fn from(e: oneshot::error::RecvError) -> AdapterError {
1257 AdapterError::Unstructured(e.into())
1258 }
1259}
1260
1261impl From<StorageError> for AdapterError {
1262 fn from(e: StorageError) -> Self {
1263 AdapterError::Storage(e)
1264 }
1265}
1266
1267impl From<compute_error::InstanceExists> for AdapterError {
1268 fn from(e: compute_error::InstanceExists) -> Self {
1269 AdapterError::Compute(e.into())
1270 }
1271}
1272
1273impl From<TimestampError> for AdapterError {
1274 fn from(e: TimestampError) -> Self {
1275 let e: EvalError = e.into();
1276 e.into()
1277 }
1278}
1279
1280impl From<mz_sql_parser::parser::ParserStatementError> for AdapterError {
1281 fn from(e: mz_sql_parser::parser::ParserStatementError) -> Self {
1282 AdapterError::ParseError(e)
1283 }
1284}
1285
1286impl From<VarError> for AdapterError {
1287 fn from(e: VarError) -> Self {
1288 let e: mz_catalog::memory::error::Error = e.into();
1289 e.into()
1290 }
1291}
1292
1293impl From<rbac::UnauthorizedError> for AdapterError {
1294 fn from(e: rbac::UnauthorizedError) -> Self {
1295 AdapterError::Unauthorized(e)
1296 }
1297}
1298
1299impl From<mz_sql_parser::ast::IdentError> for AdapterError {
1300 fn from(value: mz_sql_parser::ast::IdentError) -> Self {
1301 AdapterError::PlanError(PlanError::InvalidIdent(value))
1302 }
1303}
1304
1305impl From<mz_pgwire_common::ConnectionError> for AdapterError {
1306 fn from(value: mz_pgwire_common::ConnectionError) -> Self {
1307 match value {
1308 mz_pgwire_common::ConnectionError::TooManyConnections { current, limit } => {
1309 AdapterError::ResourceExhaustion {
1310 resource_type: "connection".into(),
1311 limit_name: "max_connections".into(),
1312 desired: (current + 1).to_string(),
1313 limit: limit.to_string(),
1314 current: current.to_string(),
1315 }
1316 }
1317 }
1318 }
1319}
1320
1321impl From<NetworkPolicyError> for AdapterError {
1322 fn from(value: NetworkPolicyError) -> Self {
1323 AdapterError::NetworkPolicyDenied(value)
1324 }
1325}
1326
1327impl From<ConnectionValidationError> for AdapterError {
1328 fn from(e: ConnectionValidationError) -> AdapterError {
1329 AdapterError::ConnectionValidation(e)
1330 }
1331}
1332
1333impl Error for AdapterError {}