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::array::InvalidArrayError;
28use mz_repr::adt::range::InvalidRangeError;
29use mz_repr::adt::timestamp::TimestampError;
30use mz_repr::explain::ExplainError;
31use mz_repr::strconv::{ParseError, ParseErrorKind};
32use mz_repr::{ColumnDiff, ColumnName, KeyDiff, NotNullViolation, RelationDescDiff, Timestamp};
33use mz_sql::plan::PlanError;
34use mz_sql::rbac;
35use mz_sql::session::vars::VarError;
36use mz_storage_types::connections::ConnectionValidationError;
37use mz_storage_types::controller::StorageError;
38use mz_storage_types::errors::CollectionMissing;
39use smallvec::SmallVec;
40use timely::progress::Antichain;
41use tokio::sync::oneshot;
42use tokio_postgres::error::SqlState;
43
44use crate::coord::NetworkPolicyError;
45use crate::optimize::OptimizerError;
46use crate::peek_client::CollectionLookupError;
47
48#[derive(Debug)]
50pub enum AdapterError {
51 AbsurdSubscribeBounds {
53 as_of: mz_repr::Timestamp,
54 up_to: mz_repr::Timestamp,
55 },
56 AmbiguousSystemColumnReference,
60 Catalog(mz_catalog::memory::error::Error),
62 ChangedPlan(String),
67 DuplicateCursor(String),
69 Eval(EvalError),
71 Explain(ExplainError),
73 IdExhaustionError,
75 Internal(String),
77 IntrospectionDisabled {
79 log_names: Vec<String>,
80 },
81 InvalidLogDependency {
84 object_type: String,
85 log_names: Vec<String>,
86 },
87 InvalidClusterReplicaAz {
89 az: String,
90 expected: Vec<String>,
91 },
92 InvalidSetIsolationLevel,
94 InvalidSetCluster,
96 InvalidStorageClusterSize {
98 size: String,
99 expected: Vec<String>,
100 },
101 SourceOrSinkSizeRequired {
103 expected: Vec<String>,
104 },
105 InvalidTableMutationSelection {
107 object_name: String,
109 object_type: String,
111 },
112 ConstraintViolation(NotNullViolation),
114 CopyFormatError(String),
116 ConcurrentClusterDrop,
118 ConcurrentDependencyDrop {
120 dependency_kind: &'static str,
121 dependency_id: String,
122 },
123 CollectionUnreadable {
124 id: String,
125 },
126 NoClusterReplicasAvailable {
128 name: String,
129 is_managed: bool,
130 },
131 OperationProhibitsTransaction(String),
133 OperationRequiresTransaction(String),
135 PlanError(PlanError),
137 PreparedStatementExists(String),
139 ParseError(mz_sql_parser::parser::ParserStatementError),
141 ReadOnlyTransaction,
143 ReadWriteUnavailable,
145 RecursionLimit(RecursionLimitError),
147 RelationOutsideTimeDomain {
150 relations: Vec<String>,
151 names: Vec<String>,
152 },
153 ResourceExhaustion {
155 resource_type: String,
156 limit_name: String,
157 desired: String,
158 limit: String,
159 current: String,
160 },
161 ResultSize(String),
163 SafeModeViolation(String),
165 WrongSetOfLocks,
167 StatementTimeout,
171 Canceled,
173 IdleInTransactionSessionTimeout,
175 SubscribeOnlyTransaction,
177 Optimizer(OptimizerError),
179 UnallowedOnCluster {
181 depends_on: SmallVec<[String; 2]>,
182 cluster: String,
183 },
184 Unauthorized(rbac::UnauthorizedError),
186 UnknownCursor(String),
188 UnknownLoginRole(String),
190 UnknownPreparedStatement(String),
191 UnknownClusterReplica {
193 cluster_name: String,
194 replica_name: String,
195 },
196 UnrecognizedConfigurationParam(String),
198 Unstructured(anyhow::Error),
202 Unsupported(&'static str),
204 UnavailableFeature {
208 feature: String,
209 docs: Option<String>,
210 },
211 UntargetedLogRead {
213 log_names: Vec<String>,
214 },
215 WriteOnlyTransaction,
217 SingleStatementTransaction,
219 DDLOnlyTransaction,
221 DDLTransactionRace,
223 Storage(mz_storage_types::controller::StorageError),
225 Compute(anyhow::Error),
227 Orchestrator(anyhow::Error),
229 DependentObject(BTreeMap<String, Vec<String>>),
233 InvalidAlter(&'static str, PlanError),
236 ConnectionValidation(ConnectionValidationError),
238 MaterializedViewWouldNeverRefresh(Timestamp, Timestamp),
242 InputNotReadableAtRefreshAtTime(Timestamp, Antichain<Timestamp>),
245 RtrTimeout(String),
247 RtrDropFailure(String),
249 UnreadableSinkCollection,
251 UserSessionsDisallowed,
253 NetworkPolicyDenied(NetworkPolicyError),
255 ReadOnly,
258 AlterClusterTimeout,
259 AlterClusterWhilePendingReplicas,
260 AuthenticationError(AuthenticationError),
261 ReplacementSchemaMismatch(RelationDescDiff),
263 ReplaceMaterializedViewSealed {
265 name: String,
266 },
267 ImpossibleTimestampConstraints {
269 constraints: String,
270 },
271 OidcGroupSyncFailed(String),
273 BoundedStalenessExceeded {
277 bound: std::time::Duration,
278 gap_ms: u64,
279 slowest_input: Option<mz_repr::GlobalId>,
280 },
281 BoundedStalenessReadOnly,
284 BoundedStalenessRealTimeRecencyConflict,
287 BoundedStalenessTimelineUnsupported,
290}
291
292#[derive(Debug, thiserror::Error)]
293pub enum AuthenticationError {
294 #[error("invalid credentials")]
295 InvalidCredentials,
296 #[error("role is not allowed to login")]
297 NonLogin,
298 #[error("role does not exist")]
299 RoleNotFound,
300 #[error("password is required")]
301 PasswordRequired,
302}
303
304fn parse_error_code(err: &ParseError) -> SqlState {
309 let is_datetime = matches!(
310 &*err.type_name,
311 "date" | "time" | "timestamp" | "timestamp with time zone" | "interval"
312 );
313 match (err.kind, is_datetime) {
314 (ParseErrorKind::OutOfRange, true) => SqlState::DATETIME_FIELD_OVERFLOW,
315 (ParseErrorKind::OutOfRange, false) => SqlState::NUMERIC_VALUE_OUT_OF_RANGE,
316 (ParseErrorKind::InvalidInputSyntax, true) => SqlState::INVALID_DATETIME_FORMAT,
317 (ParseErrorKind::InvalidInputSyntax, false) => SqlState::INVALID_TEXT_REPRESENTATION,
318 }
319}
320
321fn eval_error_code(err: &EvalError) -> SqlState {
331 match err {
332 EvalError::DivisionByZero => SqlState::DIVISION_BY_ZERO,
334 EvalError::NegSqrt | EvalError::ComplexOutOfRange(_) => {
335 SqlState::INVALID_ARGUMENT_FOR_POWER_FUNCTION
336 }
337 EvalError::InfinityOutOfDomain(_)
338 | EvalError::NegativeOutOfDomain(_)
339 | EvalError::ZeroOutOfDomain(_)
340 | EvalError::OutOfDomain(..)
341 | EvalError::Undefined(_) => SqlState::INVALID_PARAMETER_VALUE,
342
343 EvalError::FloatOverflow
345 | EvalError::FloatUnderflow
346 | EvalError::NumericFieldOverflow
347 | EvalError::Float32OutOfRange(_)
348 | EvalError::Float64OutOfRange(_)
349 | EvalError::Int16OutOfRange(_)
350 | EvalError::Int32OutOfRange(_)
351 | EvalError::Int64OutOfRange(_)
352 | EvalError::UInt16OutOfRange(_)
353 | EvalError::UInt32OutOfRange(_)
354 | EvalError::UInt64OutOfRange(_)
355 | EvalError::OidOutOfRange(_)
356 | EvalError::MzTimestampOutOfRange(_)
357 | EvalError::MzTimestampStepOverflow
358 | EvalError::CharOutOfRange => SqlState::NUMERIC_VALUE_OUT_OF_RANGE,
359
360 EvalError::DateOutOfRange
362 | EvalError::TimestampOutOfRange
363 | EvalError::TimestampCannotBeNan
364 | EvalError::DateBinOutOfRange(_)
365 | EvalError::DateDiffOverflow { .. } => SqlState::DATETIME_FIELD_OVERFLOW,
366 EvalError::IntervalOutOfRange(_) => SqlState::INTERVAL_FIELD_OVERFLOW,
367
368 EvalError::Parse(e) => parse_error_code(e),
370 EvalError::ParseHex(_)
371 | EvalError::InvalidBase64Equals
372 | EvalError::InvalidBase64Symbol(_)
373 | EvalError::InvalidBase64EndSequence => SqlState::INVALID_TEXT_REPRESENTATION,
374 EvalError::InvalidByteSequence { .. } => SqlState::CHARACTER_NOT_IN_REPERTOIRE,
375 EvalError::CharacterNotValidForEncoding(_) | EvalError::CharacterTooLargeForEncoding(_) => {
376 SqlState::PROGRAM_LIMIT_EXCEEDED
377 }
378
379 EvalError::InvalidTimezone(_)
381 | EvalError::InvalidTimezoneInterval
382 | EvalError::InvalidTimezoneConversion
383 | EvalError::InvalidIanaTimezoneId(_)
384 | EvalError::InvalidLayer { .. }
385 | EvalError::InvalidEncodingName(_)
386 | EvalError::InvalidHashAlgorithm(_)
387 | EvalError::InvalidDatePart(_)
388 | EvalError::InvalidParameterValue(_)
389 | EvalError::InvalidJsonbCast { .. }
390 | EvalError::UnknownUnits(_)
391 | EvalError::UnsupportedUnits(..)
392 | EvalError::InvalidIdentifier { .. }
393 | EvalError::InvalidRoleId(_)
394 | EvalError::InvalidPrivileges(_)
395 | EvalError::NegLimit => SqlState::INVALID_PARAMETER_VALUE,
396
397 EvalError::InvalidRegex(_) | EvalError::InvalidRegexFlag(_) => {
399 SqlState::INVALID_REGULAR_EXPRESSION
400 }
401
402 EvalError::UnterminatedLikeEscapeSequence | EvalError::LikeEscapeTooLong => {
404 SqlState::INVALID_ESCAPE_SEQUENCE
405 }
406
407 EvalError::KeyCannotBeNull
409 | EvalError::MustNotBeNull(_)
410 | EvalError::AclArrayNullElement
411 | EvalError::MzAclArrayNullElement => SqlState::NULL_VALUE_NOT_ALLOWED,
412
413 EvalError::IndexOutOfRange { .. }
415 | EvalError::ArrayFillWrongArraySubscripts
416 | EvalError::IncompatibleArrayDimensions { .. } => SqlState::ARRAY_SUBSCRIPT_ERROR,
417 EvalError::InvalidArray(e) => match e {
418 InvalidArrayError::TooManyDimensions(_) => SqlState::PROGRAM_LIMIT_EXCEEDED,
419 InvalidArrayError::WrongCardinality { .. } => SqlState::ARRAY_SUBSCRIPT_ERROR,
420 },
421
422 EvalError::InvalidRange(e) => match e {
424 InvalidRangeError::CanonicalizationOverflow(_) => SqlState::NUMERIC_VALUE_OUT_OF_RANGE,
425 InvalidRangeError::MisorderedRangeBounds
426 | InvalidRangeError::InvalidRangeBoundFlags
427 | InvalidRangeError::NullRangeBoundFlags
428 | InvalidRangeError::DiscontiguousUnion
429 | InvalidRangeError::DiscontiguousDifference => SqlState::DATA_EXCEPTION,
430 },
431
432 EvalError::MultipleRowsFromSubquery | EvalError::NegativeRowsFromSubquery => {
434 SqlState::CARDINALITY_VIOLATION
435 }
436
437 EvalError::StringValueTooLong { .. } => SqlState::STRING_DATA_RIGHT_TRUNCATION,
439 EvalError::LikePatternTooLong
440 | EvalError::LengthTooLarge
441 | EvalError::NullCharacterNotPermitted
442 | EvalError::MaxArraySizeExceeded(_)
443 | EvalError::LetRecLimitExceeded(_) => SqlState::PROGRAM_LIMIT_EXCEEDED,
444
445 EvalError::Unsupported { .. }
447 | EvalError::MultidimensionalArrayRemovalNotSupported
448 | EvalError::MultiDimensionalArraySearch => SqlState::FEATURE_NOT_SUPPORTED,
449
450 EvalError::IfNullError(_) => SqlState::DATA_EXCEPTION,
452
453 EvalError::Internal(_)
455 | EvalError::InvalidCatalogJson(_)
456 | EvalError::TypeFromOid(_)
457 | EvalError::PrettyError(_)
458 | EvalError::RedactError(_) => SqlState::INTERNAL_ERROR,
459 }
460}
461
462impl AdapterError {
463 pub fn into_response(self, severity: Severity) -> ErrorResponse {
464 ErrorResponse {
465 severity,
466 code: self.code(),
467 message: self.to_string(),
468 detail: self.detail(),
469 hint: self.hint(),
470 position: self.position(),
471 }
472 }
473
474 pub fn position(&self) -> Option<usize> {
475 match self {
476 AdapterError::ParseError(err) => Some(err.error.pos),
477 _ => None,
478 }
479 }
480
481 pub fn detail(&self) -> Option<String> {
483 match self {
484 AdapterError::AmbiguousSystemColumnReference => {
485 Some("This is a current limitation in Materialize".into())
486 }
487 AdapterError::Catalog(c) => c.detail(),
488 AdapterError::Eval(e) => e.detail(),
489 AdapterError::RelationOutsideTimeDomain { relations, names } => Some(format!(
490 "The following relations in the query are outside the transaction's time domain:\n{}\n{}",
491 relations
492 .iter()
493 .map(|r| r.quoted().to_string())
494 .collect::<Vec<_>>()
495 .join("\n"),
496 match names.is_empty() {
497 true => "No relations are available.".to_string(),
498 false => format!(
499 "Only the following relations are available:\n{}",
500 names
501 .iter()
502 .map(|name| name.quoted().to_string())
503 .collect::<Vec<_>>()
504 .join("\n")
505 ),
506 }
507 )),
508 AdapterError::SourceOrSinkSizeRequired { .. } => Some(
509 "Either specify the cluster that will maintain this object via IN CLUSTER or \
510 specify size via SIZE option."
511 .into(),
512 ),
513 AdapterError::InvalidTableMutationSelection {
514 object_name,
515 object_type,
516 } => Some(format!(
517 "{object_type} '{}' may not be used in this operation; \
518 the selection may refer to views and materialized views, but transitive \
519 dependencies must not include sources or source-export tables",
520 object_name.quoted()
521 )),
522 AdapterError::SafeModeViolation(_) => Some(
523 "The Materialize server you are connected to is running in \
524 safe mode, which limits the features that are available."
525 .into(),
526 ),
527 AdapterError::IntrospectionDisabled { log_names }
528 | AdapterError::UntargetedLogRead { log_names } => Some(format!(
529 "The query references the following log sources:\n {}",
530 log_names.join("\n "),
531 )),
532 AdapterError::InvalidLogDependency { log_names, .. } => Some(format!(
533 "The object depends on the following log sources:\n {}",
534 log_names.join("\n "),
535 )),
536 AdapterError::PlanError(e) => e.detail(),
537 AdapterError::Unauthorized(unauthorized) => unauthorized.detail(),
538 AdapterError::DependentObject(dependent_objects) => Some(
539 dependent_objects
540 .iter()
541 .map(|(role_name, err_msgs)| {
542 err_msgs
543 .iter()
544 .map(|err_msg| format!("{role_name}: {err_msg}"))
545 .join("\n")
546 })
547 .join("\n"),
548 ),
549 AdapterError::Storage(storage_error) => storage_error
550 .source()
551 .map(|source_error| source_error.to_string_with_causes()),
552 AdapterError::ReadOnlyTransaction => Some(
553 "SELECT queries cannot be combined with other query types, including SUBSCRIBE."
554 .into(),
555 ),
556 AdapterError::InvalidAlter(_, e) => e.detail(),
557 AdapterError::Optimizer(e) => e.detail(),
558 AdapterError::ConnectionValidation(e) => e.detail(),
559 AdapterError::MaterializedViewWouldNeverRefresh(last_refresh, earliest_possible) => {
560 Some(format!(
561 "The specified last refresh is at {}, while the earliest possible time to compute the materialized \
562 view is {}.",
563 last_refresh, earliest_possible,
564 ))
565 }
566 AdapterError::UnallowedOnCluster { cluster, .. } => {
567 (cluster == MZ_CATALOG_SERVER_CLUSTER.name).then(|| {
568 format!(
569 "The transaction is executing on the \
570 {cluster} cluster, maybe having been routed \
571 there by the first statement in the transaction."
572 )
573 })
574 }
575 AdapterError::InputNotReadableAtRefreshAtTime(oracle_read_ts, least_valid_read) => {
576 Some(format!(
577 "The requested REFRESH AT time is {}, \
578 but not all input collections are readable earlier than [{}].",
579 oracle_read_ts,
580 if least_valid_read.len() == 1 {
581 format!(
582 "{}",
583 least_valid_read
584 .as_option()
585 .expect("antichain contains exactly 1 timestamp")
586 )
587 } else {
588 format!("{:?}", least_valid_read)
590 }
591 ))
592 }
593 AdapterError::RtrTimeout(name) => Some(format!(
594 "{name} failed to ingest data up to the real-time recency point"
595 )),
596 AdapterError::RtrDropFailure(name) => Some(format!(
597 "{name} dropped before ingesting data to the real-time recency point"
598 )),
599 AdapterError::UserSessionsDisallowed => {
600 Some("Your organization has been blocked. Please contact support.".to_string())
601 }
602 AdapterError::NetworkPolicyDenied(reason) => Some(format!("{reason}.")),
603 AdapterError::ReplacementSchemaMismatch(diff) => {
604 let mut lines: Vec<_> = diff.column_diffs.iter().map(|(idx, diff)| {
605 let pos = idx + 1;
606 match diff {
607 ColumnDiff::Missing { name } => {
608 let name = name.as_str().quoted();
609 format!("missing column {name} at position {pos}")
610 }
611 ColumnDiff::Extra { name } => {
612 let name = name.as_str().quoted();
613 format!("extra column {name} at position {pos}")
614 }
615 ColumnDiff::TypeMismatch { name, left, right } => {
616 let name = name.as_str().quoted();
617 format!("column {name} at position {pos}: type mismatch (target: {left:?}, replacement: {right:?})")
618 }
619 ColumnDiff::NullabilityMismatch { name, left, right } => {
620 let name = name.as_str().quoted();
621 let left = if *left { "NULL" } else { "NOT NULL" };
622 let right = if *right { "NULL" } else { "NOT NULL" };
623 format!("column {name} at position {pos}: nullability mismatch (target: {left}, replacement: {right})")
624 }
625 ColumnDiff::NameMismatch { left, right } => {
626 let left = left.as_str().quoted();
627 let right = right.as_str().quoted();
628 format!("column at position {pos}: name mismatch (target: {left}, replacement: {right})")
629 }
630 }
631 }).collect();
632
633 if let Some(KeyDiff { left, right }) = &diff.key_diff {
634 let format_keys = |keys: &BTreeSet<Vec<ColumnName>>| {
635 if keys.is_empty() {
636 "(none)".to_string()
637 } else {
638 keys.iter()
639 .map(|key| {
640 let cols = key.iter().map(|c| c.as_str()).join(", ");
641 format!("{{{cols}}}")
642 })
643 .join(", ")
644 }
645 };
646 lines.push(format!(
647 "keys differ (target: {}, replacement: {})",
648 format_keys(left),
649 format_keys(right)
650 ));
651 }
652 Some(lines.join("\n"))
653 }
654 AdapterError::ReplaceMaterializedViewSealed { .. } => Some(
655 "The materialized view has already computed its output until the end of time, \
656 so replacing its definition would have no effect."
657 .into(),
658 ),
659 AdapterError::ImpossibleTimestampConstraints { constraints } => {
660 Some(format!("Constraints:\n{}", constraints))
661 }
662 AdapterError::BoundedStalenessExceeded {
663 gap_ms,
664 slowest_input,
665 ..
666 } => {
667 let mut detail = format!(
668 "Freshest available timestamp is {}ms older than the bound.",
669 gap_ms,
670 );
671 if let Some(id) = slowest_input {
672 detail.push_str(&format!(" Slowest input: {}.", id));
673 }
674 Some(detail)
675 }
676 AdapterError::BoundedStalenessTimelineUnsupported => Some(
677 "This query touches a timeline other than the EpochMilliseconds wall-clock \
678 timeline."
679 .into(),
680 ),
681 _ => None,
682 }
683 }
684
685 pub fn hint(&self) -> Option<String> {
687 match self {
688 AdapterError::AmbiguousSystemColumnReference => Some(
689 "Rewrite the view to refer to all columns by name. Expand all wildcards and \
690 convert all NATURAL JOINs to USING joins."
691 .to_string(),
692 ),
693 AdapterError::Catalog(c) => c.hint(),
694 AdapterError::Eval(e) => e.hint(),
695 AdapterError::InvalidClusterReplicaAz { expected, az: _ } => {
696 Some(if expected.is_empty() {
697 "No availability zones configured; do not specify AVAILABILITY ZONE".into()
698 } else {
699 format!("Valid availability zones are: {}", expected.join(", "))
700 })
701 }
702 AdapterError::InvalidStorageClusterSize { expected, .. } => {
703 Some(format!("Valid sizes are: {}", expected.join(", ")))
704 }
705 AdapterError::SourceOrSinkSizeRequired { expected } => Some(format!(
706 "Try choosing one of the smaller sizes to start. Available sizes: {}",
707 expected.join(", ")
708 )),
709 AdapterError::NoClusterReplicasAvailable { is_managed, .. } => {
710 Some(if *is_managed {
711 "Use ALTER CLUSTER to adjust the replication factor of the cluster. \
712 Example:`ALTER CLUSTER <cluster-name> SET (REPLICATION FACTOR 1)`".into()
713 } else {
714 "Use CREATE CLUSTER REPLICA to attach cluster replicas to the cluster".into()
715 })
716 }
717 AdapterError::UntargetedLogRead { .. } => Some(
718 "Use `SET cluster_replica = <replica-name>` to target a specific replica in the \
719 active cluster. Note that subsequent queries will only be answered by \
720 the selected replica, which might reduce availability. To undo the replica \
721 selection, use `RESET cluster_replica`."
722 .into(),
723 ),
724 AdapterError::ResourceExhaustion { resource_type, .. } => Some(format!(
725 "Drop an existing {resource_type} or contact support to request a limit increase."
726 )),
727 AdapterError::StatementTimeout => Some(
728 "Consider increasing the maximum allowed statement duration for this session by \
729 setting the statement_timeout session variable. For example, `SET \
730 statement_timeout = '120s'`."
731 .into(),
732 ),
733 AdapterError::PlanError(e) => e.hint(),
734 AdapterError::UnallowedOnCluster { cluster, .. } => {
735 (cluster != MZ_CATALOG_SERVER_CLUSTER.name).then(||
736 "Use `SET CLUSTER = <cluster-name>` to change your cluster and re-run the query."
737 .to_string()
738 )
739 }
740 AdapterError::InvalidAlter(_, e) => e.hint(),
741 AdapterError::Optimizer(e) => e.hint(),
742 AdapterError::ConnectionValidation(e) => e.hint(),
743 AdapterError::InputNotReadableAtRefreshAtTime(_, _) => Some(
744 "You can use `REFRESH AT greatest(mz_now(), <explicit timestamp>)` to refresh \
745 either at the explicitly specified timestamp, or now if the given timestamp would \
746 be in the past.".to_string()
747 ),
748 AdapterError::AlterClusterTimeout => Some(
749 "Consider increasing the timeout duration in the alter cluster statement.".into(),
750 ),
751 AdapterError::DDLTransactionRace => Some(
752 "Currently, DDL transactions fail when any other DDL happens concurrently, \
753 even on unrelated schemas/clusters.".into()
754 ),
755 AdapterError::CollectionUnreadable { .. } => Some(
756 "This could be because the collection has recently been dropped.".into()
757 ),
758 _ => None,
759 }
760 }
761
762 pub fn code(&self) -> SqlState {
763 const RECURSION_LIMIT_ERROR_CODE: SqlState = SqlState::INTERNAL_ERROR;
765
766 match self {
771 AdapterError::AbsurdSubscribeBounds { .. } => SqlState::DATA_EXCEPTION,
774 AdapterError::AmbiguousSystemColumnReference => SqlState::FEATURE_NOT_SUPPORTED,
775 AdapterError::Catalog(e) => match &e.kind {
776 mz_catalog::memory::error::ErrorKind::VarError(e) => match e {
777 VarError::ConstrainedParameter { .. } => SqlState::INVALID_PARAMETER_VALUE,
778 VarError::FixedValueParameter { .. } => SqlState::INVALID_PARAMETER_VALUE,
779 VarError::InvalidParameterType { .. } => SqlState::INVALID_PARAMETER_VALUE,
780 VarError::InvalidParameterValue { .. } => SqlState::INVALID_PARAMETER_VALUE,
781 VarError::ReadOnlyParameter(_) => SqlState::CANT_CHANGE_RUNTIME_PARAM,
782 VarError::UnknownParameter(_) => SqlState::UNDEFINED_OBJECT,
783 VarError::RequiresUnsafeMode { .. } => SqlState::CANT_CHANGE_RUNTIME_PARAM,
784 VarError::RequiresFeatureFlag { .. } => SqlState::CANT_CHANGE_RUNTIME_PARAM,
785 },
786 _ => SqlState::INTERNAL_ERROR,
787 },
788 AdapterError::ChangedPlan(_) => SqlState::FEATURE_NOT_SUPPORTED,
789 AdapterError::DuplicateCursor(_) => SqlState::DUPLICATE_CURSOR,
790 AdapterError::Eval(e) => eval_error_code(e),
795 AdapterError::Explain(_) => SqlState::INTERNAL_ERROR,
796 AdapterError::IdExhaustionError => SqlState::INTERNAL_ERROR,
797 AdapterError::Internal(_) => SqlState::INTERNAL_ERROR,
798 AdapterError::IntrospectionDisabled { .. } => SqlState::FEATURE_NOT_SUPPORTED,
799 AdapterError::InvalidLogDependency { .. } => SqlState::FEATURE_NOT_SUPPORTED,
800 AdapterError::InvalidClusterReplicaAz { .. } => SqlState::FEATURE_NOT_SUPPORTED,
801 AdapterError::InvalidSetIsolationLevel => SqlState::ACTIVE_SQL_TRANSACTION,
802 AdapterError::InvalidSetCluster => SqlState::ACTIVE_SQL_TRANSACTION,
803 AdapterError::InvalidStorageClusterSize { .. } => SqlState::FEATURE_NOT_SUPPORTED,
804 AdapterError::SourceOrSinkSizeRequired { .. } => SqlState::FEATURE_NOT_SUPPORTED,
805 AdapterError::InvalidTableMutationSelection { .. } => {
806 SqlState::INVALID_TRANSACTION_STATE
807 }
808 AdapterError::ConstraintViolation(NotNullViolation(_)) => SqlState::NOT_NULL_VIOLATION,
809 AdapterError::CopyFormatError(_) => SqlState::BAD_COPY_FILE_FORMAT,
810 AdapterError::ConcurrentClusterDrop => SqlState::INVALID_TRANSACTION_STATE,
811 AdapterError::ConcurrentDependencyDrop { .. } => SqlState::UNDEFINED_OBJECT,
812 AdapterError::CollectionUnreadable { .. } => SqlState::NO_DATA_FOUND,
813 AdapterError::NoClusterReplicasAvailable { .. } => SqlState::FEATURE_NOT_SUPPORTED,
814 AdapterError::OperationProhibitsTransaction(_) => SqlState::ACTIVE_SQL_TRANSACTION,
815 AdapterError::OperationRequiresTransaction(_) => SqlState::NO_ACTIVE_SQL_TRANSACTION,
816 AdapterError::ParseError(_) => SqlState::SYNTAX_ERROR,
817 AdapterError::PlanError(PlanError::InvalidSchemaName) => SqlState::INVALID_SCHEMA_NAME,
818 AdapterError::PlanError(PlanError::ColumnAlreadyExists { .. }) => {
819 SqlState::DUPLICATE_COLUMN
820 }
821 AdapterError::PlanError(PlanError::UnknownParameter(_)) => {
822 SqlState::UNDEFINED_PARAMETER
823 }
824 AdapterError::PlanError(PlanError::ParameterNotAllowed(_)) => {
825 SqlState::UNDEFINED_PARAMETER
826 }
827 AdapterError::PlanError(_) => SqlState::INTERNAL_ERROR,
828 AdapterError::PreparedStatementExists(_) => SqlState::DUPLICATE_PSTATEMENT,
829 AdapterError::ReadOnlyTransaction => SqlState::READ_ONLY_SQL_TRANSACTION,
830 AdapterError::ReadWriteUnavailable => SqlState::INVALID_TRANSACTION_STATE,
831 AdapterError::SingleStatementTransaction => SqlState::INVALID_TRANSACTION_STATE,
832 AdapterError::WrongSetOfLocks => SqlState::LOCK_NOT_AVAILABLE,
833 AdapterError::StatementTimeout => SqlState::QUERY_CANCELED,
834 AdapterError::Canceled => SqlState::QUERY_CANCELED,
835 AdapterError::IdleInTransactionSessionTimeout => {
836 SqlState::IDLE_IN_TRANSACTION_SESSION_TIMEOUT
837 }
838 AdapterError::RecursionLimit(_) => RECURSION_LIMIT_ERROR_CODE,
839 AdapterError::RelationOutsideTimeDomain { .. } => SqlState::INVALID_TRANSACTION_STATE,
840 AdapterError::ResourceExhaustion { .. } => SqlState::INSUFFICIENT_RESOURCES,
841 AdapterError::ResultSize(_) => SqlState::OUT_OF_MEMORY,
842 AdapterError::SafeModeViolation(_) => SqlState::INTERNAL_ERROR,
843 AdapterError::SubscribeOnlyTransaction => SqlState::INVALID_TRANSACTION_STATE,
844 AdapterError::Optimizer(e) => match e {
845 OptimizerError::PlanError(PlanError::InvalidSchemaName) => {
846 SqlState::INVALID_SCHEMA_NAME
847 }
848 OptimizerError::PlanError(PlanError::ColumnAlreadyExists { .. }) => {
849 SqlState::DUPLICATE_COLUMN
850 }
851 OptimizerError::PlanError(PlanError::UnknownParameter(_)) => {
852 SqlState::UNDEFINED_PARAMETER
853 }
854 OptimizerError::PlanError(PlanError::ParameterNotAllowed(_)) => {
855 SqlState::UNDEFINED_PARAMETER
856 }
857 OptimizerError::PlanError(_) => SqlState::INTERNAL_ERROR,
858 OptimizerError::RecursionLimitError(_) => RECURSION_LIMIT_ERROR_CODE,
859 OptimizerError::Internal(s) => {
860 AdapterError::Internal(s.clone()).code() }
862 OptimizerError::EvalError(e) => {
863 AdapterError::Eval(e.clone()).code() }
865 OptimizerError::TransformError(_) => SqlState::INTERNAL_ERROR,
866 OptimizerError::UnmaterializableFunction(_) => SqlState::FEATURE_NOT_SUPPORTED,
867 OptimizerError::UncallableFunction { .. } => SqlState::FEATURE_NOT_SUPPORTED,
868 OptimizerError::UnsupportedTemporalExpression(_) => SqlState::FEATURE_NOT_SUPPORTED,
869 OptimizerError::RestrictedFunction(_) => SqlState::INSUFFICIENT_PRIVILEGE,
870 OptimizerError::InternalUnsafeMfpPlan(_) => SqlState::INTERNAL_ERROR,
873 },
874 AdapterError::UnallowedOnCluster { .. } => {
875 SqlState::S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED
876 }
877 AdapterError::Unauthorized(_) => SqlState::INSUFFICIENT_PRIVILEGE,
878 AdapterError::UnknownCursor(_) => SqlState::INVALID_CURSOR_NAME,
879 AdapterError::UnknownPreparedStatement(_) => SqlState::UNDEFINED_PSTATEMENT,
880 AdapterError::UnknownLoginRole(_) => SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
881 AdapterError::UnknownClusterReplica { .. } => SqlState::UNDEFINED_OBJECT,
882 AdapterError::UnrecognizedConfigurationParam(_) => SqlState::UNDEFINED_OBJECT,
883 AdapterError::Unsupported(..) => SqlState::FEATURE_NOT_SUPPORTED,
884 AdapterError::UnavailableFeature { .. } => SqlState::FEATURE_NOT_SUPPORTED,
885 AdapterError::Unstructured(_) => SqlState::INTERNAL_ERROR,
886 AdapterError::UntargetedLogRead { .. } => SqlState::FEATURE_NOT_SUPPORTED,
887 AdapterError::DDLTransactionRace => SqlState::T_R_SERIALIZATION_FAILURE,
888 AdapterError::WriteOnlyTransaction => SqlState::INVALID_TRANSACTION_STATE,
893 AdapterError::DDLOnlyTransaction => SqlState::INVALID_TRANSACTION_STATE,
894 AdapterError::Storage(_) | AdapterError::Compute(_) | AdapterError::Orchestrator(_) => {
895 SqlState::INTERNAL_ERROR
896 }
897 AdapterError::DependentObject(_) => SqlState::DEPENDENT_OBJECTS_STILL_EXIST,
898 AdapterError::InvalidAlter(_, _) => SqlState::FEATURE_NOT_SUPPORTED,
899 AdapterError::ConnectionValidation(_) => SqlState::SYSTEM_ERROR,
900 AdapterError::MaterializedViewWouldNeverRefresh(_, _) => SqlState::DATA_EXCEPTION,
902 AdapterError::InputNotReadableAtRefreshAtTime(_, _) => SqlState::DATA_EXCEPTION,
903 AdapterError::RtrTimeout(_) => SqlState::QUERY_CANCELED,
904 AdapterError::RtrDropFailure(_) => SqlState::UNDEFINED_OBJECT,
905 AdapterError::UnreadableSinkCollection => SqlState::from_code("MZ009"),
906 AdapterError::UserSessionsDisallowed => SqlState::from_code("MZ010"),
907 AdapterError::NetworkPolicyDenied(_) => SqlState::from_code("MZ011"),
908 AdapterError::ReadOnly => SqlState::READ_ONLY_SQL_TRANSACTION,
911 AdapterError::AlterClusterTimeout => SqlState::QUERY_CANCELED,
912 AdapterError::AlterClusterWhilePendingReplicas => SqlState::OBJECT_IN_USE,
913 AdapterError::ReplacementSchemaMismatch(_) => SqlState::FEATURE_NOT_SUPPORTED,
914 AdapterError::AuthenticationError(AuthenticationError::InvalidCredentials) => {
915 SqlState::INVALID_PASSWORD
916 }
917 AdapterError::AuthenticationError(_) => SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
918 AdapterError::ReplaceMaterializedViewSealed { .. } => {
919 SqlState::OBJECT_NOT_IN_PREREQUISITE_STATE
920 }
921 AdapterError::ImpossibleTimestampConstraints { .. } => SqlState::DATA_EXCEPTION,
923 AdapterError::OidcGroupSyncFailed(_) => SqlState::INTERNAL_ERROR,
924 AdapterError::BoundedStalenessExceeded { .. } => SqlState::T_R_SERIALIZATION_FAILURE,
925 AdapterError::BoundedStalenessReadOnly => SqlState::READ_ONLY_SQL_TRANSACTION,
928 AdapterError::BoundedStalenessRealTimeRecencyConflict => {
929 SqlState::FEATURE_NOT_SUPPORTED
930 }
931 AdapterError::BoundedStalenessTimelineUnsupported => SqlState::FEATURE_NOT_SUPPORTED,
932 }
933 }
934
935 pub fn internal<E: std::fmt::Display>(context: &str, e: E) -> AdapterError {
936 AdapterError::Internal(format!("{context}: {e}"))
937 }
938
939 pub fn concurrent_dependency_drop_from_instance_missing(e: InstanceMissing) -> Self {
946 AdapterError::ConcurrentDependencyDrop {
947 dependency_kind: "cluster",
948 dependency_id: e.0.to_string(),
949 }
950 }
951
952 pub fn concurrent_dependency_drop_from_collection_missing(e: CollectionMissing) -> Self {
953 AdapterError::ConcurrentDependencyDrop {
954 dependency_kind: "collection",
955 dependency_id: e.0.to_string(),
956 }
957 }
958
959 pub fn concurrent_dependency_drop_from_collection_lookup_error(
960 e: CollectionLookupError,
961 compute_instance: ComputeInstanceId,
962 ) -> Self {
963 match e {
964 CollectionLookupError::InstanceMissing(id) => AdapterError::ConcurrentDependencyDrop {
965 dependency_kind: "cluster",
966 dependency_id: id.to_string(),
967 },
968 CollectionLookupError::CollectionMissing(id) => {
969 AdapterError::ConcurrentDependencyDrop {
970 dependency_kind: "collection",
971 dependency_id: id.to_string(),
972 }
973 }
974 CollectionLookupError::InstanceShutDown => AdapterError::ConcurrentDependencyDrop {
975 dependency_kind: "cluster",
976 dependency_id: compute_instance.to_string(),
977 },
978 }
979 }
980
981 pub fn concurrent_dependency_drop_from_watch_set_install_error(
982 e: compute_error::CollectionLookupError,
983 ) -> Self {
984 match e {
985 compute_error::CollectionLookupError::InstanceMissing(id) => {
986 AdapterError::ConcurrentDependencyDrop {
987 dependency_kind: "cluster",
988 dependency_id: id.to_string(),
989 }
990 }
991 compute_error::CollectionLookupError::CollectionMissing(id) => {
992 AdapterError::ConcurrentDependencyDrop {
993 dependency_kind: "collection",
994 dependency_id: id.to_string(),
995 }
996 }
997 }
998 }
999
1000 pub fn concurrent_dependency_drop_from_instance_peek_error(
1001 e: mz_compute_client::controller::instance_client::PeekError,
1002 compute_instance: ComputeInstanceId,
1003 ) -> AdapterError {
1004 use mz_compute_client::controller::instance_client::PeekError::*;
1005 match e {
1006 ReplicaMissing(id) => AdapterError::ConcurrentDependencyDrop {
1007 dependency_kind: "replica",
1008 dependency_id: id.to_string(),
1009 },
1010 InstanceShutDown => AdapterError::ConcurrentDependencyDrop {
1011 dependency_kind: "cluster",
1012 dependency_id: compute_instance.to_string(),
1013 },
1014 e @ ReadHoldIdMismatch(_) => AdapterError::internal("instance peek error", e),
1015 e @ ReadHoldInsufficient(_) => AdapterError::internal("instance peek error", e),
1016 }
1017 }
1018
1019 pub fn concurrent_dependency_drop_from_collection_update_error(
1020 e: compute_error::CollectionUpdateError,
1021 ) -> Self {
1022 use compute_error::CollectionUpdateError::*;
1023 match e {
1024 InstanceMissing(id) => AdapterError::ConcurrentDependencyDrop {
1025 dependency_kind: "cluster",
1026 dependency_id: id.to_string(),
1027 },
1028 CollectionMissing(id) => AdapterError::ConcurrentDependencyDrop {
1029 dependency_kind: "collection",
1030 dependency_id: id.to_string(),
1031 },
1032 }
1033 }
1034
1035 pub fn concurrent_dependency_drop_from_peek_error(
1036 e: mz_compute_client::controller::error::PeekError,
1037 ) -> AdapterError {
1038 use mz_compute_client::controller::error::PeekError::*;
1039 match e {
1040 InstanceMissing(id) => AdapterError::ConcurrentDependencyDrop {
1041 dependency_kind: "cluster",
1042 dependency_id: id.to_string(),
1043 },
1044 CollectionMissing(id) => AdapterError::ConcurrentDependencyDrop {
1045 dependency_kind: "collection",
1046 dependency_id: id.to_string(),
1047 },
1048 ReplicaMissing(id) => AdapterError::ConcurrentDependencyDrop {
1049 dependency_kind: "replica",
1050 dependency_id: id.to_string(),
1051 },
1052 e @ (ReadHoldIdMismatch(_) | SinceViolation(_)) => {
1053 AdapterError::internal("peek error", e)
1054 }
1055 }
1056 }
1057
1058 pub fn concurrent_dependency_drop_from_dataflow_creation_error(
1059 e: compute_error::DataflowCreationError,
1060 ) -> Self {
1061 use compute_error::DataflowCreationError::*;
1062 match e {
1063 InstanceMissing(id) => AdapterError::ConcurrentDependencyDrop {
1064 dependency_kind: "cluster",
1065 dependency_id: id.to_string(),
1066 },
1067 CollectionMissing(id) => AdapterError::ConcurrentDependencyDrop {
1068 dependency_kind: "collection",
1069 dependency_id: id.to_string(),
1070 },
1071 ReplicaMissing(id) => AdapterError::ConcurrentDependencyDrop {
1072 dependency_kind: "replica",
1073 dependency_id: id.to_string(),
1074 },
1075 MissingAsOf | SinceViolation(..) | EmptyAsOfForSubscribe | EmptyAsOfForCopyTo => {
1076 AdapterError::internal("dataflow creation error", e)
1077 }
1078 }
1079 }
1080}
1081
1082impl fmt::Display for AdapterError {
1083 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1084 match self {
1085 AdapterError::AbsurdSubscribeBounds { as_of, up_to } => {
1086 write!(
1087 f,
1088 "subscription lower bound (`AS OF`) is greater than its upper bound (`UP TO`): \
1089 {as_of} > {up_to}",
1090 )
1091 }
1092 AdapterError::AmbiguousSystemColumnReference => {
1093 write!(
1094 f,
1095 "cannot use wildcard expansions or NATURAL JOINs in a view that depends on \
1096 system objects"
1097 )
1098 }
1099 AdapterError::ChangedPlan(e) => write!(f, "{}", e),
1100 AdapterError::Catalog(e) => e.fmt(f),
1101 AdapterError::DuplicateCursor(name) => {
1102 write!(f, "cursor {} already exists", name.quoted())
1103 }
1104 AdapterError::Eval(e) => e.fmt(f),
1105 AdapterError::Explain(e) => e.fmt(f),
1106 AdapterError::IdExhaustionError => f.write_str("ID allocator exhausted all valid IDs"),
1107 AdapterError::Internal(e) => write!(f, "internal error: {}", e),
1108 AdapterError::IntrospectionDisabled { .. } => write!(
1109 f,
1110 "cannot read log sources of replica with disabled introspection"
1111 ),
1112 AdapterError::InvalidLogDependency { object_type, .. } => {
1113 write!(f, "{object_type} objects cannot depend on log sources")
1114 }
1115 AdapterError::InvalidClusterReplicaAz { az, expected: _ } => {
1116 write!(f, "unknown cluster replica availability zone {az}",)
1117 }
1118 AdapterError::InvalidSetIsolationLevel => write!(
1119 f,
1120 "SET TRANSACTION ISOLATION LEVEL must be called before any query"
1121 ),
1122 AdapterError::InvalidSetCluster => {
1123 write!(f, "SET cluster cannot be called in an active transaction")
1124 }
1125 AdapterError::InvalidStorageClusterSize { size, .. } => {
1126 write!(f, "unknown source size {size}")
1127 }
1128 AdapterError::SourceOrSinkSizeRequired { .. } => {
1129 write!(f, "must specify either cluster or size option")
1130 }
1131 AdapterError::InvalidTableMutationSelection { .. } => {
1132 write!(
1133 f,
1134 "invalid selection: operation may only (transitively) refer to non-source, non-system tables"
1135 )
1136 }
1137 AdapterError::ReplaceMaterializedViewSealed { name } => {
1138 write!(
1139 f,
1140 "materialized view {name} is sealed and thus cannot be replaced"
1141 )
1142 }
1143 AdapterError::ConstraintViolation(not_null_violation) => {
1144 write!(f, "{}", not_null_violation)
1145 }
1146 AdapterError::CopyFormatError(e) => write!(f, "{e}"),
1147 AdapterError::ConcurrentClusterDrop => {
1148 write!(f, "the transaction's active cluster has been dropped")
1149 }
1150 AdapterError::ConcurrentDependencyDrop {
1151 dependency_kind,
1152 dependency_id,
1153 } => {
1154 write!(f, "{dependency_kind} '{dependency_id}' was dropped")
1155 }
1156 AdapterError::CollectionUnreadable { id } => {
1157 write!(f, "collection '{id}' is not readable at any timestamp")
1158 }
1159 AdapterError::NoClusterReplicasAvailable { name, .. } => {
1160 write!(
1161 f,
1162 "CLUSTER {} has no replicas available to service request",
1163 name.quoted()
1164 )
1165 }
1166 AdapterError::OperationProhibitsTransaction(op) => {
1167 write!(f, "{} cannot be run inside a transaction block", op)
1168 }
1169 AdapterError::OperationRequiresTransaction(op) => {
1170 write!(f, "{} can only be used in transaction blocks", op)
1171 }
1172 AdapterError::ParseError(e) => e.fmt(f),
1173 AdapterError::PlanError(e) => e.fmt(f),
1174 AdapterError::PreparedStatementExists(name) => {
1175 write!(f, "prepared statement {} already exists", name.quoted())
1176 }
1177 AdapterError::ReadOnlyTransaction => f.write_str("transaction in read-only mode"),
1178 AdapterError::SingleStatementTransaction => {
1179 f.write_str("this transaction can only execute a single statement")
1180 }
1181 AdapterError::ReadWriteUnavailable => {
1182 f.write_str("transaction read-write mode must be set before any query")
1183 }
1184 AdapterError::WrongSetOfLocks => {
1185 write!(f, "internal error, wrong set of locks acquired")
1186 }
1187 AdapterError::StatementTimeout => {
1188 write!(f, "canceling statement due to statement timeout")
1189 }
1190 AdapterError::Canceled => {
1191 write!(f, "canceling statement due to user request")
1192 }
1193 AdapterError::IdleInTransactionSessionTimeout => {
1194 write!(
1195 f,
1196 "terminating connection due to idle-in-transaction timeout"
1197 )
1198 }
1199 AdapterError::RecursionLimit(e) => e.fmt(f),
1200 AdapterError::RelationOutsideTimeDomain { .. } => {
1201 write!(
1202 f,
1203 "Transactions can only reference objects in the same timedomain. \
1204 See https://materialize.com/docs/sql/begin/#same-timedomain-error",
1205 )
1206 }
1207 AdapterError::ResourceExhaustion {
1208 resource_type,
1209 limit_name,
1210 desired,
1211 limit,
1212 current,
1213 } => {
1214 write!(
1215 f,
1216 "creating {resource_type} would violate {limit_name} limit (desired: {desired}, limit: {limit}, current: {current})"
1217 )
1218 }
1219 AdapterError::ResultSize(e) => write!(f, "{e}"),
1220 AdapterError::SafeModeViolation(feature) => {
1221 write!(f, "cannot create {} in safe mode", feature)
1222 }
1223 AdapterError::SubscribeOnlyTransaction => {
1224 f.write_str("SUBSCRIBE in transactions must be the only read statement")
1225 }
1226 AdapterError::Optimizer(e) => e.fmt(f),
1227 AdapterError::UnallowedOnCluster {
1228 depends_on,
1229 cluster,
1230 } => {
1231 let items = depends_on.into_iter().map(|item| item.quoted()).join(", ");
1232 write!(
1233 f,
1234 "querying the following items {items} is not allowed from the {} cluster",
1235 cluster.quoted()
1236 )
1237 }
1238 AdapterError::Unauthorized(unauthorized) => {
1239 write!(f, "{unauthorized}")
1240 }
1241 AdapterError::UnknownCursor(name) => {
1242 write!(f, "cursor {} does not exist", name.quoted())
1243 }
1244 AdapterError::UnknownLoginRole(name) => {
1245 write!(f, "role {} does not exist", name.quoted())
1246 }
1247 AdapterError::Unsupported(features) => write!(f, "{} are not supported", features),
1248 AdapterError::Unstructured(e) => write!(f, "{}", e.display_with_causes()),
1249 AdapterError::WriteOnlyTransaction => f.write_str("transaction in write-only mode"),
1250 AdapterError::UnknownPreparedStatement(name) => {
1251 write!(f, "prepared statement {} does not exist", name.quoted())
1252 }
1253 AdapterError::UnknownClusterReplica {
1254 cluster_name,
1255 replica_name,
1256 } => write!(
1257 f,
1258 "cluster replica '{cluster_name}.{replica_name}' does not exist"
1259 ),
1260 AdapterError::UnrecognizedConfigurationParam(setting_name) => write!(
1261 f,
1262 "unrecognized configuration parameter {}",
1263 setting_name.quoted()
1264 ),
1265 AdapterError::UntargetedLogRead { .. } => {
1266 f.write_str("log source reads must target a replica")
1267 }
1268 AdapterError::DDLOnlyTransaction => f.write_str(
1269 "transactions which modify objects are restricted to just modifying objects",
1270 ),
1271 AdapterError::DDLTransactionRace => f.write_str(
1272 "another session modified the catalog while this DDL transaction was open",
1273 ),
1274 AdapterError::Storage(e) => e.fmt(f),
1275 AdapterError::Compute(e) => e.fmt(f),
1276 AdapterError::Orchestrator(e) => e.fmt(f),
1277 AdapterError::DependentObject(dependent_objects) => {
1278 let role_str = if dependent_objects.keys().count() == 1 {
1279 "role"
1280 } else {
1281 "roles"
1282 };
1283 write!(
1284 f,
1285 "{role_str} \"{}\" cannot be dropped because some objects depend on it",
1286 dependent_objects.keys().join(", ")
1287 )
1288 }
1289 AdapterError::InvalidAlter(t, e) => {
1290 write!(f, "invalid ALTER {t}: {e}")
1291 }
1292 AdapterError::ConnectionValidation(e) => e.fmt(f),
1293 AdapterError::MaterializedViewWouldNeverRefresh(_, _) => {
1294 write!(
1295 f,
1296 "all the specified refreshes of the materialized view would be too far in the past, and thus they \
1297 would never happen"
1298 )
1299 }
1300 AdapterError::InputNotReadableAtRefreshAtTime(_, _) => {
1301 write!(
1302 f,
1303 "REFRESH AT requested for a time where not all the inputs are readable"
1304 )
1305 }
1306 AdapterError::RtrTimeout(_) => {
1307 write!(
1308 f,
1309 "timed out before ingesting the source's visible frontier when real-time-recency query issued"
1310 )
1311 }
1312 AdapterError::RtrDropFailure(_) => write!(
1313 f,
1314 "real-time source dropped before ingesting the upstream system's visible frontier"
1315 ),
1316 AdapterError::UnreadableSinkCollection => {
1317 write!(f, "collection is not readable at any time")
1318 }
1319 AdapterError::UserSessionsDisallowed => write!(f, "login blocked"),
1320 AdapterError::NetworkPolicyDenied(_) => write!(f, "session denied"),
1321 AdapterError::ReadOnly => write!(f, "cannot write in read-only mode"),
1322 AdapterError::AlterClusterTimeout => {
1323 write!(f, "canceling statement, provided timeout lapsed")
1324 }
1325 AdapterError::AuthenticationError(e) => {
1326 write!(f, "authentication error {e}")
1327 }
1328 AdapterError::UnavailableFeature { feature, docs } => {
1329 write!(f, "{} is not supported in this environment.", feature)?;
1330 if let Some(docs) = docs {
1331 write!(
1332 f,
1333 " For more information consult the documentation at {docs}"
1334 )?;
1335 }
1336 Ok(())
1337 }
1338 AdapterError::AlterClusterWhilePendingReplicas => {
1339 write!(f, "cannot alter clusters with pending updates")
1340 }
1341 AdapterError::ReplacementSchemaMismatch(_) => {
1342 write!(f, "replacement schema differs from target schema")
1343 }
1344 AdapterError::ImpossibleTimestampConstraints { .. } => {
1345 write!(f, "could not find a valid timestamp for the query")
1346 }
1347 AdapterError::OidcGroupSyncFailed(msg) => {
1348 write!(f, "OIDC group-to-role sync failed: {msg}")
1349 }
1350 AdapterError::BoundedStalenessExceeded { bound, .. } => {
1351 write!(
1352 f,
1353 "cannot serve query under bounded staleness {}",
1354 humantime::format_duration(*bound),
1355 )
1356 }
1357 AdapterError::BoundedStalenessReadOnly => {
1358 f.write_str("writes are not permitted under bounded staleness isolation")
1359 }
1360 AdapterError::BoundedStalenessRealTimeRecencyConflict => {
1361 f.write_str("real_time_recency cannot be combined with bounded staleness isolation")
1362 }
1363 AdapterError::BoundedStalenessTimelineUnsupported => {
1364 f.write_str("bounded staleness isolation requires the EpochMilliseconds timeline")
1365 }
1366 }
1367 }
1368}
1369
1370impl From<anyhow::Error> for AdapterError {
1371 fn from(e: anyhow::Error) -> AdapterError {
1372 match e.downcast::<PlanError>() {
1373 Ok(plan_error) => AdapterError::PlanError(plan_error),
1374 Err(e) => AdapterError::Unstructured(e),
1375 }
1376 }
1377}
1378
1379impl From<TryFromIntError> for AdapterError {
1380 fn from(e: TryFromIntError) -> AdapterError {
1381 AdapterError::Unstructured(e.into())
1382 }
1383}
1384
1385impl From<TryFromDecimalError> for AdapterError {
1386 fn from(e: TryFromDecimalError) -> AdapterError {
1387 AdapterError::Unstructured(e.into())
1388 }
1389}
1390
1391impl From<mz_catalog::memory::error::Error> for AdapterError {
1392 fn from(e: mz_catalog::memory::error::Error) -> AdapterError {
1393 AdapterError::Catalog(e)
1394 }
1395}
1396
1397impl From<mz_catalog::durable::CatalogError> for AdapterError {
1398 fn from(e: mz_catalog::durable::CatalogError) -> Self {
1399 mz_catalog::memory::error::Error::from(e).into()
1400 }
1401}
1402
1403impl From<mz_catalog::durable::DurableCatalogError> for AdapterError {
1404 fn from(e: mz_catalog::durable::DurableCatalogError) -> Self {
1405 mz_catalog::durable::CatalogError::from(e).into()
1406 }
1407}
1408
1409impl From<EvalError> for AdapterError {
1410 fn from(e: EvalError) -> AdapterError {
1411 AdapterError::Eval(e)
1412 }
1413}
1414
1415impl From<ExplainError> for AdapterError {
1416 fn from(e: ExplainError) -> AdapterError {
1417 match e {
1418 ExplainError::RecursionLimitError(e) => AdapterError::RecursionLimit(e),
1419 e => AdapterError::Explain(e),
1420 }
1421 }
1422}
1423
1424impl From<mz_sql::catalog::CatalogError> for AdapterError {
1425 fn from(e: mz_sql::catalog::CatalogError) -> AdapterError {
1426 AdapterError::Catalog(mz_catalog::memory::error::Error::from(e))
1427 }
1428}
1429
1430impl From<PlanError> for AdapterError {
1431 fn from(e: PlanError) -> AdapterError {
1432 match e {
1433 PlanError::UnknownCursor(name) => AdapterError::UnknownCursor(name),
1434 _ => AdapterError::PlanError(e),
1435 }
1436 }
1437}
1438
1439impl From<OptimizerError> for AdapterError {
1440 fn from(e: OptimizerError) -> AdapterError {
1441 use OptimizerError::*;
1442 match e {
1443 PlanError(e) => Self::PlanError(e),
1444 RecursionLimitError(e) => Self::RecursionLimit(e),
1445 EvalError(e) => Self::Eval(e),
1446 InternalUnsafeMfpPlan(e) => Self::Internal(e),
1447 Internal(e) => Self::Internal(e),
1448 RestrictedFunction(func) => {
1449 Self::Unauthorized(mz_sql::rbac::UnauthorizedError::RestrictedSystemObject {
1450 object_name: format!("function {func}"),
1451 })
1452 }
1453 e => Self::Optimizer(e),
1454 }
1455 }
1456}
1457
1458impl From<NotNullViolation> for AdapterError {
1459 fn from(e: NotNullViolation) -> AdapterError {
1460 AdapterError::ConstraintViolation(e)
1461 }
1462}
1463
1464impl From<RecursionLimitError> for AdapterError {
1465 fn from(e: RecursionLimitError) -> AdapterError {
1466 AdapterError::RecursionLimit(e)
1467 }
1468}
1469
1470impl From<oneshot::error::RecvError> for AdapterError {
1471 fn from(e: oneshot::error::RecvError) -> AdapterError {
1472 AdapterError::Unstructured(e.into())
1473 }
1474}
1475
1476impl From<StorageError> for AdapterError {
1477 fn from(e: StorageError) -> Self {
1478 AdapterError::Storage(e)
1479 }
1480}
1481
1482impl From<compute_error::InstanceExists> for AdapterError {
1483 fn from(e: compute_error::InstanceExists) -> Self {
1484 AdapterError::Compute(e.into())
1485 }
1486}
1487
1488impl From<TimestampError> for AdapterError {
1489 fn from(e: TimestampError) -> Self {
1490 let e: EvalError = e.into();
1491 e.into()
1492 }
1493}
1494
1495impl From<mz_sql_parser::parser::ParserStatementError> for AdapterError {
1496 fn from(e: mz_sql_parser::parser::ParserStatementError) -> Self {
1497 AdapterError::ParseError(e)
1498 }
1499}
1500
1501impl From<VarError> for AdapterError {
1502 fn from(e: VarError) -> Self {
1503 let e: mz_catalog::memory::error::Error = e.into();
1504 e.into()
1505 }
1506}
1507
1508impl From<rbac::UnauthorizedError> for AdapterError {
1509 fn from(e: rbac::UnauthorizedError) -> Self {
1510 AdapterError::Unauthorized(e)
1511 }
1512}
1513
1514impl From<mz_sql_parser::ast::IdentError> for AdapterError {
1515 fn from(value: mz_sql_parser::ast::IdentError) -> Self {
1516 AdapterError::PlanError(PlanError::InvalidIdent(value))
1517 }
1518}
1519
1520impl From<mz_pgwire_common::ConnectionError> for AdapterError {
1521 fn from(value: mz_pgwire_common::ConnectionError) -> Self {
1522 match value {
1523 mz_pgwire_common::ConnectionError::TooManyConnections { current, limit } => {
1524 AdapterError::ResourceExhaustion {
1525 resource_type: "connection".into(),
1526 limit_name: "max_connections".into(),
1527 desired: (current + 1).to_string(),
1528 limit: limit.to_string(),
1529 current: current.to_string(),
1530 }
1531 }
1532 }
1533 }
1534}
1535
1536impl From<NetworkPolicyError> for AdapterError {
1537 fn from(value: NetworkPolicyError) -> Self {
1538 AdapterError::NetworkPolicyDenied(value)
1539 }
1540}
1541
1542impl From<ConnectionValidationError> for AdapterError {
1543 fn from(e: ConnectionValidationError) -> AdapterError {
1544 AdapterError::ConnectionValidation(e)
1545 }
1546}
1547
1548impl Error for AdapterError {}