1use std::fmt;
16use std::time::Duration;
17
18use reqwest::StatusCode;
19use uuid::Uuid;
20
21use crate::protocol::AppendErrorDetails;
22use crate::protocol::AppendState;
23use crate::protocol::StatementErrorDetails;
24
25#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
27#[non_exhaustive]
28pub enum ErrorKind {
29 Unexpected,
32
33 ConfigInvalid,
35
36 AppendRowsFailed,
38
39 StatementFailed,
41
42 StatementCancelled,
44
45 CatalogFailed,
47}
48
49#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
51#[serde(rename_all = "snake_case")]
52#[non_exhaustive]
53pub enum WriteErrorReason {
54 Timeout,
56}
57
58impl fmt::Display for WriteErrorReason {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 f.write_str(match self {
61 Self::Timeout => "timeout",
62 })
63 }
64}
65
66#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
69#[non_exhaustive]
70pub struct WriteErrorDetails {
71 pub reason: WriteErrorReason,
72 pub outcome: AppendState,
73}
74
75impl ErrorKind {
76 pub fn into_static(self) -> &'static str {
78 self.into()
79 }
80}
81
82impl fmt::Display for ErrorKind {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 write!(f, "{}", self.into_static())
85 }
86}
87
88impl From<ErrorKind> for &'static str {
89 fn from(v: ErrorKind) -> &'static str {
90 match v {
91 ErrorKind::Unexpected => "Unexpected",
92 ErrorKind::ConfigInvalid => "ConfigInvalid",
93 ErrorKind::AppendRowsFailed => "AppendRowsFailed",
94 ErrorKind::StatementFailed => "StatementFailed",
95 ErrorKind::StatementCancelled => "StatementCancelled",
96 ErrorKind::CatalogFailed => "CatalogFailed",
97 }
98 }
99}
100
101#[derive(Clone, Copy, Debug, PartialEq, Eq)]
102enum ErrorStatus {
103 Permanent,
109 Temporary,
115 Persistent,
122}
123
124#[derive(Debug, Default, Clone)]
125struct HttpErrorMetadata {
126 status: Option<StatusCode>,
127 request_id: Option<String>,
128 retry_after: Option<Duration>,
129 retryable: Option<bool>,
130}
131
132#[derive(Debug, Clone)]
133struct ApiErrorDetails {
134 code: Option<String>,
135 details: Option<serde_json::Value>,
136}
137
138#[derive(Debug, Default, Clone)]
139struct StatementErrorMetadata {
140 id: Option<Uuid>,
141 details: Option<StatementErrorDetails>,
142}
143
144impl fmt::Display for ErrorStatus {
145 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146 match self {
147 ErrorStatus::Permanent => write!(f, "permanent"),
148 ErrorStatus::Temporary => write!(f, "temporary"),
149 ErrorStatus::Persistent => write!(f, "persistent"),
150 }
151 }
152}
153
154#[derive(Clone)]
166pub struct Error {
167 kind: ErrorKind,
168 message: String,
169
170 status: ErrorStatus,
171 context: Vec<(&'static str, String)>,
172 api_error: Option<Box<ApiErrorDetails>>,
173 append_details: Option<AppendErrorDetails>,
174 write_details: Option<WriteErrorDetails>,
175 statement_metadata: Option<Box<StatementErrorMetadata>>,
176 http_metadata: Option<Box<HttpErrorMetadata>>,
177
178 source: Option<std::sync::Arc<anyhow::Error>>,
179}
180
181impl fmt::Display for Error {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 write!(f, "{} ({})", self.kind, self.status)?;
184
185 if !self.context.is_empty() {
186 write!(f, ", context: {{ ")?;
187 write!(
188 f,
189 "{}",
190 self.context
191 .iter()
192 .map(|(k, v)| format!("{k}: {v}"))
193 .collect::<Vec<_>>()
194 .join(", ")
195 )?;
196 write!(f, " }}")?;
197 }
198
199 if !self.message.is_empty() {
200 write!(f, " => {}", self.message)?;
201 }
202
203 if let Some(code) = self.code() {
204 write!(f, ", code: {code}")?;
205 }
206 if let Some(id) = self.statement_id() {
207 write!(f, ", statement_id: {id}")?;
208 }
209 if let Some(status) = self.http_status() {
210 write!(f, ", http_status: {}", status.as_u16())?;
211 }
212 if let Some(request_id) = self.request_id() {
213 write!(f, ", request_id: {request_id}")?;
214 }
215 if let Some(retry_after) = self.retry_after() {
216 write!(f, ", retry_after: {retry_after:?}")?;
217 }
218
219 if let Some(details) = self.write_details() {
220 write!(
221 f,
222 ", write_reason: {}, write_outcome: {}",
223 details.reason, details.outcome
224 )?;
225 }
226
227 if let Some(source) = &self.source {
228 write!(f, ", source: {source}")?;
229 }
230
231 Ok(())
232 }
233}
234
235impl fmt::Debug for Error {
236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237 if f.alternate() {
239 let mut de = f.debug_struct("Error");
240 de.field("kind", &self.kind);
241 de.field("message", &self.message);
242 de.field("api_error", &self.api_error);
243 de.field("status", &self.status);
244 de.field("context", &self.context);
245 de.field("append_details", &self.append_details);
246 de.field("write_details", &self.write_details);
247 de.field("statement_id", &self.statement_id());
248 de.field("statement_details", &self.statement_details());
249 de.field("http_metadata", &self.http_metadata);
250 de.field("source", &self.source);
251 return de.finish();
252 }
253
254 write!(f, "{} ({})", self.kind, self.status)?;
255 if !self.message.is_empty() {
256 write!(f, " => {}", self.message)?;
257 }
258 if let Some(code) = self.code() {
259 write!(f, ", code: {code}")?;
260 }
261 if let Some(id) = self.statement_id() {
262 write!(f, ", statement_id: {id}")?;
263 }
264 if let Some(status) = self.http_status() {
265 write!(f, ", http_status: {}", status.as_u16())?;
266 }
267 if let Some(request_id) = self.request_id() {
268 write!(f, ", request_id: {request_id}")?;
269 }
270 if let Some(retry_after) = self.retry_after() {
271 write!(f, ", retry_after: {retry_after:?}")?;
272 }
273 if let Some(details) = self.write_details() {
274 write!(
275 f,
276 ", write_reason: {}, write_outcome: {}",
277 details.reason, details.outcome
278 )?;
279 }
280 writeln!(f)?;
281
282 if !self.context.is_empty() {
283 writeln!(f)?;
284 writeln!(f, "Context:")?;
285 for (k, v) in self.context.iter() {
286 writeln!(f, " {k}: {v}")?;
287 }
288 }
289 if let Some(source) = &self.source {
290 writeln!(f)?;
291 writeln!(f, "Source:")?;
292 writeln!(f, " {source:#}")?;
293 }
294
295 Ok(())
296 }
297}
298
299impl std::error::Error for Error {
300 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
301 self.source.as_ref().map(|v| v.as_ref().as_ref())
302 }
303}
304
305impl Error {
306 pub fn new(kind: ErrorKind, message: impl Into<String>) -> Self {
308 Self {
309 kind,
310 message: message.into(),
311
312 status: ErrorStatus::Permanent,
313 context: Vec::default(),
314 api_error: None,
315 append_details: None,
316 write_details: None,
317 statement_metadata: None,
318 http_metadata: None,
319 source: None,
320 }
321 }
322
323 pub fn with_context(mut self, key: &'static str, value: impl ToString) -> Self {
325 self.context.push((key, value.to_string()));
326 self
327 }
328
329 pub fn set_source(mut self, src: impl Into<anyhow::Error>) -> Self {
335 debug_assert!(self.source.is_none(), "the source error has been set");
336
337 self.source = Some(std::sync::Arc::new(src.into()));
338 self
339 }
340
341 pub(crate) fn set_write_timeout(mut self) -> Self {
342 self.write_details = Some(WriteErrorDetails {
343 reason: WriteErrorReason::Timeout,
344 outcome: AppendState::Unknown,
345 });
346 self
347 }
348
349 pub fn write_details(&self) -> Option<&WriteErrorDetails> {
352 self.write_details.as_ref()
353 }
354
355 pub fn append_details(&self) -> Option<&AppendErrorDetails> {
357 self.append_details.as_ref()
358 }
359
360 pub(crate) fn set_append_details(mut self, details: AppendErrorDetails) -> Self {
361 self.append_details = Some(details);
362 self
363 }
364
365 pub fn statement_details(&self) -> Option<&StatementErrorDetails> {
367 self.statement_metadata
368 .as_ref()
369 .and_then(|m| m.details.as_ref())
370 }
371
372 pub(crate) fn set_statement_details(mut self, details: StatementErrorDetails) -> Self {
373 self.statement_metadata
374 .get_or_insert_with(Default::default)
375 .details = Some(details);
376 self
377 }
378
379 pub fn statement_id(&self) -> Option<Uuid> {
383 self.statement_metadata.as_ref().and_then(|m| m.id)
384 }
385
386 pub(crate) fn set_statement_id(mut self, id: Uuid) -> Self {
387 self.statement_metadata
388 .get_or_insert_with(Default::default)
389 .id = Some(id);
390 self
391 }
392
393 pub(crate) fn set_http_status(mut self, status: StatusCode) -> Self {
394 self.http_metadata_mut().status = Some(status);
395 self
396 }
397
398 pub(crate) fn set_request_id(mut self, request_id: String) -> Self {
399 self.http_metadata_mut().request_id = Some(request_id);
400 self
401 }
402
403 pub(crate) fn set_retry_after(mut self, retry_after: Duration) -> Self {
404 self.http_metadata_mut().retry_after = Some(retry_after);
405 self
406 }
407
408 pub(crate) fn set_server_retryable(mut self, retryable: Option<bool>) -> Self {
409 self.http_metadata_mut().retryable = retryable;
410 self
411 }
412
413 pub(crate) fn server_retryable(&self) -> Option<bool> {
414 self.http_metadata
415 .as_ref()
416 .and_then(|metadata| metadata.retryable)
417 }
418
419 fn http_metadata_mut(&mut self) -> &mut HttpErrorMetadata {
420 self.http_metadata
421 .get_or_insert_with(|| Box::new(HttpErrorMetadata::default()))
422 }
423
424 pub fn set_permanent(mut self) -> Self {
426 self.status = ErrorStatus::Permanent;
427 self
428 }
429
430 pub fn set_temporary(mut self) -> Self {
434 self.status = ErrorStatus::Temporary;
435 self
436 }
437
438 pub fn set_persistent(mut self) -> Self {
442 self.status = ErrorStatus::Persistent;
443 self
444 }
445
446 pub fn kind(&self) -> ErrorKind {
448 self.kind
449 }
450
451 pub fn code(&self) -> Option<&str> {
453 self.api_error
454 .as_deref()
455 .and_then(|e| e.code.as_deref())
456 .or_else(|| self.statement_details().map(|e| e.code.as_str()))
457 }
458
459 pub fn details(&self) -> Option<&serde_json::Value> {
461 self.api_error
462 .as_deref()
463 .and_then(|e| e.details.as_ref())
464 .or_else(|| self.statement_details().and_then(|e| e.details.as_ref()))
465 }
466
467 pub(crate) fn set_api_error(
468 mut self,
469 code: Option<String>,
470 details: Option<serde_json::Value>,
471 ) -> Self {
472 if code.is_some() || details.is_some() {
473 self.api_error = Some(Box::new(ApiErrorDetails { code, details }));
474 }
475 self
476 }
477
478 pub fn message(&self) -> &str {
480 &self.message
481 }
482
483 pub fn http_status(&self) -> Option<StatusCode> {
485 self.http_metadata
486 .as_ref()
487 .and_then(|metadata| metadata.status)
488 }
489
490 pub fn request_id(&self) -> Option<&str> {
492 self.http_metadata
493 .as_ref()
494 .and_then(|metadata| metadata.request_id.as_deref())
495 }
496
497 pub fn retry_after(&self) -> Option<Duration> {
499 self.http_metadata
500 .as_ref()
501 .and_then(|metadata| metadata.retry_after)
502 }
503
504 pub fn is_retryable(&self) -> bool {
508 self.is_temporary()
509 }
510
511 pub fn is_temporary(&self) -> bool {
513 self.status == ErrorStatus::Temporary
514 }
515
516 pub fn is_permanent(&self) -> bool {
518 self.status == ErrorStatus::Permanent
519 }
520
521 pub fn is_persistent(&self) -> bool {
523 self.status == ErrorStatus::Persistent
524 }
525}