1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display, Formatter};
use crate::protocol::response::ErrPacket;
use std::borrow::Cow;
pub(crate) use sqlx_core::error::*;
/// An error returned from the MySQL database.
pub struct MySqlDatabaseError(pub(super) ErrPacket);
impl MySqlDatabaseError {
/// The [SQLSTATE](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html) code for this error.
pub fn code(&self) -> Option<&str> {
self.0.sql_state.as_deref()
}
/// The [number](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html)
/// for this error.
///
/// MySQL tends to use SQLSTATE as a general error category, and the error number as a more
/// granular indication of the error.
pub fn number(&self) -> u16 {
self.0.error_code
}
/// The human-readable error message.
pub fn message(&self) -> &str {
&self.0.error_message
}
}
impl Debug for MySqlDatabaseError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("MySqlDatabaseError")
.field("code", &self.code())
.field("number", &self.number())
.field("message", &self.message())
.finish()
}
}
impl Display for MySqlDatabaseError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if let Some(code) = &self.code() {
write!(f, "{} ({}): {}", self.number(), code, self.message())
} else {
write!(f, "{}: {}", self.number(), self.message())
}
}
}
impl StdError for MySqlDatabaseError {}
impl DatabaseError for MySqlDatabaseError {
#[inline]
fn message(&self) -> &str {
self.message()
}
#[inline]
fn code(&self) -> Option<Cow<'_, str>> {
self.code().map(Cow::Borrowed)
}
#[doc(hidden)]
fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static) {
self
}
#[doc(hidden)]
fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
self
}
#[doc(hidden)]
fn into_error(self: Box<Self>) -> Box<dyn StdError + Send + Sync + 'static> {
self
}
fn kind(&self) -> ErrorKind {
match self.number() {
error_codes::ER_DUP_KEY
| error_codes::ER_DUP_ENTRY
| error_codes::ER_DUP_UNIQUE
| error_codes::ER_DUP_ENTRY_WITH_KEY_NAME
| error_codes::ER_DUP_UNKNOWN_IN_INDEX => ErrorKind::UniqueViolation,
error_codes::ER_NO_REFERENCED_ROW
| error_codes::ER_NO_REFERENCED_ROW_2
| error_codes::ER_ROW_IS_REFERENCED
| error_codes::ER_ROW_IS_REFERENCED_2
| error_codes::ER_FK_COLUMN_NOT_NULL
| error_codes::ER_FK_CANNOT_DELETE_PARENT => ErrorKind::ForeignKeyViolation,
error_codes::ER_BAD_NULL_ERROR | error_codes::ER_NO_DEFAULT_FOR_FIELD => {
ErrorKind::NotNullViolation
}
error_codes::ER_CHECK_CONSTRAINT_VIOLATED => ErrorKind::CheckViolation,
_ => ErrorKind::Other,
}
}
}
/// The MySQL server uses SQLSTATEs as a generic error category,
/// and returns a `error_code` instead within the error packet.
///
/// For reference: <https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html>.
pub(crate) mod error_codes {
/// Caused when a DDL operation creates duplicated keys.
pub const ER_DUP_KEY: u16 = 1022;
/// Caused when a DML operation tries create a duplicated entry for a key,
/// be it a unique or primary one.
pub const ER_DUP_ENTRY: u16 = 1062;
/// Similar to `ER_DUP_ENTRY`, but only present in NDB clusters.
///
/// See: <https://github.com/mysql/mysql-server/blob/fbdaa4def30d269bc4de5b85de61de34b11c0afc/mysql-test/suite/stress/include/ddl7.inc#L68>.
pub const ER_DUP_UNIQUE: u16 = 1169;
/// Similar to `ER_DUP_ENTRY`, but with a formatted string message.
///
/// See: <https://bugs.mysql.com/bug.php?id=46976>.
pub const ER_DUP_ENTRY_WITH_KEY_NAME: u16 = 1586;
/// Caused when a DDL operation to add a unique index fails,
/// because duplicate items were created by concurrent DML operations.
/// When this happens, the key is unknown, so the server can't use `ER_DUP_KEY`.
///
/// For example: an `INSERT` operation creates duplicate `name` fields when `ALTER`ing a table and making `name` unique.
pub const ER_DUP_UNKNOWN_IN_INDEX: u16 = 1859;
/// Caused when inserting an entry with a column with a value that does not reference a foreign row.
pub const ER_NO_REFERENCED_ROW: u16 = 1216;
/// Caused when deleting a row that is referenced in other tables.
pub const ER_ROW_IS_REFERENCED: u16 = 1217;
/// Caused when deleting a row that is referenced in other tables.
/// This differs from `ER_ROW_IS_REFERENCED` in that the error message contains the affected constraint.
pub const ER_ROW_IS_REFERENCED_2: u16 = 1451;
/// Caused when inserting an entry with a column with a value that does not reference a foreign row.
/// This differs from `ER_NO_REFERENCED_ROW` in that the error message contains the affected constraint.
pub const ER_NO_REFERENCED_ROW_2: u16 = 1452;
/// Caused when creating a FK with `ON DELETE SET NULL` or `ON UPDATE SET NULL` to a column that is `NOT NULL`, or vice-versa.
pub const ER_FK_COLUMN_NOT_NULL: u16 = 1830;
/// Removed in 5.7.3.
pub const ER_FK_CANNOT_DELETE_PARENT: u16 = 1834;
/// Caused when inserting a NULL value to a column marked as NOT NULL.
pub const ER_BAD_NULL_ERROR: u16 = 1048;
/// Caused when inserting a DEFAULT value to a column marked as NOT NULL, which also doesn't have a default value set.
pub const ER_NO_DEFAULT_FOR_FIELD: u16 = 1364;
/// Caused when a check constraint is violated.
///
/// Only available after 8.0.16.
pub const ER_CHECK_CONSTRAINT_VIOLATED: u16 = 3819;
}