1from .constants.ER import *
2from .structs import H
3
4
5cdef class MySQLError(Exception):
6    """Exception related to operation with MySQL."""
7
8cdef class Warning(MySQLError):
9    """Exception raised for important warnings like data truncations
10    while inserting, etc."""
11
12cdef class Error(MySQLError):
13    """Exception that is the base class of all other error exceptions
14    (not Warning)."""
15
16cdef class InterfaceError(Error):
17    """Exception raised for errors that are related to the database
18    interface rather than the database itself."""
19
20cdef class DatabaseError(Error):
21    """Exception raised for errors that are related to the
22    database."""
23
24cdef class DataError(DatabaseError):
25    """Exception raised for errors that are due to problems with the
26    processed data like division by zero, numeric value out of range,
27    etc."""
28
29cdef class OperationalError(DatabaseError):
30    """Exception raised for errors that are related to the database's
31    operation and not necessarily under the control of the programmer,
32    e.g. an unexpected disconnect occurs, the data source name is not
33    found, a transaction could not be processed, a memory allocation
34    error occurred during processing, etc."""
35
36cdef class IntegrityError(DatabaseError):
37    """Exception raised when the relational integrity of the database
38    is affected, e.g. a foreign key check fails, duplicate key,
39    etc."""
40
41cdef class InternalError(DatabaseError):
42    """Exception raised when the database encounters an internal
43    error, e.g. the cursor is not valid anymore, the transaction is
44    out of sync, etc."""
45
46cdef class ProgrammingError(DatabaseError):
47    """Exception raised for programming errors, e.g. table not found
48    or already exists, syntax error in the SQL statement, wrong number
49    of parameters specified, etc."""
50
51cdef class NotSupportedError(DatabaseError):
52    """Exception raised in case a method or database API was used
53    which is not supported by the database, e.g. requesting a
54    .rollback() on a connection that does not support transaction or
55    has transactions turned off."""
56
57cdef dict error_map = {}
58
59cdef _map_error(exc, list errors):
60    for error in errors:
61        error_map[error] = exc
62
63_map_error(
64    ProgrammingError, [
65        DB_CREATE_EXISTS,
66        SYNTAX_ERROR,
67        PARSE_ERROR,
68        NO_SUCH_TABLE,
69        WRONG_DB_NAME,
70        WRONG_TABLE_NAME,
71        FIELD_SPECIFIED_TWICE,
72        INVALID_GROUP_FUNC_USE,
73        UNSUPPORTED_EXTENSION,
74        TABLE_MUST_HAVE_COLUMNS,
75        CANT_DO_THIS_DURING_AN_TRANSACTION,
76        WRONG_DB_NAME,
77        WRONG_COLUMN_NAME,
78    ]
79)
80_map_error(
81    DataError,
82    [
83        WARN_DATA_TRUNCATED,
84        WARN_NULL_TO_NOTNULL,
85        WARN_DATA_OUT_OF_RANGE,
86        NO_DEFAULT,
87        PRIMARY_CANT_HAVE_NULL,
88        DATA_TOO_LONG,
89        DATETIME_FUNCTION_OVERFLOW,
90        TRUNCATED_WRONG_VALUE_FOR_FIELD,
91        ILLEGAL_VALUE_FOR_TYPE,
92    ]
93)
94_map_error(
95    IntegrityError,
96    [
97        DUP_ENTRY,
98        NO_REFERENCED_ROW,
99        NO_REFERENCED_ROW_2,
100        ROW_IS_REFERENCED,
101        ROW_IS_REFERENCED_2,
102        CANNOT_ADD_FOREIGN,
103        BAD_NULL_ERROR,
104    ]
105)
106_map_error(
107    NotSupportedError,
108    [
109        WARNING_NOT_COMPLETE_ROLLBACK,
110        NOT_SUPPORTED_YET,
111        FEATURE_DISABLED,
112        UNKNOWN_STORAGE_ENGINE,
113    ]
114)
115_map_error(
116    OperationalError,
117    [
118        DBACCESS_DENIED_ERROR,
119        ACCESS_DENIED_ERROR,
120        CON_COUNT_ERROR,
121        TABLEACCESS_DENIED_ERROR,
122        COLUMNACCESS_DENIED_ERROR,
123        CONSTRAINT_FAILED,
124        LOCK_DEADLOCK,
125    ]
126)
127
128cpdef raise_mysql_exception(bytes data):
129    errno = H.unpack(data[1:3])[0]
130    err_val = data[9:].decode("utf-8", "replace")
131    error_class = error_map.get(errno)
132    if error_class is None:
133        error_class = InternalError if errno < 1000 else OperationalError
134    raise error_class(errno, err_val)
135