1use crate::to_rust_str;
17use crate::AssertSend;
18use crate::AssertSync;
19use crate::Context;
20#[cfg(doc)]
21use crate::{Batch, BatchBuilder, Connection, Statement};
22use odpic_sys::*;
23use std::borrow::Cow;
24use std::error;
25use std::ffi::CStr;
26use std::fmt;
27#[cfg(feature = "struct_error")]
28use std::fmt::Display;
29use std::mem::MaybeUninit;
30use std::num;
31use std::str;
32use std::sync;
33
34pub(crate) const DPI_ERR_NOT_CONNECTED: i32 = 1010;
36
37pub(crate) const DPI_ERR_BUFFER_SIZE_TOO_SMALL: i32 = 1019;
39
40#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
41#[non_exhaustive]
42pub enum ErrorKind {
48 OciError,
50
51 DpiError,
53
54 NullValue,
57
58 ParseError,
60
61 OutOfRange,
63
64 InvalidArgument,
66
67 InvalidTypeConversion,
69
70 InvalidBindIndex,
72
73 InvalidBindName,
75
76 InvalidColumnIndex,
78
79 InvalidColumnName,
81
82 InvalidAttributeName,
84
85 InvalidOperation,
87
88 UninitializedBindValue,
92
93 NoDataFound,
95
96 BatchErrors,
100
101 InternalError,
103
104 Other,
108}
109
110#[derive(Debug)]
112#[cfg(feature = "struct_error")]
113pub struct Error {
114 kind: ErrorKind,
115 message: Cow<'static, str>,
116 dberr: Option<Box<DbError>>,
119 batch_errors: Option<Vec<DbError>>,
120 source: Option<Box<dyn error::Error + Send + Sync>>,
121}
122
123#[non_exhaustive]
127#[derive(Debug)]
128#[cfg(not(feature = "struct_error"))]
129pub enum Error {
130 #[deprecated(note = "Use kind() to check the error category. Use db_error() to get DbError.")]
132 OciError(DbError),
133
134 #[deprecated(note = "Use kind() to check the error category. Use db_error() to get DbError.")]
136 DpiError(DbError),
137
138 #[deprecated(note = "Use kind() to check the error category.")]
141 NullValue,
142
143 #[deprecated(
145 note = "Use kind() to check the error category. Use source() to get the underlying error."
146 )]
147 ParseError(Box<dyn error::Error + Send + Sync>),
148
149 #[deprecated(
151 note = "Use kind() to check the error category. Use to_string() to get the message."
152 )]
153 OutOfRange(String),
154
155 #[deprecated(note = "Use kind() to check the error category.")]
157 InvalidTypeConversion(String, String),
158
159 #[deprecated]
161 InvalidArgument {
162 message: Cow<'static, str>,
163 source: Option<Box<dyn error::Error + Send + Sync>>,
164 },
165
166 #[deprecated(note = "Use kind() to check the error category.")]
168 InvalidBindIndex(usize),
169
170 #[deprecated(note = "Use kind() to check the error category.")]
172 InvalidBindName(String),
173
174 #[deprecated(note = "Use kind() to check the error category.")]
176 InvalidColumnIndex(usize),
177
178 #[deprecated(note = "Use kind() to check the error category.")]
180 InvalidColumnName(String),
181
182 #[deprecated(note = "Use kind() to check the error category.")]
184 InvalidAttributeName(String),
185
186 #[deprecated(
188 note = "Use kind() to check the error category. Use to_string() to get the message."
189 )]
190 InvalidOperation(String),
191
192 #[deprecated(note = "Use kind() to check the error category.")]
196 UninitializedBindValue,
197
198 #[deprecated(note = "Use kind() to check the error category.")]
200 NoDataFound,
201
202 #[deprecated(
203 note = "Use kind() to check the error category. Use batch_errors() to get the db errors."
204 )]
205 BatchErrors(Vec<DbError>),
206
207 #[deprecated(
209 note = "Use kind() to check the error category. Use to_string() to get the message."
210 )]
211 InternalError(String),
212
213 #[non_exhaustive]
217 Other {
218 kind: ErrorKind,
219 message: Cow<'static, str>,
220 source: Option<Box<dyn error::Error + Send + Sync>>,
221 },
222}
223
224impl Error {
225 pub(crate) fn from_context(ctxt: &Context) -> Error {
226 let err = unsafe {
227 let mut err = MaybeUninit::uninit();
228 dpiContext_getError(ctxt.context, err.as_mut_ptr());
229 err.assume_init()
230 };
231 Error::from_dpi_error(&err)
232 }
233
234 pub(crate) fn from_dpi_error(err: &dpiErrorInfo) -> Error {
235 Error::from_db_error(DbError::from_dpi_error(err))
236 }
237}
238
239#[cfg(feature = "struct_error")]
240impl Error {
241 pub fn new<M>(kind: ErrorKind, message: M) -> Error
243 where
244 M: Into<Cow<'static, str>>,
245 {
246 Error {
247 kind,
248 message: message.into(),
249 dberr: None,
250 batch_errors: None,
251 source: None,
252 }
253 }
254
255 pub(crate) fn add_dberr(self, dberr: DbError) -> Error {
256 Error {
257 dberr: Some(Box::new(dberr)),
258 ..self
259 }
260 }
261
262 pub(crate) fn add_batch_errors(self, batch_errors: Vec<DbError>) -> Error {
263 Error {
264 batch_errors: Some(batch_errors),
265 ..self
266 }
267 }
268
269 pub fn add_source<E>(self, source: E) -> Error
276 where
277 E: Into<Box<dyn error::Error + Send + Sync>>,
278 {
279 Error {
280 source: Some(source.into()),
281 ..self
282 }
283 }
284
285 pub fn with_source<E>(kind: ErrorKind, source: E) -> Error
291 where
292 E: Into<Box<dyn error::Error + Send + Sync>>,
293 {
294 Error::new(kind, "").add_source(source)
295 }
296
297 pub(crate) fn from_db_error(dberr: DbError) -> Error {
298 let (kind, message_prefix) = if dberr.message().starts_with("DPI") {
299 (ErrorKind::DpiError, "DPI")
300 } else {
301 (ErrorKind::OciError, "OCI")
302 };
303 Error::new(kind, format!("{} Error: {}", message_prefix, dberr.message)).add_dberr(dberr)
304 }
305
306 pub fn kind(&self) -> ErrorKind {
307 self.kind
308 }
309
310 pub fn db_error(&self) -> Option<&DbError> {
312 self.dberr.as_ref().map(|b| b.as_ref())
313 }
314
315 pub fn batch_errors(&self) -> Option<&Vec<DbError>> {
318 self.batch_errors.as_ref()
319 }
320
321 pub fn oci_code(&self) -> Option<i32> {
324 match (self.kind, &self.dberr) {
325 (ErrorKind::OciError, Some(dberr)) if dberr.code != 0 => Some(dberr.code),
326 _ => None,
327 }
328 }
329
330 pub fn dpi_code(&self) -> Option<i32> {
332 match (self.kind, &self.dberr) {
333 (ErrorKind::DpiError, Some(dberr)) => dpi_error_in_message(&dberr.message),
334 _ => None,
335 }
336 }
337
338 pub fn into_source(self) -> Option<Box<dyn error::Error + Send + Sync>> {
340 self.source
341 }
342
343 pub(crate) fn oci_error(dberr: DbError) -> Error {
344 Error::new(ErrorKind::OciError, format!("OCI Error: {}", dberr.message)).add_dberr(dberr)
345 }
346
347 pub(crate) fn null_value() -> Error {
348 Error::new(ErrorKind::NullValue, "NULL value found")
349 }
350
351 pub(crate) fn parse_error<T>(source: T) -> Error
352 where
353 T: Into<Box<dyn error::Error + Send + Sync>>,
354 {
355 let source = source.into();
356 Error::new(ErrorKind::ParseError, "").add_source(source)
357 }
358
359 pub(crate) fn out_of_range<T>(message: T) -> Error
360 where
361 T: Into<Cow<'static, str>>,
362 {
363 Error::new(ErrorKind::OutOfRange, message.into())
364 }
365
366 pub(crate) fn invalid_type_conversion<T1, T2>(from: T1, to: T2) -> Error
367 where
368 T1: Display,
369 T2: Display,
370 {
371 Error::new(
372 ErrorKind::InvalidTypeConversion,
373 format!("invalid type conversion from {} to {}", from, to),
374 )
375 }
376
377 pub(crate) fn invalid_bind_index<T>(index: T) -> Error
378 where
379 T: Display,
380 {
381 Error::new(
382 ErrorKind::InvalidBindIndex,
383 format!("invalid bind index {} (one-based)", index),
384 )
385 }
386
387 pub(crate) fn invalid_bind_name<T>(name: T) -> Error
388 where
389 T: Display,
390 {
391 Error::new(
392 ErrorKind::InvalidBindName,
393 format!("invalid bind name {}", name),
394 )
395 }
396
397 pub(crate) fn invalid_column_index<T>(index: T) -> Error
398 where
399 T: Display,
400 {
401 Error::new(
402 ErrorKind::InvalidColumnIndex,
403 format!("invalid column index {} (zero-based)", index),
404 )
405 }
406
407 pub(crate) fn invalid_column_name<T>(name: T) -> Error
408 where
409 T: Display,
410 {
411 Error::new(
412 ErrorKind::InvalidColumnName,
413 format!("invalid column name {}", name),
414 )
415 }
416
417 pub(crate) fn invalid_attribute_name<T>(name: T) -> Error
418 where
419 T: Display,
420 {
421 Error::new(
422 ErrorKind::InvalidAttributeName,
423 format!("invalid attribute name {}", name),
424 )
425 }
426
427 pub(crate) fn invalid_operation<T>(message: T) -> Error
428 where
429 T: Into<Cow<'static, str>>,
430 {
431 Error::new(ErrorKind::InvalidOperation, message.into())
432 }
433
434 pub(crate) fn uninitialized_bind_value() -> Error {
435 Error::new(
436 ErrorKind::UninitializedBindValue,
437 "try to access uninitialized bind value",
438 )
439 }
440
441 pub(crate) fn no_data_found() -> Error {
442 Error::new(ErrorKind::NoDataFound, "no data found")
443 }
444
445 pub(crate) fn make_batch_errors(batch_errors: Vec<DbError>) -> Error {
446 Error::new(
447 ErrorKind::BatchErrors,
448 format!("batch error containing {} error(s)", batch_errors.len()),
449 )
450 .add_batch_errors(batch_errors)
451 }
452
453 pub(crate) fn internal_error<T>(message: T) -> Error
454 where
455 T: Into<Cow<'static, str>>,
456 {
457 Error::new(ErrorKind::InternalError, message.into())
458 }
459
460 pub(crate) fn invalid_argument<M>(message: M) -> Error
461 where
462 M: Into<Cow<'static, str>>,
463 {
464 Error::new(ErrorKind::InvalidArgument, message.into())
465 }
466}
467
468#[allow(deprecated)]
469#[cfg(not(feature = "struct_error"))]
470impl Error {
471 pub fn new<M>(kind: ErrorKind, message: M) -> Error
473 where
474 M: Into<Cow<'static, str>>,
475 {
476 Error::Other {
477 kind,
478 message: message.into(),
479 source: None,
480 }
481 }
482
483 pub(crate) fn from_db_error(dberr: DbError) -> Error {
484 if dberr.message().starts_with("DPI") {
485 Error::DpiError(dberr)
486 } else {
487 Error::OciError(dberr)
488 }
489 }
490
491 pub fn add_source<E>(self, source: E) -> Error
498 where
499 E: Into<Box<dyn error::Error + Send + Sync>>,
500 {
501 match self {
502 Error::InvalidArgument { message, .. } => Error::InvalidArgument {
503 message,
504 source: Some(source.into()),
505 },
506 Error::Other { kind, message, .. } => Error::Other {
507 kind,
508 message,
509 source: Some(source.into()),
510 },
511 _ => self,
512 }
513 }
514
515 pub fn with_source<E>(kind: ErrorKind, source: E) -> Error
521 where
522 E: Into<Box<dyn error::Error + Send + Sync>>,
523 {
524 Error::new(kind, "").add_source(source)
525 }
526
527 pub fn kind(&self) -> ErrorKind {
529 match self {
530 Error::OciError(_) => ErrorKind::OciError,
531 Error::DpiError(_) => ErrorKind::DpiError,
532 Error::NullValue => ErrorKind::NullValue,
533 Error::ParseError(_) => ErrorKind::ParseError,
534 Error::OutOfRange(_) => ErrorKind::OutOfRange,
535 Error::InvalidArgument { .. } => ErrorKind::InvalidArgument,
536 Error::InvalidTypeConversion(_, _) => ErrorKind::InvalidTypeConversion,
537 Error::InvalidBindIndex(_) => ErrorKind::InvalidBindIndex,
538 Error::InvalidBindName(_) => ErrorKind::InvalidBindName,
539 Error::InvalidColumnIndex(_) => ErrorKind::InvalidColumnIndex,
540 Error::InvalidColumnName(_) => ErrorKind::InvalidColumnName,
541 Error::InvalidAttributeName(_) => ErrorKind::InvalidAttributeName,
542 Error::InvalidOperation(_) => ErrorKind::InvalidOperation,
543 Error::UninitializedBindValue => ErrorKind::UninitializedBindValue,
544 Error::NoDataFound => ErrorKind::NoDataFound,
545 Error::BatchErrors(_) => ErrorKind::BatchErrors,
546 Error::InternalError(_) => ErrorKind::InternalError,
547 Error::Other { kind, .. } => *kind,
548 }
549 }
550
551 pub fn db_error(&self) -> Option<&DbError> {
553 match self {
554 Error::OciError(err) | Error::DpiError(err) => Some(err),
555 _ => None,
556 }
557 }
558
559 pub fn batch_errors(&self) -> Option<&Vec<DbError>> {
562 match self {
563 Error::BatchErrors(errs) => Some(errs),
564 _ => None,
565 }
566 }
567
568 pub fn oci_code(&self) -> Option<i32> {
571 if let Error::OciError(dberr) = &self {
572 if dberr.code != 0 {
573 Some(dberr.code)
574 } else {
575 None
576 }
577 } else {
578 None
579 }
580 }
581
582 pub fn dpi_code(&self) -> Option<i32> {
584 if let Error::DpiError(dberr) = &self {
585 dpi_error_in_message(&dberr.message)
586 } else {
587 None
588 }
589 }
590
591 pub fn into_source(self) -> Option<Box<dyn error::Error + Send + Sync>> {
593 match self {
594 Error::ParseError(err) => Some(err),
595 Error::InvalidArgument { source, .. } => source,
596 Error::Other { source, .. } => source,
597 _ => None,
598 }
599 }
600
601 pub(crate) fn oci_error(dberr: DbError) -> Error {
602 Error::OciError(dberr)
603 }
604
605 pub(crate) fn null_value() -> Error {
606 Error::NullValue
607 }
608
609 pub(crate) fn parse_error<T>(source: T) -> Error
610 where
611 T: Into<Box<dyn error::Error + Send + Sync>>,
612 {
613 Error::ParseError(source.into())
614 }
615
616 pub(crate) fn out_of_range<T>(message: T) -> Error
617 where
618 T: Into<String>,
619 {
620 Error::OutOfRange(message.into())
621 }
622
623 pub(crate) fn invalid_type_conversion<T1, T2>(from: T1, to: T2) -> Error
624 where
625 T1: Into<String>,
626 T2: Into<String>,
627 {
628 Error::InvalidTypeConversion(from.into(), to.into())
629 }
630
631 pub(crate) fn invalid_bind_index(index: usize) -> Error {
632 Error::InvalidBindIndex(index)
633 }
634
635 pub(crate) fn invalid_bind_name<T>(name: T) -> Error
636 where
637 T: Into<String>,
638 {
639 Error::InvalidBindName(name.into())
640 }
641
642 pub(crate) fn invalid_column_index(index: usize) -> Error {
643 Error::InvalidColumnIndex(index)
644 }
645
646 pub(crate) fn invalid_column_name<T>(name: T) -> Error
647 where
648 T: Into<String>,
649 {
650 Error::InvalidColumnName(name.into())
651 }
652
653 pub(crate) fn invalid_attribute_name<T>(name: T) -> Error
654 where
655 T: Into<String>,
656 {
657 Error::InvalidAttributeName(name.into())
658 }
659
660 pub(crate) fn invalid_operation<T>(message: T) -> Error
661 where
662 T: Into<String>,
663 {
664 Error::InvalidOperation(message.into())
665 }
666
667 pub(crate) fn uninitialized_bind_value() -> Error {
668 Error::UninitializedBindValue
669 }
670
671 pub(crate) fn no_data_found() -> Error {
672 Error::NoDataFound
673 }
674
675 pub(crate) fn make_batch_errors(errs: Vec<DbError>) -> Error {
676 Error::BatchErrors(errs)
677 }
678
679 pub(crate) fn internal_error<T>(message: T) -> Error
680 where
681 T: Into<String>,
682 {
683 Error::InternalError(message.into())
684 }
685
686 pub(crate) fn invalid_argument<M>(message: M) -> Error
687 where
688 M: Into<Cow<'static, str>>,
689 {
690 Error::InvalidArgument {
691 message: message.into(),
692 source: None,
693 }
694 }
695}
696
697impl AssertSend for Error {}
698impl AssertSync for Error {}
699
700#[derive(Eq, PartialEq, Clone)]
703pub struct ParseOracleTypeError {
704 typename: &'static str,
705}
706
707impl ParseOracleTypeError {
708 pub fn new(typename: &'static str) -> ParseOracleTypeError {
709 ParseOracleTypeError { typename }
710 }
711}
712
713impl fmt::Display for ParseOracleTypeError {
714 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
715 write!(f, "{} parse error", self.typename)
716 }
717}
718
719impl fmt::Debug for ParseOracleTypeError {
720 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
721 write!(f, "ParseOracleTypeError")
722 }
723}
724
725impl error::Error for ParseOracleTypeError {
726 fn description(&self) -> &str {
727 "Oracle type parse error"
728 }
729
730 fn cause(&self) -> Option<&dyn error::Error> {
731 None
732 }
733}
734
735#[derive(Debug, Eq, PartialEq, Clone)]
737pub struct DbError {
738 code: i32,
739 offset: u32,
740 message: String,
741 fn_name: Cow<'static, str>,
742 action: Cow<'static, str>,
743 is_recoverable: bool,
744 is_warning: bool,
745}
746
747impl DbError {
748 pub(crate) fn from_dpi_error(err: &dpiErrorInfo) -> DbError {
749 DbError {
750 code: err.code,
751 offset: err.offset,
752 message: to_rust_str(err.message, err.messageLength),
753 fn_name: unsafe { CStr::from_ptr(err.fnName) }.to_string_lossy(),
754 action: unsafe { CStr::from_ptr(err.action) }.to_string_lossy(),
755 is_recoverable: err.isRecoverable != 0,
756 is_warning: err.isWarning != 0,
757 }
758 }
759
760 pub(crate) fn to_warning(ctxt: &Context) -> Option<DbError> {
761 let err = unsafe {
762 let mut err = MaybeUninit::uninit();
763 dpiContext_getError(ctxt.context, err.as_mut_ptr());
764 err.assume_init()
765 };
766 if err.isWarning != 0 {
767 Some(DbError::from_dpi_error(&err))
768 } else {
769 None
770 }
771 }
772
773 pub fn new<M, F, A>(code: i32, offset: u32, message: M, fn_name: F, action: A) -> DbError
775 where
776 M: Into<String>,
777 F: Into<Cow<'static, str>>,
778 A: Into<Cow<'static, str>>,
779 {
780 DbError {
781 code,
782 offset,
783 message: message.into(),
784 fn_name: fn_name.into(),
785 action: action.into(),
786 is_recoverable: false,
787 is_warning: false,
788 }
789 }
790
791 pub fn code(&self) -> i32 {
793 self.code
794 }
795
796 pub fn offset(&self) -> u32 {
798 self.offset
799 }
800
801 pub fn message(&self) -> &str {
803 &self.message
804 }
805
806 pub fn fn_name(&self) -> &str {
808 &self.fn_name
809 }
810
811 pub fn action(&self) -> &str {
813 &self.action
814 }
815
816 pub fn is_recoverable(&self) -> bool {
818 self.is_recoverable
819 }
820
821 pub fn is_warning(&self) -> bool {
825 self.is_warning
826 }
827}
828
829#[cfg(feature = "struct_error")]
830impl fmt::Display for Error {
831 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
832 if !self.message.is_empty() {
833 write!(f, "{}", self.message)
834 } else if let Some(source) = &self.source {
835 write!(f, "{}", source)
836 } else {
837 write!(f, "blank error message")
838 }
839 }
840}
841
842#[cfg(not(feature = "struct_error"))]
843impl fmt::Display for Error {
844 #[allow(deprecated)]
845 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
846 match self {
847 Error::OciError(err) => write!(f, "OCI Error: {}", err.message),
848 Error::DpiError(err) => write!(f, "DPI Error: {}", err.message),
849 Error::NullValue => write!(f, "NULL value found"),
850 Error::ParseError(err) => write!(f, "{}", err),
851 Error::OutOfRange(msg) => write!(f, "{}", msg),
852 Error::InvalidTypeConversion(from, to) => {
853 write!(f, "invalid type conversion from {} to {}", from, to)
854 }
855 Error::InvalidBindIndex(idx) => {
856 write!(f, "invalid bind index {} (one-based)", idx)
857 }
858 Error::InvalidBindName(name) => write!(f, "invalid bind name {}", name),
859 Error::InvalidColumnIndex(idx) => {
860 write!(f, "invalid column index {} (zero-based)", idx)
861 }
862 Error::InvalidColumnName(name) => write!(f, "invalid column name {}", name),
863 Error::InvalidAttributeName(name) => write!(f, "invalid attribute name {}", name),
864 Error::InvalidOperation(msg) => write!(f, "{}", msg),
865 Error::UninitializedBindValue => write!(f, "try to access uninitialized bind value"),
866 Error::NoDataFound => write!(f, "no data found"),
867 Error::BatchErrors(errs) => {
868 write!(f, "batch errors (")?;
869 for err in errs {
870 write!(f, "{}, ", err)?;
871 }
872 write!(f, ")")
873 }
874 Error::InternalError(msg) => write!(f, "{}", msg),
875 Error::InvalidArgument { message, .. } => write!(f, "{}", message),
876 Error::Other {
877 message, source, ..
878 } => {
879 if !message.is_empty() {
880 write!(f, "{}", message)
881 } else if let Some(source) = source {
882 write!(f, "{}", source)
883 } else {
884 write!(f, "blank error message")
885 }
886 }
887 }
888 }
889}
890
891#[cfg(feature = "struct_error")]
892impl error::Error for Error {
893 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
894 if let Some(ref err) = self.source {
895 Some(err.as_ref())
896 } else {
897 None
898 }
899 }
900}
901
902#[cfg(not(feature = "struct_error"))]
903impl error::Error for Error {
904 #[allow(deprecated)]
905 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
906 match self {
907 Error::ParseError(err) => Some(err.as_ref()),
908 Error::InvalidArgument {
909 source: Some(source),
910 ..
911 } => Some(source.as_ref()),
912 Error::Other {
913 source: Some(source),
914 ..
915 } => Some(source.as_ref()),
916 _ => None,
917 }
918 }
919}
920
921impl fmt::Display for DbError {
922 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
923 write!(f, "{}", self.message)
924 }
925}
926
927impl From<ParseOracleTypeError> for Error {
928 fn from(err: ParseOracleTypeError) -> Self {
929 Error::parse_error(err)
930 }
931}
932
933impl From<num::ParseIntError> for Error {
934 fn from(err: num::ParseIntError) -> Self {
935 Error::parse_error(err)
936 }
937}
938
939impl From<num::ParseFloatError> for Error {
940 fn from(err: num::ParseFloatError) -> Self {
941 Error::parse_error(err)
942 }
943}
944
945impl From<num::TryFromIntError> for Error {
946 fn from(err: num::TryFromIntError) -> Self {
947 Error::parse_error(err)
948 }
949}
950
951impl From<str::Utf8Error> for Error {
952 fn from(err: str::Utf8Error) -> Self {
953 Error::parse_error(err)
954 }
955}
956
957impl<T> From<sync::PoisonError<T>> for Error {
958 fn from(err: sync::PoisonError<T>) -> Self {
959 Error::internal_error(err.to_string())
960 }
961}
962
963fn dpi_error_in_message(message: &str) -> Option<i32> {
964 let bytes = message.as_bytes();
965 if !bytes.starts_with(b"DPI-") {
966 return None;
967 }
968 let mut code = 0;
969 for c in bytes.iter().skip(4) {
970 if b'0' <= *c && *c <= b'9' {
971 code *= 10;
972 code += (*c - b'0') as i32;
973 } else if *c == b':' {
974 return Some(code);
975 } else {
976 break;
977 }
978 }
979 None
980}
981
982#[macro_export]
983#[doc(hidden)]
984macro_rules! chkerr {
985 ($ctxt:expr, $code:expr) => {{
986 #[allow(unused_unsafe)]
987 if unsafe { $code } != DPI_SUCCESS as i32 {
988 return Err($crate::Error::from_context($ctxt));
989 }
990 }};
991 ($ctxt:expr, $code:expr, $cleanup:stmt) => {{
992 #[allow(unused_unsafe)]
993 if unsafe { $code } != DPI_SUCCESS as i32 {
994 let err = $crate::Error::from_context($ctxt);
995 $cleanup
996 return Err(err);
997 }
998 }};
999}
1000
1001#[cfg(test)]
1002mod tests {
1003 use super::*;
1004 use std::error::Error as StdError;
1005 use std::io;
1006
1007 #[test]
1008 fn test_dpi_error_in_message() {
1009 assert_eq!(None, dpi_error_in_message("ORA-1234"));
1010 assert_eq!(None, dpi_error_in_message("DPI-1234"));
1011 assert_eq!(Some(1234), dpi_error_in_message("DPI-1234: xxx"));
1012 }
1013
1014 #[test]
1015 fn new_and_add_source() {
1016 let err = Error::new(ErrorKind::Other, "custom error");
1017 assert_eq!(err.kind(), ErrorKind::Other);
1018 assert_eq!(err.to_string(), "custom error");
1019 assert!(err.source().is_none());
1020
1021 let err = err.add_source(io::Error::new(io::ErrorKind::Other, "io error"));
1022 assert_eq!(err.kind(), ErrorKind::Other);
1023 assert_eq!(err.to_string(), "custom error");
1024 assert!(err.source().is_some());
1025 }
1026
1027 #[test]
1028 fn with_source() {
1029 let err = Error::with_source(
1030 ErrorKind::InvalidTypeConversion,
1031 io::Error::new(io::ErrorKind::Other, "io error"),
1032 );
1033 assert_eq!(err.kind(), ErrorKind::InvalidTypeConversion);
1034 assert_eq!(err.to_string(), "io error");
1035 assert!(err.source().is_some());
1036 }
1037}