mysqlx-connector-python 8.3.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mysqlx/errors.py ADDED
@@ -0,0 +1,257 @@
1
+ # Copyright (c) 2016, 2023, Oracle and/or its affiliates.
2
+ #
3
+ # This program is free software; you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License, version 2.0, as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is also distributed with certain software (including
8
+ # but not limited to OpenSSL) that is licensed under separate terms,
9
+ # as designated in a particular file or component or in included license
10
+ # documentation. The authors of MySQL hereby grant you an
11
+ # additional permission to link the program and your derivative works
12
+ # with the separately licensed software that they have included with
13
+ # MySQL.
14
+ #
15
+ # Without limiting anything contained in the foregoing, this file,
16
+ # which is part of MySQL Connector/Python, is also subject to the
17
+ # Universal FOSS Exception, version 1.0, a copy of which can be found at
18
+ # http://oss.oracle.com/licenses/universal-foss-exception.
19
+ #
20
+ # This program is distributed in the hope that it will be useful, but
21
+ # WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23
+ # See the GNU General Public License, version 2.0, for more details.
24
+ #
25
+ # You should have received a copy of the GNU General Public License
26
+ # along with this program; if not, write to the Free Software Foundation, Inc.,
27
+ # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28
+
29
+ """Implementation of the Python Database API Specification v2.0 exceptions."""
30
+
31
+ from struct import unpack as struct_unpack
32
+ from typing import Dict, Optional, Tuple, Union
33
+
34
+ from .locales import get_client_error
35
+ from .types import ErrorClassTypes, ErrorTypes, StrOrBytes
36
+
37
+
38
+ class Error(Exception):
39
+ """Exception that is base class for all other error exceptions."""
40
+
41
+ def __init__(
42
+ self,
43
+ msg: Optional[str] = None,
44
+ errno: Optional[int] = None,
45
+ values: Optional[Tuple[Union[int, str], ...]] = None,
46
+ sqlstate: Optional[str] = None,
47
+ ) -> None:
48
+ super().__init__()
49
+ self.msg = msg
50
+ self._full_msg = self.msg
51
+ self.errno = errno or -1
52
+ self.sqlstate = sqlstate
53
+
54
+ if not self.msg and (2000 <= self.errno < 3000):
55
+ self.msg = get_client_error(self.errno)
56
+ if values is not None:
57
+ try:
58
+ self.msg = self.msg % values
59
+ except TypeError as err:
60
+ self.msg = f"{self.msg} (Warning: {err})"
61
+ elif not self.msg:
62
+ self._full_msg = self.msg = "Unknown error"
63
+
64
+ if self.msg and self.errno != -1:
65
+ fields = {"errno": self.errno, "msg": self.msg}
66
+ if self.sqlstate:
67
+ fmt = "{errno} ({state}): {msg}"
68
+ fields["state"] = self.sqlstate
69
+ else:
70
+ fmt = "{errno}: {msg}"
71
+ self._full_msg = fmt.format(**fields)
72
+
73
+ self.args = (self.errno, self._full_msg, self.sqlstate)
74
+
75
+ def __str__(self) -> str:
76
+ return self._full_msg
77
+
78
+
79
+ class InterfaceError(Error):
80
+ """Exception for errors related to the interface."""
81
+
82
+
83
+ class DatabaseError(Error):
84
+ """Exception for errors related to the database."""
85
+
86
+
87
+ class InternalError(DatabaseError):
88
+ """Exception for errors internal database errors."""
89
+
90
+
91
+ class OperationalError(DatabaseError):
92
+ """Exception for errors related to the database's operation."""
93
+
94
+
95
+ class ProgrammingError(DatabaseError):
96
+ """Exception for errors programming errors."""
97
+
98
+
99
+ class IntegrityError(DatabaseError):
100
+ """Exception for errors regarding relational integrity."""
101
+
102
+
103
+ class DataError(DatabaseError):
104
+ """Exception for errors reporting problems with processed data."""
105
+
106
+
107
+ class NotSupportedError(DatabaseError):
108
+ """Exception for errors when an unsupported database feature was used."""
109
+
110
+
111
+ class PoolError(Error):
112
+ """Exception for errors relating to connection pooling."""
113
+
114
+
115
+ class TimeoutError(Error): # pylint: disable=redefined-builtin
116
+ """Exception for errors relating to connection timeout."""
117
+
118
+
119
+ def intread(buf: bytes) -> int:
120
+ """Unpacks the given buffer to an integer."""
121
+ if isinstance(buf, int):
122
+ return buf
123
+ length = len(buf)
124
+ if length == 1:
125
+ return buf[0]
126
+ if length <= 4:
127
+ tmp = buf + b"\x00" * (4 - length)
128
+ return struct_unpack("<I", tmp)[0]
129
+ tmp = buf + b"\x00" * (8 - length)
130
+ return struct_unpack("<Q", tmp)[0]
131
+
132
+
133
+ def read_int(buf: bytes, size: int) -> Tuple[bytes, int]:
134
+ """Read an integer from buffer.
135
+
136
+ Returns a tuple (truncated buffer, int).
137
+ """
138
+ res = intread(buf[0:size])
139
+ return (buf[size:], res)
140
+
141
+
142
+ def read_bytes(buf: bytes, size: int) -> Tuple[bytes, bytes]:
143
+ """Reads bytes from a buffer.
144
+
145
+ Returns a tuple with buffer less the read bytes, and the bytes.
146
+ """
147
+ res = buf[0:size]
148
+ return (buf[size:], res)
149
+
150
+
151
+ def get_mysql_exception(
152
+ errno: int, msg: Optional[str] = None, sqlstate: Optional[str] = None
153
+ ) -> ErrorTypes:
154
+ """Get the exception matching the MySQL error.
155
+
156
+ This function will return an exception based on the SQLState. The given
157
+ message will be passed on in the returned exception.
158
+
159
+ Returns an Exception.
160
+ """
161
+ try:
162
+ return _ERROR_EXCEPTIONS[errno](msg=msg, errno=errno, sqlstate=sqlstate)
163
+ except KeyError:
164
+ # Error was not mapped to particular exception
165
+ pass
166
+
167
+ if not sqlstate:
168
+ return DatabaseError(msg=msg, errno=errno)
169
+
170
+ try:
171
+ return _SQLSTATE_CLASS_EXCEPTION[sqlstate[0:2]](
172
+ msg=msg, errno=errno, sqlstate=sqlstate
173
+ )
174
+ except KeyError:
175
+ # Return default InterfaceError
176
+ return DatabaseError(msg=msg, errno=errno, sqlstate=sqlstate)
177
+
178
+
179
+ def get_exception(packet: bytes) -> ErrorTypes:
180
+ """Returns an exception object based on the MySQL error.
181
+
182
+ Returns an exception object based on the MySQL error in the given
183
+ packet.
184
+
185
+ Returns an Error-Object.
186
+ """
187
+ errno = errmsg = None
188
+
189
+ try:
190
+ if packet[4] != 255:
191
+ raise ValueError("Packet is not an error packet")
192
+ except IndexError as err:
193
+ return InterfaceError(f"Failed getting Error information ({err})")
194
+
195
+ sqlstate: Optional[StrOrBytes] = None
196
+ try:
197
+ packet = packet[5:]
198
+ packet, errno = read_int(packet, 2)
199
+ if packet[0] != 35:
200
+ # Error without SQLState
201
+ errmsg = (
202
+ packet.decode("utf8")
203
+ if isinstance(packet, (bytes, bytearray))
204
+ else packet
205
+ )
206
+ else:
207
+ packet, sqlstate = read_bytes(packet[1:], 5)
208
+ sqlstate = sqlstate.decode("utf8")
209
+ errmsg = packet.decode("utf8")
210
+ except (IndexError, ValueError) as err:
211
+ return InterfaceError(f"Failed getting Error information ({err})")
212
+ return get_mysql_exception(errno, errmsg, sqlstate) # type: ignore[arg-type]
213
+
214
+
215
+ _SQLSTATE_CLASS_EXCEPTION: Dict[str, ErrorClassTypes] = {
216
+ "02": DataError, # no data
217
+ "07": DatabaseError, # dynamic SQL error
218
+ "08": OperationalError, # connection exception
219
+ "0A": NotSupportedError, # feature not supported
220
+ "21": DataError, # cardinality violation
221
+ "22": DataError, # data exception
222
+ "23": IntegrityError, # integrity constraint violation
223
+ "24": ProgrammingError, # invalid cursor state
224
+ "25": ProgrammingError, # invalid transaction state
225
+ "26": ProgrammingError, # invalid SQL statement name
226
+ "27": ProgrammingError, # triggered data change violation
227
+ "28": ProgrammingError, # invalid authorization specification
228
+ "2A": ProgrammingError, # direct SQL syntax error or access rule violation
229
+ "2B": DatabaseError, # dependent privilege descriptors still exist
230
+ "2C": ProgrammingError, # invalid character set name
231
+ "2D": DatabaseError, # invalid transaction termination
232
+ "2E": DatabaseError, # invalid connection name
233
+ "33": DatabaseError, # invalid SQL descriptor name
234
+ "34": ProgrammingError, # invalid cursor name
235
+ "35": ProgrammingError, # invalid condition number
236
+ "37": ProgrammingError, # dynamic SQL syntax error or access rule violation
237
+ "3C": ProgrammingError, # ambiguous cursor name
238
+ "3D": ProgrammingError, # invalid catalog name
239
+ "3F": ProgrammingError, # invalid schema name
240
+ "40": InternalError, # transaction rollback
241
+ "42": ProgrammingError, # syntax error or access rule violation
242
+ "44": InternalError, # with check option violation
243
+ "HZ": OperationalError, # remote database access
244
+ "XA": IntegrityError,
245
+ "0K": OperationalError,
246
+ "HY": DatabaseError, # default when no SQLState provided by MySQL server
247
+ }
248
+
249
+ _ERROR_EXCEPTIONS: Dict[int, ErrorClassTypes] = {
250
+ 1243: ProgrammingError,
251
+ 1210: ProgrammingError,
252
+ 2002: InterfaceError,
253
+ 2013: OperationalError,
254
+ 2049: NotSupportedError,
255
+ 2055: OperationalError,
256
+ 2061: InterfaceError,
257
+ }