├── client_error.py ├── connection.py ├── constants.py ├── conversion.py ├── cursor.py ├── dbapi.py ├── errorcode.py ├── errors.py ├── locales.py ├── mysqldb.py ├── network.py ├── protocol.py ├── utils.py └── version.py /client_error.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # MySQL Connector/Python - MySQL driver written in Python. 4 | # Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 5 | # 6 | # MySQL Connector/Python is licensed under the terms of the GPLv2 7 | # , like most 8 | # MySQL Connectors. There are special exceptions to the terms and 9 | # conditions of the GPLv2 as it is applied to this software, see the 10 | # FOSS License Exception 11 | # . 12 | # 13 | # This program is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 25 | 26 | # This file was auto-generated. 27 | _GENERATED_ON = '2013-01-28' 28 | _MYSQL_VERSION = (5, 6, 9) 29 | 30 | # Start MySQL Error messages 31 | CR_UNKNOWN_ERROR = u"Unknown MySQL error" 32 | CR_SOCKET_CREATE_ERROR = u"Can't create UNIX socket (%s)" 33 | CR_CONNECTION_ERROR = u"Can't connect to local MySQL server through socket '%-.100s' (%s)" 34 | CR_CONN_HOST_ERROR = u"Can't connect to MySQL server on '%-.100s' (%s)" 35 | CR_IPSOCK_ERROR = u"Can't create TCP/IP socket (%s)" 36 | CR_UNKNOWN_HOST = u"Unknown MySQL server host '%-.100s' (%s)" 37 | CR_SERVER_GONE_ERROR = u"MySQL server has gone away" 38 | CR_VERSION_ERROR = u"Protocol mismatch; server version = %s, client version = %s" 39 | CR_OUT_OF_MEMORY = u"MySQL client ran out of memory" 40 | CR_WRONG_HOST_INFO = u"Wrong host info" 41 | CR_LOCALHOST_CONNECTION = u"Localhost via UNIX socket" 42 | CR_TCP_CONNECTION = u"%-.100s via TCP/IP" 43 | CR_SERVER_HANDSHAKE_ERR = u"Error in server handshake" 44 | CR_SERVER_LOST = u"Lost connection to MySQL server during query" 45 | CR_COMMANDS_OUT_OF_SYNC = u"Commands out of sync; you can't run this command now" 46 | CR_NAMEDPIPE_CONNECTION = u"Named pipe: %-.32s" 47 | CR_NAMEDPIPEWAIT_ERROR = u"Can't wait for named pipe to host: %-.64s pipe: %-.32s (%s)" 48 | CR_NAMEDPIPEOPEN_ERROR = u"Can't open named pipe to host: %-.64s pipe: %-.32s (%s)" 49 | CR_NAMEDPIPESETSTATE_ERROR = u"Can't set state of named pipe to host: %-.64s pipe: %-.32s (%s)" 50 | CR_CANT_READ_CHARSET = u"Can't initialize character set %-.32s (path: %-.100s)" 51 | CR_NET_PACKET_TOO_LARGE = u"Got packet bigger than 'max_allowed_packet' bytes" 52 | CR_EMBEDDED_CONNECTION = u"Embedded server" 53 | CR_PROBE_SLAVE_STATUS = u"Error on SHOW SLAVE STATUS:" 54 | CR_PROBE_SLAVE_HOSTS = u"Error on SHOW SLAVE HOSTS:" 55 | CR_PROBE_SLAVE_CONNECT = u"Error connecting to subordinate:" 56 | CR_PROBE_MASTER_CONNECT = u"Error connecting to main:" 57 | CR_SSL_CONNECTION_ERROR = u"SSL connection error: %-.100s" 58 | CR_MALFORMED_PACKET = u"Malformed packet" 59 | CR_WRONG_LICENSE = u"This client library is licensed only for use with MySQL servers having '%s' license" 60 | CR_NULL_POINTER = u"Invalid use of null pointer" 61 | CR_NO_PREPARE_STMT = u"Statement not prepared" 62 | CR_PARAMS_NOT_BOUND = u"No data supplied for parameters in prepared statement" 63 | CR_DATA_TRUNCATED = u"Data truncated" 64 | CR_NO_PARAMETERS_EXISTS = u"No parameters exist in the statement" 65 | CR_INVALID_PARAMETER_NO = u"Invalid parameter number" 66 | CR_INVALID_BUFFER_USE = u"Can't send long data for non-string/non-binary data types (parameter: %s)" 67 | CR_UNSUPPORTED_PARAM_TYPE = u"Using unsupported buffer type: %s (parameter: %s)" 68 | CR_SHARED_MEMORY_CONNECTION = u"Shared memory: %-.100s" 69 | CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR = u"Can't open shared memory; client could not create request event (%s)" 70 | CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR = u"Can't open shared memory; no answer event received from server (%s)" 71 | CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR = u"Can't open shared memory; server could not allocate file mapping (%s)" 72 | CR_SHARED_MEMORY_CONNECT_MAP_ERROR = u"Can't open shared memory; server could not get pointer to file mapping (%s)" 73 | CR_SHARED_MEMORY_FILE_MAP_ERROR = u"Can't open shared memory; client could not allocate file mapping (%s)" 74 | CR_SHARED_MEMORY_MAP_ERROR = u"Can't open shared memory; client could not get pointer to file mapping (%s)" 75 | CR_SHARED_MEMORY_EVENT_ERROR = u"Can't open shared memory; client could not create %s event (%s)" 76 | CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR = u"Can't open shared memory; no answer from server (%s)" 77 | CR_SHARED_MEMORY_CONNECT_SET_ERROR = u"Can't open shared memory; cannot send request event to server (%s)" 78 | CR_CONN_UNKNOW_PROTOCOL = u"Wrong or unknown protocol" 79 | CR_INVALID_CONN_HANDLE = u"Invalid connection handle" 80 | CR_SECURE_AUTH = u"Connection using old (pre-4.1.1) authentication protocol refused (client option 'secure_auth' enabled)" 81 | CR_FETCH_CANCELED = u"Row retrieval was canceled by mysql_stmt_close() call" 82 | CR_NO_DATA = u"Attempt to read column without prior row fetch" 83 | CR_NO_STMT_METADATA = u"Prepared statement contains no metadata" 84 | CR_NO_RESULT_SET = u"Attempt to read a row while there is no result set associated with the statement" 85 | CR_NOT_IMPLEMENTED = u"This feature is not implemented yet" 86 | CR_SERVER_LOST_EXTENDED = u"Lost connection to MySQL server at '%s', system error: %s" 87 | CR_STMT_CLOSED = u"Statement closed indirectly because of a preceeding %s() call" 88 | CR_NEW_STMT_METADATA = u"The number of columns in the result set differs from the number of bound buffers. You must reset the statement, rebind the result set columns, and execute the statement again" 89 | CR_ALREADY_CONNECTED = u"This handle is already connected. Use a separate handle for each connection." 90 | CR_AUTH_PLUGIN_CANNOT_LOAD = u"Authentication plugin '%s' cannot be loaded: %s" 91 | CR_DUPLICATE_CONNECTION_ATTR = u"" 92 | # End MySQL Error messages 93 | 94 | -------------------------------------------------------------------------------- /connection.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Implementing communication with MySQL servers. 25 | """ 26 | 27 | import os 28 | import time 29 | import re 30 | 31 | from network import (MySQLUnixSocket, MySQLTCPSocket) 32 | from constants import (ClientFlag, ServerCmd, CharacterSet, 33 | ServerFlag, flag_is_set, ShutdownType) 34 | from conversion import MySQLConverter 35 | from protocol import MySQLProtocol 36 | import errors 37 | from utils import (int4store, int1store) 38 | from cursor import (CursorBase, MySQLCursor, MySQLCursorRaw, 39 | MySQLCursorBuffered, MySQLCursorBufferedRaw) 40 | 41 | DEFAULT_CONFIGURATION = { 42 | 'database': None, 43 | 'user': '', 44 | 'password': '', 45 | 'host': '127.0.0.1', 46 | 'port': 3306, 47 | 'unix_socket': None, 48 | 'use_unicode': True, 49 | 'charset': 'utf8', 50 | 'collation': None, 51 | 'autocommit': False, 52 | 'time_zone': None, 53 | 'sql_mode': None, 54 | 'get_warnings': False, 55 | 'raise_on_warnings': False, 56 | 'connection_timeout': None, 57 | 'client_flags': 0, 58 | 'buffered': False, 59 | 'raw': False, 60 | 'ssl_ca': None, 61 | 'ssl_cert': None, 62 | 'ssl_key': None, 63 | 'ssl_verify_cert': False, 64 | 'passwd': None, 65 | 'db': None, 66 | 'connect_timeout': None, 67 | 'dsn': None, 68 | 'force_ipv6': False, 69 | } 70 | 71 | class MySQLConnection(object): 72 | """Connection to a MySQL Server""" 73 | def __init__(self, **kwargs): 74 | self._protocol = None 75 | self._socket = None 76 | self._handshake = None 77 | self._server_version = None 78 | self.converter = None 79 | self._converter_class = None 80 | 81 | self._client_flags = ClientFlag.get_default() 82 | self._charset_id = 33 83 | self._sql_mode = None 84 | self._time_zone = None 85 | self._autocommit = False 86 | 87 | self._user = '' 88 | self._password = '' 89 | self._database = '' 90 | self._host = '127.0.0.1' 91 | self._port = 3306 92 | self._unix_socket = None 93 | self._client_host = '' 94 | self._client_port = 0 95 | self._ssl = {} 96 | self._force_ipv6 = False 97 | 98 | self._use_unicode = True 99 | self._get_warnings = False 100 | self._raise_on_warnings = False 101 | self._connection_timeout = None 102 | self._buffered = False 103 | self._unread_result = False 104 | self._have_next_result = False 105 | self._raw = False 106 | 107 | if len(kwargs) > 0: 108 | self.connect(**kwargs) 109 | 110 | def _get_self(self): 111 | """Return self for weakref.proxy 112 | 113 | This method is used when the original object is needed when using 114 | weakref.proxy. 115 | """ 116 | return self 117 | 118 | def _do_handshake(self): 119 | """Get the handshake from the MySQL server""" 120 | packet = self._socket.recv() 121 | if packet[4] == '\xff': 122 | raise errors.get_exception(packet) 123 | 124 | try: 125 | handshake = self._protocol.parse_handshake(packet) 126 | except Exception, err: 127 | raise errors.InterfaceError('Failed parsing handshake; %s' % err) 128 | 129 | regex_ver = re.compile("^(\d{1,2})\.(\d{1,2})\.(\d{1,3})(.*)") 130 | match = regex_ver.match(handshake['server_version_original']) 131 | if not match: 132 | raise errors.InterfaceError("Failed parsing MySQL version") 133 | 134 | version = tuple([ int(v) for v in match.groups()[0:3]]) 135 | if version < (4, 1): 136 | raise errors.InterfaceError( 137 | "MySQL Version '%s' is not supported." % \ 138 | handshake['server_version_original']) 139 | 140 | self._handshake = handshake 141 | self._server_version = version 142 | 143 | def _do_auth(self, username=None, password=None, database=None, 144 | client_flags=0, charset=33, ssl_options=None): 145 | """Authenticate with the MySQL server 146 | """ 147 | if client_flags & ClientFlag.SSL and ssl_options: 148 | packet = self._protocol.make_auth_ssl(charset=charset, 149 | client_flags=client_flags) 150 | self._socket.send(packet) 151 | self._socket.switch_to_ssl(**ssl_options) 152 | 153 | packet = self._protocol.make_auth( 154 | seed=self._handshake['scramble'], 155 | username=username, password=password, database=database, 156 | charset=charset, client_flags=client_flags) 157 | self._socket.send(packet) 158 | packet = self._socket.recv() 159 | 160 | if packet[4] == '\xfe': 161 | raise errors.NotSupportedError( 162 | "Authentication with old (insecure) passwords "\ 163 | "is not supported. For more information, lookup "\ 164 | "Password Hashing in the latest MySQL manual") 165 | elif packet[4] == '\xff': 166 | raise errors.get_exception(packet) 167 | 168 | try: 169 | if (not (client_flags & ClientFlag.CONNECT_WITH_DB) 170 | and database): 171 | self.cmd_init_db(database) 172 | except: 173 | raise 174 | 175 | return True 176 | 177 | def config(self, **kwargs): 178 | """Configure the MySQL Connection 179 | 180 | This method allows you to configure the MySQLConnection instance. 181 | 182 | Raises on errors. 183 | """ 184 | config = kwargs.copy() 185 | if 'dsn' in config: 186 | raise errors.NotSupportedError("Data source name is not supported") 187 | 188 | # Configure how we handle MySQL warnings 189 | try: 190 | self.get_warnings = config['get_warnings'] 191 | del config['get_warnings'] 192 | except KeyError: 193 | pass # Leave what was set or default 194 | try: 195 | self.raise_on_warnings = config['raise_on_warnings'] 196 | del config['raise_on_warnings'] 197 | except KeyError: 198 | pass # Leave what was set or default 199 | 200 | # Configure client flags 201 | try: 202 | default = ClientFlag.get_default() 203 | self.set_client_flags(config['client_flags'] or default) 204 | del config['client_flags'] 205 | except KeyError: 206 | pass # Missing client_flags-argument is OK 207 | 208 | # Configure character set and collation 209 | if ('charset' in config or 'collation' in config): 210 | try: 211 | charset = config['charset'] 212 | del config['charset'] 213 | except KeyError: 214 | charset = None 215 | try: 216 | collation = config['collation'] 217 | del config['collation'] 218 | except KeyError: 219 | collation = None 220 | self._charset_id = CharacterSet.get_charset_info(charset, 221 | collation)[0] 222 | 223 | # Compatible configuration with other drivers 224 | compat_map = [ 225 | # (,) 226 | ('db','database'), 227 | ('passwd','password'), 228 | ('connect_timeout','connection_timeout'), 229 | ] 230 | for compat, translate in compat_map: 231 | try: 232 | if translate not in config: 233 | config[translate] = config[compat] 234 | del config[compat] 235 | except KeyError: 236 | pass # Missing compat argument is OK 237 | 238 | # Configure login information 239 | if ('user' in config or 'password' in config): 240 | try: 241 | user = config['user'] 242 | del config['user'] 243 | except KeyError: 244 | user = self._user 245 | try: 246 | password = config['password'] 247 | del config['password'] 248 | except KeyError: 249 | password = self._password 250 | self.set_login(user, password) 251 | 252 | # Check network locations 253 | try: 254 | self._port = int(config['port']) 255 | del config['port'] 256 | except KeyError: 257 | pass # Missing port argument is OK 258 | except ValueError: 259 | raise errors.InterfaceError( 260 | "TCP/IP port number should be an integer") 261 | 262 | # Other configuration 263 | set_ssl_flag = False 264 | for key, value in config.items(): 265 | try: 266 | DEFAULT_CONFIGURATION[key] 267 | except KeyError: 268 | raise AttributeError("Unsupported argument '%s'" % key) 269 | # SSL Configuration 270 | if key == 'ssl_verify_cert': 271 | set_ssl_flag = True 272 | self._ssl.update({'verify_cert': value}) 273 | elif key.startswith('ssl_') and value: 274 | set_ssl_flag = True 275 | self._ssl.update({key.replace('ssl_', ''): value}) 276 | else: 277 | attribute = '_' + key 278 | try: 279 | setattr(self, attribute, value.strip()) 280 | except AttributeError: 281 | setattr(self, attribute, value) 282 | 283 | if set_ssl_flag: 284 | if 'verify_cert' not in self._ssl: 285 | self._ssl['verify_cert'] = \ 286 | DEFAULT_CONFIGURATION['ssl_verify_cert'] 287 | required_keys = set(['ca', 'cert', 'key']) 288 | diff = list(required_keys - set(self._ssl.keys())) 289 | if diff: 290 | missing_attrs = [ "ssl_" + val for val in diff ] 291 | raise AttributeError("Missing SSL argument(s): %s" % ( 292 | ', '.join(missing_attrs))) 293 | self.set_client_flags([ClientFlag.SSL]) 294 | 295 | def _get_connection(self): 296 | """Get connection based on configuration 297 | 298 | This method will return the appropriated connection object using 299 | the connection parameters. 300 | 301 | Returns subclass of MySQLBaseSocket. 302 | """ 303 | conn = None 304 | if self.unix_socket and os.name != 'nt': 305 | conn = MySQLUnixSocket(unix_socket=self.unix_socket) 306 | else: 307 | conn = MySQLTCPSocket(host=self.server_host, 308 | port=self.server_port, 309 | force_ipv6=self._force_ipv6) 310 | conn.set_connection_timeout(self._connection_timeout) 311 | return conn 312 | 313 | def _open_connection(self): 314 | """Open the connection to the MySQL server 315 | 316 | This method sets up and opens the connection to the MySQL server. 317 | """ 318 | self._socket = self._get_connection() 319 | self._socket.open_connection() 320 | self._do_handshake() 321 | self._do_auth(self._user, self._password, 322 | self._database, self._client_flags, self._charset_id, 323 | self._ssl) 324 | self.set_converter_class(MySQLConverter) 325 | if self._client_flags & ClientFlag.COMPRESS: 326 | self._socket.recv = self._socket.recv_compressed 327 | self._socket.send = self._socket.send_compressed 328 | 329 | def _post_connection(self): 330 | """Executes commands after connection has been established 331 | 332 | This method executes commands after the connection has been 333 | established. Some setting like autocommit, character set, and SQL mode 334 | are set using this method. 335 | """ 336 | self.set_charset_collation(charset=self._charset_id) 337 | self.autocommit = self._autocommit 338 | if self._time_zone: 339 | self.time_zone = self._time_zone 340 | if self._sql_mode: 341 | self.sql_mode = self._sql_mode 342 | 343 | def connect(self, **kwargs): 344 | """Connect to the MySQL server 345 | 346 | This method sets up the connection to the MySQL server. If no 347 | arguments are given, it will use the already configured or default 348 | values. 349 | """ 350 | if len(kwargs) > 0: 351 | self.config(**kwargs) 352 | 353 | self._protocol = MySQLProtocol() 354 | 355 | self.disconnect() 356 | self._open_connection() 357 | self._post_connection() 358 | 359 | def disconnect(self): 360 | """Disconnect from the MySQL server 361 | """ 362 | if not self._socket: 363 | return 364 | 365 | try: 366 | self.cmd_quit() 367 | self._socket.close_connection() 368 | except errors.Error: 369 | pass # Getting an exception would mean we are disconnected. 370 | close = disconnect 371 | 372 | def _send_cmd(self, command, argument=None, packet_number=0): 373 | """Send a command to the MySQL server 374 | 375 | This method sends a command with an optional argument. 376 | 377 | Returns a MySQL packet 378 | """ 379 | if self.unread_result: 380 | raise errors.InternalError("Unread result found.") 381 | 382 | try: 383 | self._socket.send(self._protocol.make_command(command, argument), 384 | packet_number) 385 | except AttributeError: 386 | raise errors.OperationalError("MySQL Connection not available.") 387 | 388 | return self._socket.recv() 389 | 390 | def _send_data(self, fp, send_empty_packet=False): 391 | """Send data to the MySQL server 392 | 393 | This method accepts a file-like object and sends its data 394 | as is to the MySQL server. If the send_empty_packet is 395 | True, it will send an extra empty package (for example 396 | when using LOAD LOCAL DATA INFILE). 397 | 398 | Returns a MySQL packet. 399 | """ 400 | if self.unread_result: 401 | raise errors.InternalError("Unread result found.") 402 | 403 | if not hasattr(fp, 'read'): 404 | raise ValueError("expecting a file-like object") 405 | 406 | try: 407 | buf = fp.read(4096) 408 | while buf: 409 | self._socket.send(buf) 410 | buf = fp.read(4096) 411 | except AttributeError: 412 | raise errors.OperationalError("MySQL Connection not available.") 413 | 414 | if send_empty_packet: 415 | try: 416 | self._socket.send('') 417 | except AttributeError: 418 | raise errors.OperationalError( 419 | "MySQL Connection not available.") 420 | 421 | return self._socket.recv() 422 | 423 | def _toggle_have_next_result(self, flags): 424 | """Toggle whether there more results 425 | 426 | This method checks the whether MORE_RESULTS_EXISTS is set in flags. 427 | """ 428 | if flag_is_set(ServerFlag.MORE_RESULTS_EXISTS, flags): 429 | self._have_next_result = True 430 | else: 431 | self._have_next_result = False 432 | 433 | def _handle_ok(self, packet): 434 | """Handle a MySQL OK packet 435 | 436 | This method handles a MySQL OK packet. When the packet is found to 437 | be an Error packet, an error will be raised. If the packet is neither 438 | an OK or an Error packet, errors.InterfaceError will be raised. 439 | 440 | Returns a dict() 441 | """ 442 | if packet[4] == '\x00': 443 | ok = self._protocol.parse_ok(packet) 444 | self._toggle_have_next_result(ok['server_status']) 445 | return ok 446 | elif packet[4] == '\xff': 447 | raise errors.get_exception(packet) 448 | raise errors.InterfaceError('Expected OK packet') 449 | 450 | def _handle_eof(self, packet): 451 | """Handle a MySQL EOF packet 452 | 453 | This method handles a MySQL EOF packet. When the packet is found to 454 | be an Error packet, an error will be raised. If the packet is neither 455 | and OK or an Error packet, errors.InterfaceError will be raised. 456 | 457 | Returns a dict() 458 | """ 459 | if packet[4] == '\xfe': 460 | eof = self._protocol.parse_eof(packet) 461 | self._toggle_have_next_result(eof['status_flag']) 462 | return eof 463 | elif packet[4] == '\xff': 464 | raise errors.get_exception(packet) 465 | raise errors.InterfaceError('Expected EOF packet') 466 | 467 | def _handle_load_data_infile(self, filename): 468 | """Handle a LOAD DATA INFILE LOCAL request""" 469 | try: 470 | fp = open(filename, 'rb') 471 | except IOError: 472 | # Send a empty packet to cancel the operation 473 | try: 474 | self._socket.send('') 475 | except AttributeError: 476 | raise errors.OperationalError( 477 | "MySQL Connection not available.") 478 | raise errors.InterfaceError("File '%s' could not be read" % 479 | filename) 480 | 481 | return self._handle_ok(self._send_data(fp, send_empty_packet=True)) 482 | 483 | def _handle_result(self, packet): 484 | """Handle a MySQL Result 485 | 486 | This method handles a MySQL result, for example, after sending the 487 | query command. OK and EOF packets will be handled and returned. If 488 | the packet is an Error packet, an errors.Error-exception will be 489 | raised. 490 | 491 | The dictionary returned of: 492 | - columns: column information 493 | - eof: the EOF-packet information 494 | 495 | Returns a dict() 496 | """ 497 | if not packet or len(packet) < 4: 498 | raise errors.InterfaceError('Empty response') 499 | elif packet[4] == '\x00': 500 | return self._handle_ok(packet) 501 | elif packet[4] == '\xfb': 502 | return self._handle_load_data_infile(packet[5:]) 503 | elif packet[4] == '\xfe': 504 | return self._handle_eof(packet) 505 | elif packet[4] == '\xff': 506 | raise errors.get_exception(packet) 507 | 508 | # We have a text result set 509 | column_count = self._protocol.parse_column_count(packet) 510 | if not column_count or not isinstance(column_count, int): 511 | raise errors.InterfaceError('Illegal result set.') 512 | 513 | columns = [None,]*column_count 514 | for i in xrange(0, column_count): 515 | columns[i] = self._protocol.parse_column(self._socket.recv()) 516 | 517 | eof = self._handle_eof(self._socket.recv()) 518 | self.unread_result = True 519 | return {'columns': columns, 'eof': eof} 520 | 521 | def get_rows(self, count=None): 522 | """Get all rows returned by the MySQL server 523 | 524 | This method gets all rows returned by the MySQL server after sending, 525 | for example, the query command. The result is a tuple consisting of 526 | a list of rows and the EOF packet. 527 | 528 | Returns a tuple() 529 | """ 530 | if not self.unread_result: 531 | raise errors.InternalError("No result set available.") 532 | 533 | rows = self._protocol.read_text_result(self._socket, count) 534 | if rows[-1] is not None: 535 | self._toggle_have_next_result(rows[-1]['status_flag']) 536 | self.unread_result = False 537 | 538 | return rows 539 | 540 | def get_row(self): 541 | """Get the next rows returned by the MySQL server 542 | 543 | This method gets one row from the result set after sending, for 544 | example, the query command. The result is a tuple consisting of the 545 | row and the EOF packet. 546 | If no row was available in the result set, the row data will be None. 547 | 548 | Returns a tuple. 549 | """ 550 | (rows, eof) = self.get_rows(count=1) 551 | if len(rows): 552 | return (rows[0], eof) 553 | return (None, eof) 554 | 555 | def cmd_init_db(self, database): 556 | """Change the current database 557 | 558 | This method changes the current (default) database by sending the 559 | INIT_DB command. The result is a dictionary containing the OK packet 560 | information. 561 | 562 | Returns a dict() 563 | """ 564 | return self._handle_ok(self._send_cmd(ServerCmd.INIT_DB, database)) 565 | 566 | def cmd_query(self, statement): 567 | """Send a statement to the MySQL server 568 | 569 | This method sends the given statement to the MySQL server and 570 | returns a result. If you need to send multiple statements, you 571 | have to use the cmd_query_iter() method. 572 | 573 | The returned dictionary contains information depending on what kind 574 | of query was executed. If the query is a SELECT statement, the result 575 | will contain information about columns. Other statements will return 576 | a dictionary containing an OK or EOF packet. 577 | 578 | Errors received from the MySQL server will be raised as exceptions. 579 | An InterfaceError is raised when multiple results were found. 580 | 581 | Returns a dictionary. 582 | """ 583 | result = self._handle_result(self._send_cmd(ServerCmd.QUERY, 584 | statement)) 585 | 586 | if self._have_next_result: 587 | raise errors.InterfaceError( 588 | 'Use cmd_query_iter for statements with multiple queries.') 589 | return result 590 | 591 | def cmd_query_iter(self, statements): 592 | """Send one or more statements to the MySQL server 593 | 594 | Similar to the cmd_query method, but instead returns a generator 595 | object to iterate through results. It sends the statements to the 596 | MySQL server and through the iterator you can get the results. 597 | 598 | statement = 'SELECT 1; INSERT INTO t1 VALUES (); SELECT 2' 599 | for result in cnx.cmd_query(statement, iterate=True): 600 | if 'columns' in result: 601 | columns = result['columns'] 602 | rows = cnx.get_rows() 603 | else: 604 | # do something useful with INSERT result 605 | 606 | Returns a generator. 607 | """ 608 | # Handle the first query result 609 | yield self._handle_result(self._send_cmd(ServerCmd.QUERY, statements)) 610 | 611 | # Handle next results, if any 612 | while self._have_next_result: 613 | if self.unread_result: 614 | raise errors.InternalError("Unread result found.") 615 | else: 616 | result = self._handle_result(self._socket.recv()) 617 | yield result 618 | 619 | def cmd_refresh(self, options): 620 | """Send the Refresh command to the MySQL server 621 | 622 | This method sends the Refresh command to the MySQL server. The options 623 | argument should be a bitwise value using contants.RefreshOption. 624 | Usage example: 625 | RefreshOption = mysql.connector.RefreshOption 626 | refresh = RefreshOption.LOG | RefreshOption.THREADS 627 | cnx.cmd_refresh(refresh) 628 | 629 | The result is a dictionary with the OK packat information. 630 | 631 | Returns a dict() 632 | """ 633 | return self._handle_ok( 634 | self._send_cmd(ServerCmd.REFRESH, int4store(options))) 635 | 636 | def cmd_quit(self): 637 | """Close the current connection with the server 638 | 639 | This method sends the QUIT command to the MySQL server, closing the 640 | current connection. Since the no response can be returned to the 641 | client, cmd_quit() will return the packet it send. 642 | 643 | Returns a str() 644 | """ 645 | if self.unread_result: 646 | raise errors.InternalError("Unread result found.") 647 | 648 | packet = self._protocol.make_command(ServerCmd.QUIT) 649 | self._socket.send(packet, 0) 650 | return packet 651 | 652 | def cmd_shutdown(self, shutdown_type=None): 653 | """Shut down the MySQL Server 654 | 655 | This method sends the SHUTDOWN command to the MySQL server and is only 656 | possible if the current user has SUPER privileges. The result is a 657 | dictionary containing the OK packet information. 658 | 659 | Note: Most applications and scripts do not the SUPER privilege. 660 | 661 | Returns a dict() 662 | """ 663 | atype = None 664 | if shutdown_type: 665 | if not ShutdownType.get_info(shutdown_type): 666 | raise errors.InterfaceError("Invalid shutdown type") 667 | atype = int1store(shutdown_type) 668 | return self._handle_eof(self._send_cmd(ServerCmd.SHUTDOWN, atype)) 669 | 670 | def cmd_statistics(self): 671 | """Send the statistics command to the MySQL Server 672 | 673 | This method sends the STATISTICS command to the MySQL server. The 674 | result is a dictionary with various statistical information. 675 | 676 | Returns a dict() 677 | """ 678 | if self.unread_result: 679 | raise errors.InternalError("Unread result found.") 680 | 681 | packet = self._protocol.make_command(ServerCmd.STATISTICS) 682 | self._socket.send(packet, 0) 683 | return self._protocol.parse_statistics(self._socket.recv()) 684 | 685 | def cmd_process_info(self): 686 | """Get the process list of the MySQL Server 687 | 688 | This method is a placeholder to notify that the PROCESS_INFO command 689 | is not supported by raising the NotSupportedError. The command 690 | "SHOW PROCESSLIST" should be send using the cmd_query()-method or 691 | using the INFORMATION_SCHEMA database. 692 | 693 | Raises NotSupportedError exception 694 | """ 695 | raise errors.NotSupportedError( 696 | "Not implemented. Use SHOW PROCESSLIST or INFORMATION_SCHEMA") 697 | 698 | def cmd_process_kill(self, mysql_pid): 699 | """Kill a MySQL process 700 | 701 | This method send the PROCESS_KILL command to the server along with 702 | the process ID. The result is a dictionary with the OK packet 703 | information. 704 | 705 | Returns a dict() 706 | """ 707 | return self._handle_ok( 708 | self._send_cmd(ServerCmd.PROCESS_KILL, int4store(mysql_pid))) 709 | 710 | def cmd_debug(self): 711 | """Send the DEBUG command 712 | 713 | This method sends the DEBUG command to the MySQL server, which 714 | requires the MySQL user to have SUPER privilege. The output will go 715 | to the MySQL server error log and the result of this method is a 716 | dictionary with EOF packet information. 717 | 718 | Returns a dict() 719 | """ 720 | return self._handle_eof(self._send_cmd(ServerCmd.DEBUG)) 721 | 722 | def cmd_ping(self): 723 | """Send the PING command 724 | 725 | This method sends the PING command to the MySQL server. It is used to 726 | check if the the connection is still valid. The result of this 727 | method is dictionary with OK packet information. 728 | 729 | Returns a dict() 730 | """ 731 | return self._handle_ok(self._send_cmd(ServerCmd.PING)) 732 | 733 | def cmd_change_user(self, username='', password='', database='', 734 | charset=33): 735 | """Change the current logged in user 736 | 737 | This method allows to change the current logged in user information. 738 | The result is a dictionary with OK packet information. 739 | 740 | Returns a dict() 741 | """ 742 | if self.unread_result: 743 | raise errors.InternalError("Unread result found.") 744 | 745 | packet = self._protocol.make_change_user( 746 | seed=self._handshake['scramble'], 747 | username=username, password=password, database=database, 748 | charset=charset, client_flags=self._client_flags) 749 | self._socket.send(packet, 0) 750 | return self._handle_ok(self._socket.recv()) 751 | 752 | def is_connected(self): 753 | """Reports whether the connection to MySQL Server is available 754 | 755 | This method checks whether the connection to MySQL is available. 756 | It is similar to ping(), but unlike the ping()-method, either True 757 | or False is returned and no exception is raised. 758 | 759 | Returns True or False. 760 | """ 761 | try: 762 | self.cmd_ping() 763 | except errors.Error: 764 | return False # This method does not raise 765 | return True 766 | 767 | def reconnect(self, attempts=1, delay=0): 768 | """Attempt to reconnect to the MySQL server 769 | 770 | The argument attempts should be the number of times a reconnect 771 | is tried. The delay argument is the number of seconds to wait between 772 | each retry. 773 | 774 | You may want to set the number of attempts higher and use delay when 775 | you expect the MySQL server to be down for maintenance or when you 776 | expect the network to be temporary unavailable. 777 | 778 | Raises InterfaceError on errors. 779 | """ 780 | counter = 0 781 | while counter != attempts: 782 | counter = counter + 1 783 | try: 784 | self.disconnect() 785 | self.connect() 786 | except Exception, err: 787 | if counter == attempts: 788 | raise errors.InterfaceError("Can not reconnect to MySQL " 789 | "after %d attempt(s): %s" % ( 790 | attempts, str(err))) 791 | if delay > 0: 792 | time.sleep(delay) 793 | 794 | def ping(self, reconnect=False, attempts=1, delay=0): 795 | """Check availability to the MySQL server 796 | 797 | When reconnect is set to True, one or more attempts are made to try 798 | to reconnect to the MySQL server using the reconnect()-method. 799 | 800 | delay is the number of seconds to wait between each retry. 801 | 802 | When the connection is not available, an InterfaceError is raised. Use 803 | the is_connected()-method if you just want to check the connection 804 | without raising an error. 805 | 806 | Raises InterfaceError on errors. 807 | """ 808 | try: 809 | self.cmd_ping() 810 | except errors.Error: 811 | if reconnect: 812 | self.reconnect(attempts=attempts, delay=delay) 813 | else: 814 | raise errors.InterfaceError("Connection to MySQL is" 815 | " not available.") 816 | 817 | def set_converter_class(self, convclass): 818 | """ 819 | Set the converter class to be used. This should be a class overloading 820 | methods and members of conversion.MySQLConverter. 821 | """ 822 | charset_name = CharacterSet.get_info(self._charset_id)[0] 823 | self._converter_class = convclass 824 | self.converter = convclass(charset_name, self._use_unicode) 825 | 826 | def get_server_version(self): 827 | """Get the MySQL version 828 | 829 | This method returns the MySQL server version as a tuple. If not 830 | perviously connected, it will return None. 831 | 832 | Returns a tuple or None. 833 | """ 834 | return self._server_version 835 | 836 | def get_server_info(self): 837 | """Get the original MySQL version information 838 | 839 | This method returns the original MySQL server as text. If not 840 | previously connected, it will return None. 841 | 842 | Returns a string or None. 843 | """ 844 | try: 845 | return self._handshake['server_version_original'] 846 | except (TypeError, KeyError): 847 | return None 848 | 849 | @property 850 | def connection_id(self): 851 | """MySQL connection ID""" 852 | try: 853 | return self._handshake['server_threadid'] 854 | except KeyError: 855 | return None 856 | 857 | def set_login(self, username=None, password=None): 858 | """Set login information for MySQL 859 | 860 | Set the username and/or password for the user connecting to 861 | the MySQL Server. 862 | """ 863 | if username is not None: 864 | self._user = username.strip() 865 | else: 866 | self._user = '' 867 | if password is not None: 868 | self._password = password.strip() 869 | else: 870 | self._password = '' 871 | 872 | def set_unicode(self, value=True): 873 | """Toggle unicode mode 874 | 875 | Set whether we return string fields as unicode or not. 876 | Default is True. 877 | """ 878 | self._use_unicode = value 879 | if self.converter: 880 | self.converter.set_unicode(value) 881 | 882 | def set_charset_collation(self, charset=None, collation=None): 883 | """Sets the character set and collation for the current connection 884 | 885 | This method sets the character set and collation to be used for 886 | the current connection. The charset argument can be either the 887 | name of a character set as a string, or the numerical equivalent 888 | as defined in constants.CharacterSet. 889 | 890 | When the collation is not given, the default will be looked up and 891 | used. 892 | 893 | For example, the following will set the collation for the latin1 894 | character set to latin1_general_ci: 895 | 896 | set_charset('latin1','latin1_general_ci') 897 | 898 | """ 899 | if charset: 900 | if isinstance(charset, int): 901 | self._charset_id = charset 902 | (charset_name, collation_name) = CharacterSet.get_info( 903 | self._charset_id) 904 | elif isinstance(charset, str): 905 | (self._charset_id, charset_name, collation_name) = \ 906 | CharacterSet.get_charset_info(charset, collation) 907 | else: 908 | raise ValueError( 909 | "charset should be either integer, string or None") 910 | elif collation: 911 | (self._charset_id, charset_name, collation_name) = \ 912 | CharacterSet.get_charset_info(collation=collation) 913 | 914 | self._execute_query("SET NAMES '%s' COLLATE '%s'" % ( 915 | charset_name, collation_name)) 916 | self.converter.set_charset(charset_name) 917 | 918 | @property 919 | def charset(self): 920 | """Returns the character set for current connection 921 | 922 | This property returns the character set name of the current connection. 923 | Note that the value returned is based on what is previously set by 924 | the set_charset_collation(). 925 | 926 | Returns a string. 927 | """ 928 | return CharacterSet.get_info(self._charset_id)[0] 929 | 930 | @property 931 | def collation(self): 932 | """Returns the collation for current connection 933 | 934 | This property returns the collation name of the current connection. 935 | Note that the value returned is based on what is previously set by 936 | the set_charset_collation(). 937 | 938 | Returns a string. 939 | """ 940 | return CharacterSet.get_charset_info(self._charset_id)[2] 941 | 942 | def set_client_flags(self, flags): 943 | """Set the client flags 944 | 945 | The flags-argument can be either an int or a list (or tuple) of 946 | ClientFlag-values. If it is an integer, it will set client_flags 947 | to flags as is. 948 | If flags is a list (or tuple), each flag will be set or unset 949 | when it's negative. 950 | 951 | set_client_flags([ClientFlag.FOUND_ROWS,-ClientFlag.LONG_FLAG]) 952 | 953 | Raises ProgrammingError when the flags argument is not a set or 954 | an integer bigger than 0. 955 | 956 | Returns self._client_flags 957 | """ 958 | if isinstance(flags, int) and flags > 0: 959 | self._client_flags = flags 960 | elif isinstance(flags, (tuple, list)): 961 | for flag in flags: 962 | if flag < 0: 963 | self._client_flags &= ~abs(flag) 964 | else: 965 | self._client_flags |= flag 966 | else: 967 | raise errors.ProgrammingError( 968 | "set_client_flags expect int (>0) or set") 969 | 970 | return self._client_flags 971 | 972 | def isset_client_flag(self, flag): 973 | """Check if a client flag is set""" 974 | if (self._client_flags & flag) > 0: 975 | return True 976 | return False 977 | 978 | @property 979 | def user(self): 980 | """User used while connecting to MySQL""" 981 | return self._user 982 | 983 | @property 984 | def server_host(self): 985 | """MySQL server IP address or name""" 986 | return self._host 987 | 988 | @property 989 | def server_port(self): 990 | "MySQL server TCP/IP port" 991 | return self._port 992 | 993 | @property 994 | def unix_socket(self): 995 | "MySQL Unix socket file location" 996 | return self._unix_socket 997 | 998 | def _set_unread_result(self, toggle): 999 | """Set whether there is an unread resultself._port 1000 | 1001 | This method is used by cursors to let other cursors know there is 1002 | still a result set that needs to be retrieved. 1003 | 1004 | Raises ValueError on errors. 1005 | """ 1006 | if not isinstance(toggle, bool): 1007 | raise ValueError("Expected a boolean type") 1008 | self._unread_result = toggle 1009 | 1010 | def _get_unread_result(self): 1011 | """Get whether there is an unread result 1012 | 1013 | This method is used by cursors to check whether another cursor still 1014 | needs to retrieve its result set. 1015 | 1016 | Returns True, or False when there is no unread result. 1017 | """ 1018 | return self._unread_result 1019 | 1020 | unread_result = property(_get_unread_result, _set_unread_result, 1021 | doc="Unread result for this MySQL connection") 1022 | 1023 | def set_database(self, value): 1024 | """Set the current database""" 1025 | self.cmd_query("USE %s" % value) 1026 | def get_database(self): 1027 | """Get the current database""" 1028 | return self._info_query("SELECT DATABASE()")[0] 1029 | database = property(get_database, set_database, 1030 | doc="Current database") 1031 | 1032 | def set_time_zone(self, value): 1033 | """Set the time zone""" 1034 | self.cmd_query("SET @@session.time_zone = '%s'" % value) 1035 | self._time_zone = value 1036 | def get_time_zone(self): 1037 | """Get the current time zone""" 1038 | return self._info_query("SELECT @@session.time_zone")[0] 1039 | time_zone = property(get_time_zone, set_time_zone, 1040 | doc="time_zone value for current MySQL session") 1041 | 1042 | def set_sql_mode(self, value): 1043 | """Set the SQL mode 1044 | 1045 | This method sets the SQL Mode for the current connection. The value 1046 | argument can be either a string with comma sepearate mode names, or 1047 | a sequence of mode names. 1048 | 1049 | It is good practice to use the constants class SQLMode: 1050 | from mysql.connector.constants import SQLMode 1051 | cnx.sql_mode = [SQLMode.NO_ZERO_DATE, SQLMode.REAL_AS_FLOAT] 1052 | """ 1053 | if isinstance(value, (list, tuple)): 1054 | value = ','.join(value) 1055 | self.cmd_query("SET @@session.sql_mode = '%s'" % value) 1056 | self._sql_mode = value 1057 | def get_sql_mode(self): 1058 | """Get the SQL mode""" 1059 | return self._info_query("SELECT @@session.sql_mode")[0] 1060 | sql_mode = property(get_sql_mode, set_sql_mode, 1061 | doc="sql_mode value for current MySQL session") 1062 | 1063 | def set_autocommit(self, value): 1064 | """Toggle autocommit""" 1065 | if value: 1066 | switch = 'ON' 1067 | else: 1068 | switch = 'OFF' 1069 | self._execute_query("SET @@session.autocommit = %s" % switch) 1070 | def get_autocommit(self): 1071 | """Get whether autocommit is on or off""" 1072 | value = self._info_query("SELECT @@session.autocommit")[0] 1073 | if value == 1: 1074 | return True 1075 | return False 1076 | autocommit = property(get_autocommit, set_autocommit, 1077 | doc="autocommit value for current MySQL session") 1078 | 1079 | def _set_getwarnings(self, toggle): 1080 | """Set whether warnings should be automatically retrieved 1081 | 1082 | The toggle-argument must be a boolean. When True, cursors for this 1083 | connection will retrieve information about warnings (if any). 1084 | 1085 | Raises ValueError on error. 1086 | """ 1087 | if not isinstance(toggle, bool): 1088 | raise ValueError("Expected a boolean type") 1089 | self._get_warnings = toggle 1090 | 1091 | def _get_getwarnings(self): 1092 | """Get whether this connection retrieves warnings automatically 1093 | 1094 | This method returns whether this connection retrieves warnings 1095 | automatically. 1096 | 1097 | Returns True, or False when warnings are not retrieved. 1098 | """ 1099 | return self._get_warnings 1100 | get_warnings = property(_get_getwarnings, _set_getwarnings, 1101 | doc="Toggle and check wheter to retrieve "\ 1102 | "warnings automatically") 1103 | 1104 | def _set_raise_on_warnings(self, toggle): 1105 | """Set whether warnings raise an error 1106 | 1107 | The toggle-argument must be a boolean. When True, cursors for this 1108 | connection will raise an error when MySQL reports warnings. 1109 | 1110 | Raising on warnings implies retrieving warnings automatically. In 1111 | other words: warnings will be set to True. If set to False, warnings 1112 | will be also set to False. 1113 | 1114 | Raises ValueError on error. 1115 | """ 1116 | if not isinstance(toggle, bool): 1117 | raise ValueError("Expected a boolean type") 1118 | self._raise_on_warnings = toggle 1119 | self._get_warnings = toggle 1120 | 1121 | def _get_raise_on_warnings(self): 1122 | """Get whether this connection raises an error on warnings 1123 | 1124 | This method returns whether this connection will raise errors when 1125 | MySQL reports warnings. 1126 | 1127 | Returns True or False. 1128 | """ 1129 | return self._raise_on_warnings 1130 | 1131 | raise_on_warnings = property(_get_raise_on_warnings, 1132 | _set_raise_on_warnings, 1133 | doc="Toggle wheter to raise on warnings "\ 1134 | "(emplies retrieving warnings).") 1135 | 1136 | def cursor(self, buffered=None, raw=None, cursor_class=None): 1137 | """Instantiates and returns a cursor 1138 | 1139 | By default, MySQLCursor is returned. Depending on the options 1140 | while connecting, a buffered and/or raw cursor instantiated 1141 | instead. 1142 | 1143 | It is possible to also give a custom cursor through the 1144 | cursor_class paramter, but it needs to be a subclass of 1145 | mysql.connector.cursor.CursorBase. 1146 | 1147 | Returns a cursor-object 1148 | """ 1149 | if not self.is_connected(): 1150 | raise errors.OperationalError("MySQL Connection not available.") 1151 | if cursor_class is not None: 1152 | if not issubclass(cursor_class, CursorBase): 1153 | raise errors.ProgrammingError( 1154 | "Cursor class needs to be subclass of cursor.CursorBase") 1155 | return (cursor_class)(self) 1156 | 1157 | buffered = buffered or self._buffered 1158 | raw = raw or self._raw 1159 | 1160 | cursor_type = 0 1161 | if buffered is True: 1162 | cursor_type |= 1 1163 | if raw is True: 1164 | cursor_type |= 2 1165 | 1166 | types = ( 1167 | MySQLCursor, # 0 1168 | MySQLCursorBuffered, 1169 | MySQLCursorRaw, 1170 | MySQLCursorBufferedRaw, 1171 | ) 1172 | return (types[cursor_type ])(self) 1173 | 1174 | def commit(self): 1175 | """Commit current transaction""" 1176 | self._execute_query("COMMIT") 1177 | 1178 | def rollback(self): 1179 | """Rollback current transaction""" 1180 | self._execute_query("ROLLBACK") 1181 | 1182 | def _execute_query(self, query): 1183 | """Execute a query 1184 | 1185 | This method simply calles cmd_query() after checking for unread 1186 | result. If there are still unread result, an errors.InterfaceError 1187 | is raised. Otherwise whatever cmd_query() returns is returned. 1188 | 1189 | Returns a dict() 1190 | """ 1191 | if self._unread_result is True: 1192 | raise errors.InternalError("Unread result found.") 1193 | 1194 | self.cmd_query(query) 1195 | 1196 | def _info_query(self, query): 1197 | """Send a query which only returns 1 row""" 1198 | cursor = self.cursor(buffered=True) 1199 | cursor.execute(query) 1200 | return cursor.fetchone() 1201 | 1202 | 1203 | -------------------------------------------------------------------------------- /constants.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Various MySQL constants and character sets 25 | """ 26 | 27 | from errors import ProgrammingError 28 | 29 | MAX_PACKET_LENGTH = 16777215 30 | RESULT_WITHOUT_ROWS = 0 31 | RESULT_WITH_ROWS = 1 32 | 33 | def flag_is_set(flag, flags): 34 | """Checks if the flag is set 35 | 36 | Returns boolean""" 37 | if (flags & flag) > 0: 38 | return True 39 | return False 40 | 41 | class _constants(object): 42 | 43 | prefix = '' 44 | desc = {} 45 | 46 | def __new__(cls): 47 | raise TypeError, "Can not instanciate from %s" % cls.__name__ 48 | 49 | @classmethod 50 | def get_desc(cls,name): 51 | try: 52 | return cls.desc[name][1] 53 | except: 54 | return None 55 | 56 | @classmethod 57 | def get_info(cls,n): 58 | for name, info in cls.desc.items(): 59 | if info[0] == n: 60 | return name 61 | return None 62 | 63 | @classmethod 64 | def get_full_info(cls): 65 | res = () 66 | try: 67 | res = ["%s : %s" % (k,v[1]) for k,v in cls.desc.items()] 68 | except StandardError, e: 69 | res = ('No information found in constant class.%s' % e) 70 | 71 | return res 72 | 73 | class _constantflags(_constants): 74 | 75 | @classmethod 76 | def get_bit_info(cls, v): 77 | """Get the name of all bits set 78 | 79 | Returns a list of strings.""" 80 | res = [] 81 | for name,d in cls.desc.items(): 82 | if v & d[0]: 83 | res.append(name) 84 | return res 85 | 86 | class FieldType(_constants): 87 | 88 | prefix = 'FIELD_TYPE_' 89 | DECIMAL = 0x00 90 | TINY = 0x01 91 | SHORT = 0x02 92 | LONG = 0x03 93 | FLOAT = 0x04 94 | DOUBLE = 0x05 95 | NULL = 0x06 96 | TIMESTAMP = 0x07 97 | LONGLONG = 0x08 98 | INT24 = 0x09 99 | DATE = 0x0a 100 | TIME = 0x0b 101 | DATETIME = 0x0c 102 | YEAR = 0x0d 103 | NEWDATE = 0x0e 104 | VARCHAR = 0x0f 105 | BIT = 0x10 106 | NEWDECIMAL = 0xf6 107 | ENUM = 0xf7 108 | SET = 0xf8 109 | TINY_BLOB = 0xf9 110 | MEDIUM_BLOB = 0xfa 111 | LONG_BLOB = 0xfb 112 | BLOB = 0xfc 113 | VAR_STRING = 0xfd 114 | STRING = 0xfe 115 | GEOMETRY = 0xff 116 | 117 | desc = { 118 | 'DECIMAL': (0x00, 'DECIMAL'), 119 | 'TINY': (0x01, 'TINY'), 120 | 'SHORT': (0x02, 'SHORT'), 121 | 'LONG': (0x03, 'LONG'), 122 | 'FLOAT': (0x04, 'FLOAT'), 123 | 'DOUBLE': (0x05, 'DOUBLE'), 124 | 'NULL': (0x06, 'NULL'), 125 | 'TIMESTAMP': (0x07, 'TIMESTAMP'), 126 | 'LONGLONG': (0x08, 'LONGLONG'), 127 | 'INT24': (0x09, 'INT24'), 128 | 'DATE': (0x0a, 'DATE'), 129 | 'TIME': (0x0b, 'TIME'), 130 | 'DATETIME': (0x0c, 'DATETIME'), 131 | 'YEAR': (0x0d, 'YEAR'), 132 | 'NEWDATE': (0x0e, 'NEWDATE'), 133 | 'VARCHAR': (0x0f, 'VARCHAR'), 134 | 'BIT': (0x10, 'BIT'), 135 | 'NEWDECIMAL': (0xf6, 'NEWDECIMAL'), 136 | 'ENUM': (0xf7, 'ENUM'), 137 | 'SET': (0xf8, 'SET'), 138 | 'TINY_BLOB': (0xf9, 'TINY_BLOB'), 139 | 'MEDIUM_BLOB': (0xfa, 'MEDIUM_BLOB'), 140 | 'LONG_BLOB': (0xfb, 'LONG_BLOB'), 141 | 'BLOB': (0xfc, 'BLOB'), 142 | 'VAR_STRING': (0xfd, 'VAR_STRING'), 143 | 'STRING': (0xfe, 'STRING'), 144 | 'GEOMETRY': (0xff, 'GEOMETRY'), 145 | } 146 | 147 | @classmethod 148 | def get_string_types(cls): 149 | return [ 150 | cls.VARCHAR, 151 | cls.ENUM, 152 | cls.VAR_STRING, cls.STRING, 153 | ] 154 | 155 | @classmethod 156 | def get_binary_types(cls): 157 | return [ 158 | cls.TINY_BLOB, cls.MEDIUM_BLOB, 159 | cls.LONG_BLOB, cls.BLOB, 160 | ] 161 | 162 | @classmethod 163 | def get_number_types(cls): 164 | return [ 165 | cls.DECIMAL, cls.NEWDECIMAL, 166 | cls.TINY, cls.SHORT, cls.LONG, 167 | cls.FLOAT, cls.DOUBLE, 168 | cls.LONGLONG, cls.INT24, 169 | cls.BIT, 170 | cls.YEAR, 171 | ] 172 | 173 | @classmethod 174 | def get_timestamp_types(cls): 175 | return [ 176 | cls.DATETIME, cls.TIMESTAMP, 177 | ] 178 | 179 | class FieldFlag(_constantflags): 180 | """ 181 | Field flags as found in MySQL sources mysql-src/include/mysql_com.h 182 | """ 183 | _prefix = '' 184 | NOT_NULL = 1 << 0 185 | PRI_KEY = 1 << 1 186 | UNIQUE_KEY = 1 << 2 187 | MULTIPLE_KEY = 1 << 3 188 | BLOB = 1 << 4 189 | UNSIGNED = 1 << 5 190 | ZEROFILL = 1 << 6 191 | BINARY = 1 << 7 192 | 193 | ENUM = 1 << 8 194 | AUTO_INCREMENT = 1 << 9 195 | TIMESTAMP = 1 << 10 196 | SET = 1 << 11 197 | 198 | NO_DEFAULT_VALUE = 1 << 12 199 | ON_UPDATE_NOW = 1 << 13 200 | NUM = 1 << 14 201 | PART_KEY = 1 << 15 202 | GROUP = 1 << 14 # SAME AS NUM !!!!!!!???? 203 | UNIQUE = 1 << 16 204 | BINCMP = 1 << 17 205 | 206 | GET_FIXED_FIELDS = 1 << 18 207 | FIELD_IN_PART_FUNC = 1 << 19 208 | FIELD_IN_ADD_INDEX = 1 << 20 209 | FIELD_IS_RENAMED = 1 << 21 210 | 211 | desc = { 212 | 'NOT_NULL': (1 << 0, "Field can't be NULL"), 213 | 'PRI_KEY': (1 << 1, "Field is part of a primary key"), 214 | 'UNIQUE_KEY': (1 << 2, "Field is part of a unique key"), 215 | 'MULTIPLE_KEY': (1 << 3, "Field is part of a key"), 216 | 'BLOB': (1 << 4, "Field is a blob"), 217 | 'UNSIGNED': (1 << 5, "Field is unsigned"), 218 | 'ZEROFILL': (1 << 6, "Field is zerofill"), 219 | 'BINARY': (1 << 7, "Field is binary "), 220 | 'ENUM': (1 << 8, "field is an enum"), 221 | 'AUTO_INCREMENT': (1 << 9, "field is a autoincrement field"), 222 | 'TIMESTAMP': (1 << 10, "Field is a timestamp"), 223 | 'SET': (1 << 11, "field is a set"), 224 | 'NO_DEFAULT_VALUE': (1 << 12, "Field doesn't have default value"), 225 | 'ON_UPDATE_NOW': (1 << 13, "Field is set to NOW on UPDATE"), 226 | 'NUM': (1 << 14, "Field is num (for clients)"), 227 | 228 | 'PART_KEY': (1 << 15, "Intern; Part of some key"), 229 | 'GROUP': (1 << 14, "Intern: Group field"), # Same as NUM 230 | 'UNIQUE': (1 << 16, "Intern: Used by sql_yacc"), 231 | 'BINCMP': (1 << 17, "Intern: Used by sql_yacc"), 232 | 'GET_FIXED_FIELDS': (1 << 18, "Used to get fields in item tree"), 233 | 'FIELD_IN_PART_FUNC': (1 << 19, "Field part of partition func"), 234 | 'FIELD_IN_ADD_INDEX': (1 << 20, "Intern: Field used in ADD INDEX"), 235 | 'FIELD_IS_RENAMED': (1 << 21, "Intern: Field is being renamed"), 236 | } 237 | 238 | class ServerCmd(_constants): 239 | _prefix = 'COM_' 240 | SLEEP = 0 241 | QUIT = 1 242 | INIT_DB = 2 243 | QUERY = 3 244 | FIELD_LIST = 4 245 | CREATE_DB = 5 246 | DROP_DB = 6 247 | REFRESH = 7 248 | SHUTDOWN = 8 249 | STATISTICS = 9 250 | PROCESS_INFO = 10 251 | CONNECT = 11 252 | PROCESS_KILL = 12 253 | DEBUG = 13 254 | PING = 14 255 | TIME = 15 256 | DELAYED_INSERT = 16 257 | CHANGE_USER = 17 258 | BINLOG_DUMP = 18 259 | TABLE_DUMP = 19 260 | CONNECT_OUT = 20 261 | REGISTER_SLAVE = 21 262 | STMT_PREPARE = 22 263 | STMT_EXECUTE = 23 264 | STMT_SEND_LONG_DATA = 24 265 | STMT_CLOSE = 25 266 | STMT_RESET = 26 267 | SET_OPTION = 27 268 | STMT_FETCH = 28 269 | DAEMON = 29 270 | 271 | desc = { 272 | 'SLEEP': (0,'SLEEP'), 273 | 'QUIT': (1,'QUIT'), 274 | 'INIT_DB': (2,'INIT_DB'), 275 | 'QUERY': (3,'QUERY'), 276 | 'FIELD_LIST': (4,'FIELD_LIST'), 277 | 'CREATE_DB': (5,'CREATE_DB'), 278 | 'DROP_DB': (6,'DROP_DB'), 279 | 'REFRESH': (7,'REFRESH'), 280 | 'SHUTDOWN': (8,'SHUTDOWN'), 281 | 'STATISTICS': (9,'STATISTICS'), 282 | 'PROCESS_INFO': (10,'PROCESS_INFO'), 283 | 'CONNECT': (11,'CONNECT'), 284 | 'PROCESS_KILL': (12,'PROCESS_KILL'), 285 | 'DEBUG': (13,'DEBUG'), 286 | 'PING': (14,'PING'), 287 | 'TIME': (15,'TIME'), 288 | 'DELAYED_INSERT': (16,'DELAYED_INSERT'), 289 | 'CHANGE_USER': (17,'CHANGE_USER'), 290 | 'BINLOG_DUMP': (18,'BINLOG_DUMP'), 291 | 'TABLE_DUMP': (19,'TABLE_DUMP'), 292 | 'CONNECT_OUT': (20,'CONNECT_OUT'), 293 | 'REGISTER_SLAVE': (21,'REGISTER_SLAVE'), 294 | 'STMT_PREPARE': (22,'STMT_PREPARE'), 295 | 'STMT_EXECUTE': (23,'STMT_EXECUTE'), 296 | 'STMT_SEND_LONG_DATA': (24,'STMT_SEND_LONG_DATA'), 297 | 'STMT_CLOSE': (25,'STMT_CLOSE'), 298 | 'STMT_RESET': (26,'STMT_RESET'), 299 | 'SET_OPTION': (27,'SET_OPTION'), 300 | 'STMT_FETCH': (28,'STMT_FETCH'), 301 | 'DAEMON': (29,'DAEMON'), 302 | } 303 | 304 | class ClientFlag(_constantflags): 305 | """ 306 | Client Options as found in the MySQL sources mysql-src/include/mysql_com.h 307 | """ 308 | LONG_PASSWD = 1 << 0 309 | FOUND_ROWS = 1 << 1 310 | LONG_FLAG = 1 << 2 311 | CONNECT_WITH_DB = 1 << 3 312 | NO_SCHEMA = 1 << 4 313 | COMPRESS = 1 << 5 314 | ODBC = 1 << 6 315 | LOCAL_FILES = 1 << 7 316 | IGNORE_SPACE = 1 << 8 317 | PROTOCOL_41 = 1 << 9 318 | INTERACTIVE = 1 << 10 319 | SSL = 1 << 11 320 | IGNORE_SIGPIPE = 1 << 12 321 | TRANSACTIONS = 1 << 13 322 | RESERVED = 1 << 14 323 | SECURE_CONNECTION = 1 << 15 324 | MULTI_STATEMENTS = 1 << 16 325 | MULTI_RESULTS = 1 << 17 326 | SSL_VERIFY_SERVER_CERT = 1 << 30 327 | REMEMBER_OPTIONS = 1 << 31 328 | 329 | desc = { 330 | 'LONG_PASSWD': (1 << 0, 'New more secure passwords'), 331 | 'FOUND_ROWS': (1 << 1, 'Found instead of affected rows'), 332 | 'LONG_FLAG': (1 << 2, 'Get all column flags'), 333 | 'CONNECT_WITH_DB': (1 << 3, 'One can specify db on connect'), 334 | 'NO_SCHEMA': (1 << 4, "Don't allow database.table.column"), 335 | 'COMPRESS': (1 << 5, 'Can use compression protocol'), 336 | 'ODBC': (1 << 6, 'ODBC client'), 337 | 'LOCAL_FILES': (1 << 7, 'Can use LOAD DATA LOCAL'), 338 | 'IGNORE_SPACE': (1 << 8, "Ignore spaces before ''"), 339 | 'PROTOCOL_41': (1 << 9, 'New 4.1 protocol'), 340 | 'INTERACTIVE': (1 << 10, 'This is an interactive client'), 341 | 'SSL': (1 << 11, 'Switch to SSL after handshake'), 342 | 'IGNORE_SIGPIPE': (1 << 12, 'IGNORE sigpipes'), 343 | 'TRANSACTIONS': (1 << 13, 'Client knows about transactions'), 344 | 'RESERVED': (1 << 14, 'Old flag for 4.1 protocol'), 345 | 'SECURE_CONNECTION': (1 << 15, 'New 4.1 authentication'), 346 | 'MULTI_STATEMENTS': (1 << 16, 'Enable/disable multi-stmt support'), 347 | 'MULTI_RESULTS': (1 << 17, 'Enable/disable multi-results'), 348 | 'SSL_VERIFY_SERVER_CERT': (1 << 30, ''), 349 | 'REMEMBER_OPTIONS': (1 << 31, ''), 350 | } 351 | 352 | default = [ 353 | LONG_PASSWD, 354 | LONG_FLAG, 355 | CONNECT_WITH_DB, 356 | PROTOCOL_41, 357 | TRANSACTIONS, 358 | SECURE_CONNECTION, 359 | MULTI_STATEMENTS, 360 | MULTI_RESULTS, 361 | ] 362 | 363 | @classmethod 364 | def get_default(cls): 365 | flags = 0 366 | for f in cls.default: 367 | flags |= f 368 | return flags 369 | 370 | class ServerFlag(_constantflags): 371 | """ 372 | Server flags as found in the MySQL sources mysql-src/include/mysql_com.h 373 | """ 374 | _prefix = 'SERVER_' 375 | STATUS_IN_TRANS = 1 << 0 376 | STATUS_AUTOCOMMIT = 1 << 1 377 | MORE_RESULTS_EXISTS = 1 << 3 378 | QUERY_NO_GOOD_INDEX_USED = 1 << 4 379 | QUERY_NO_INDEX_USED = 1 << 5 380 | STATUS_CURSOR_EXISTS = 1 << 6 381 | STATUS_LAST_ROW_SENT = 1 << 7 382 | STATUS_DB_DROPPED = 1 << 8 383 | STATUS_NO_BACKSLASH_ESCAPES = 1 << 9 384 | 385 | desc = { 386 | 'SERVER_STATUS_IN_TRANS': (1 << 0, 'Transaction has started'), 387 | 'SERVER_STATUS_AUTOCOMMIT': (1 << 1, 'Server in auto_commit mode'), 388 | 'SERVER_MORE_RESULTS_EXISTS': (1 << 3, 'Multi query - next query exists'), 389 | 'SERVER_QUERY_NO_GOOD_INDEX_USED': (1 << 4, ''), 390 | 'SERVER_QUERY_NO_INDEX_USED': (1 << 5, ''), 391 | 'SERVER_STATUS_CURSOR_EXISTS': (1 << 6, ''), 392 | 'SERVER_STATUS_LAST_ROW_SENT': (1 << 7, ''), 393 | 'SERVER_STATUS_DB_DROPPED': (1 << 8, 'A database was dropped'), 394 | 'SERVER_STATUS_NO_BACKSLASH_ESCAPES': (1 << 9, ''), 395 | } 396 | 397 | class RefreshOption(_constants): 398 | """Options used when sending the COM_REFRESH server command.""" 399 | 400 | _prefix = 'REFRESH_' 401 | GRANT = 1 << 0 402 | LOG = 1 << 1 403 | TABLES = 1 << 2 404 | HOST = 1 << 3 405 | STATUS = 1 << 4 406 | THREADS = 1 << 5 407 | SLAVE = 1 << 6 408 | 409 | desc = { 410 | 'GRANT': (1 << 0, 'Refresh grant tables'), 411 | 'LOG': (1 << 1, 'Start on new log file'), 412 | 'TABLES': (1 << 2, 'close all tables'), 413 | 'HOSTS': (1 << 3, 'Flush host cache'), 414 | 'STATUS': (1 << 4, 'Flush status variables'), 415 | 'THREADS': (1 << 5, 'Flush thread cache'), 416 | 'SLAVE': (1 << 6, 'Reset main info and restart subordinate thread'), 417 | } 418 | 419 | 420 | class ShutdownType(_constants): 421 | """Shutdown types used by the COM_SHUTDOWN server command.""" 422 | _prefix = '' 423 | SHUTDOWN_DEFAULT = 0 424 | SHUTDOWN_WAIT_CONNECTIONS = 1 425 | SHUTDOWN_WAIT_TRANSACTIONS = 2 426 | SHUTDOWN_WAIT_UPDATES = 8 427 | SHUTDOWN_WAIT_ALL_BUFFERS = 10 428 | SHUTDOWN_WAIT_CRITICAL_BUFFERS = 11 429 | KILL_QUERY = 254 430 | KILL_CONNECTION = 255 431 | 432 | desc = { 433 | 'SHUTDOWN_DEFAULT': (0, 434 | "defaults to SHUTDOWN_WAIT_ALL_BUFFERS"), 435 | 'SHUTDOWN_WAIT_CONNECTIONS': (1, 436 | "wait for existing connections to finish"), 437 | 'SHUTDOWN_WAIT_TRANSACTIONS': (2, 438 | "wait for existing trans to finish"), 439 | 'SHUTDOWN_WAIT_UPDATES': (8, 440 | "wait for existing updates to finish"), 441 | 'SHUTDOWN_WAIT_ALL_BUFFERS': (10, 442 | "flush InnoDB and other storage engine buffers"), 443 | 'SHUTDOWN_WAIT_CRITICAL_BUFFERS': (11, 444 | "don't flush InnoDB buffers, " 445 | "flush other storage engines' buffers"), 446 | 'KILL_QUERY': (254, "(no description)"), 447 | 'KILL_CONNECTION': (255, "(no description)"), 448 | } 449 | 450 | 451 | class CharacterSet(_constants): 452 | """MySQL supported character sets and collations 453 | 454 | List of character sets with their collations supported by MySQL. This 455 | maps to the character set we get from the server within the handshake 456 | packet. 457 | 458 | The list is hardcode so we avoid a database query when getting the 459 | name of the used character set or collation. 460 | """ 461 | 462 | desc = [ 463 | # (character set name, collation, default) 464 | None, 465 | ("big5","big5_chinese_ci",True), # 1 466 | ("latin2","latin2_czech_cs",False), # 2 467 | ("dec8","dec8_swedish_ci",True), # 3 468 | ("cp850","cp850_general_ci",True), # 4 469 | ("latin1","latin1_german1_ci",False), # 5 470 | ("hp8","hp8_english_ci",True), # 6 471 | ("koi8r","koi8r_general_ci",True), # 7 472 | ("latin1","latin1_swedish_ci",True), # 8 473 | ("latin2","latin2_general_ci",True), # 9 474 | ("swe7","swe7_swedish_ci",True), # 10 475 | ("ascii","ascii_general_ci",True), # 11 476 | ("ujis","ujis_japanese_ci",True), # 12 477 | ("sjis","sjis_japanese_ci",True), # 13 478 | ("cp1251","cp1251_bulgarian_ci",False), # 14 479 | ("latin1","latin1_danish_ci",False), # 15 480 | ("hebrew","hebrew_general_ci",True), # 16 481 | None, 482 | ("tis620","tis620_thai_ci",True), # 18 483 | ("euckr","euckr_korean_ci",True), # 19 484 | ("latin7","latin7_estonian_cs",False), # 20 485 | ("latin2","latin2_hungarian_ci",False), # 21 486 | ("koi8u","koi8u_general_ci",True), # 22 487 | ("cp1251","cp1251_ukrainian_ci",False), # 23 488 | ("gb2312","gb2312_chinese_ci",True), # 24 489 | ("greek","greek_general_ci",True), # 25 490 | ("cp1250","cp1250_general_ci",True), # 26 491 | ("latin2","latin2_croatian_ci",False), # 27 492 | ("gbk","gbk_chinese_ci",True), # 28 493 | ("cp1257","cp1257_lithuanian_ci",False), # 29 494 | ("latin5","latin5_turkish_ci",True), # 30 495 | ("latin1","latin1_german2_ci",False), # 31 496 | ("armscii8","armscii8_general_ci",True), # 32 497 | ("utf8","utf8_general_ci",True), # 33 498 | ("cp1250","cp1250_czech_cs",False), # 34 499 | ("ucs2","ucs2_general_ci",True), # 35 500 | ("cp866","cp866_general_ci",True), # 36 501 | ("keybcs2","keybcs2_general_ci",True), # 37 502 | ("macce","macce_general_ci",True), # 38 503 | ("macroman","macroman_general_ci",True), # 39 504 | ("cp852","cp852_general_ci",True), # 40 505 | ("latin7","latin7_general_ci",True), # 41 506 | ("latin7","latin7_general_cs",False), # 42 507 | ("macce","macce_bin",False), # 43 508 | ("cp1250","cp1250_croatian_ci",False), # 44 509 | None, 510 | None, 511 | ("latin1","latin1_bin",False), # 47 512 | ("latin1","latin1_general_ci",False), # 48 513 | ("latin1","latin1_general_cs",False), # 49 514 | ("cp1251","cp1251_bin",False), # 50 515 | ("cp1251","cp1251_general_ci",True), # 51 516 | ("cp1251","cp1251_general_cs",False), # 52 517 | ("macroman","macroman_bin",False), # 53 518 | None, 519 | None, 520 | None, 521 | ("cp1256","cp1256_general_ci",True), # 57 522 | ("cp1257","cp1257_bin",False), # 58 523 | ("cp1257","cp1257_general_ci",True), # 59 524 | None, 525 | None, 526 | None, 527 | ("binary","binary",True), # 63 528 | ("armscii8","armscii8_bin",False), # 64 529 | ("ascii","ascii_bin",False), # 65 530 | ("cp1250","cp1250_bin",False), # 66 531 | ("cp1256","cp1256_bin",False), # 67 532 | ("cp866","cp866_bin",False), # 68 533 | ("dec8","dec8_bin",False), # 69 534 | ("greek","greek_bin",False), # 70 535 | ("hebrew","hebrew_bin",False), # 71 536 | ("hp8","hp8_bin",False), # 72 537 | ("keybcs2","keybcs2_bin",False), # 73 538 | ("koi8r","koi8r_bin",False), # 74 539 | ("koi8u","koi8u_bin",False), # 75 540 | None, 541 | ("latin2","latin2_bin",False), # 77 542 | ("latin5","latin5_bin",False), # 78 543 | ("latin7","latin7_bin",False), # 79 544 | ("cp850","cp850_bin",False), # 80 545 | ("cp852","cp852_bin",False), # 81 546 | ("swe7","swe7_bin",False), # 82 547 | ("utf8","utf8_bin",False), # 83 548 | ("big5","big5_bin",False), # 84 549 | ("euckr","euckr_bin",False), # 85 550 | ("gb2312","gb2312_bin",False), # 86 551 | ("gbk","gbk_bin",False), # 87 552 | ("sjis","sjis_bin",False), # 88 553 | ("tis620","tis620_bin",False), # 89 554 | ("ucs2","ucs2_bin",False), # 90 555 | ("ujis","ujis_bin",False), # 91 556 | ("geostd8","geostd8_general_ci",True), # 92 557 | ("geostd8","geostd8_bin",False), # 93 558 | ("latin1","latin1_spanish_ci",False), # 94 559 | ("cp932","cp932_japanese_ci",True), # 95 560 | ("cp932","cp932_bin",False), # 96 561 | ("eucjpms","eucjpms_japanese_ci",True), # 97 562 | ("eucjpms","eucjpms_bin",False), # 98 563 | ("cp1250","cp1250_polish_ci",False), # 99 564 | None, 565 | None, 566 | None, 567 | None, 568 | None, 569 | None, 570 | None, 571 | None, 572 | None, 573 | None, 574 | None, 575 | None, 576 | None, 577 | None, 578 | None, 579 | None, 580 | None, 581 | None, 582 | None, 583 | None, 584 | None, 585 | None, 586 | None, 587 | None, 588 | None, 589 | None, 590 | None, 591 | None, 592 | ("ucs2","ucs2_unicode_ci",False), # 128 593 | ("ucs2","ucs2_icelandic_ci",False), # 129 594 | ("ucs2","ucs2_latvian_ci",False), # 130 595 | ("ucs2","ucs2_romanian_ci",False), # 131 596 | ("ucs2","ucs2_slovenian_ci",False), # 132 597 | ("ucs2","ucs2_polish_ci",False), # 133 598 | ("ucs2","ucs2_estonian_ci",False), # 134 599 | ("ucs2","ucs2_spanish_ci",False), # 135 600 | ("ucs2","ucs2_swedish_ci",False), # 136 601 | ("ucs2","ucs2_turkish_ci",False), # 137 602 | ("ucs2","ucs2_czech_ci",False), # 138 603 | ("ucs2","ucs2_danish_ci",False), # 139 604 | ("ucs2","ucs2_lithuanian_ci",False), # 140 605 | ("ucs2","ucs2_slovak_ci",False), # 141 606 | ("ucs2","ucs2_spanish2_ci",False), # 142 607 | ("ucs2","ucs2_roman_ci",False), # 143 608 | ("ucs2","ucs2_persian_ci",False), # 144 609 | ("ucs2","ucs2_esperanto_ci",False), # 145 610 | ("ucs2","ucs2_hungarian_ci",False), # 146 611 | None, 612 | None, 613 | None, 614 | None, 615 | None, 616 | None, 617 | None, 618 | None, 619 | None, 620 | None, 621 | None, 622 | None, 623 | None, 624 | None, 625 | None, 626 | None, 627 | None, 628 | None, 629 | None, 630 | None, 631 | None, 632 | None, 633 | None, 634 | None, 635 | None, 636 | None, 637 | None, 638 | None, 639 | None, 640 | None, 641 | None, 642 | None, 643 | None, 644 | None, 645 | None, 646 | None, 647 | None, 648 | None, 649 | None, 650 | None, 651 | None, 652 | None, 653 | None, 654 | None, 655 | None, 656 | ("utf8","utf8_unicode_ci",False), # 192 657 | ("utf8","utf8_icelandic_ci",False), # 193 658 | ("utf8","utf8_latvian_ci",False), # 194 659 | ("utf8","utf8_romanian_ci",False), # 195 660 | ("utf8","utf8_slovenian_ci",False), # 196 661 | ("utf8","utf8_polish_ci",False), # 197 662 | ("utf8","utf8_estonian_ci",False), # 198 663 | ("utf8","utf8_spanish_ci",False), # 199 664 | ("utf8","utf8_swedish_ci",False), # 200 665 | ("utf8","utf8_turkish_ci",False), # 201 666 | ("utf8","utf8_czech_ci",False), # 202 667 | ("utf8","utf8_danish_ci",False), # 203 668 | ("utf8","utf8_lithuanian_ci",False), # 204 669 | ("utf8","utf8_slovak_ci",False), # 205 670 | ("utf8","utf8_spanish2_ci",False), # 206 671 | ("utf8","utf8_roman_ci",False), # 207 672 | ("utf8","utf8_persian_ci",False), # 208 673 | ("utf8","utf8_esperanto_ci",False), # 209 674 | ("utf8","utf8_hungarian_ci",False), # 210 675 | ] 676 | 677 | @classmethod 678 | def get_info(cls,setid): 679 | """Retrieves character set information as tuple using an ID 680 | 681 | Retrieves character set and collation information based on the 682 | given MySQL ID. 683 | 684 | Returns a tuple. 685 | """ 686 | try: 687 | r = cls.desc[setid] 688 | if r is None: 689 | raise 690 | return r[0:2] 691 | except: 692 | raise ProgrammingError("Character set '%d' unsupported" % (setid)) 693 | 694 | @classmethod 695 | def get_desc(cls,setid): 696 | """Retrieves character set information as string using an ID 697 | 698 | Retrieves character set and collation information based on the 699 | given MySQL ID. 700 | 701 | Returns a tuple. 702 | """ 703 | try: 704 | return "%s/%s" % cls.get_info(setid) 705 | except: 706 | raise 707 | 708 | @classmethod 709 | def get_default_collation(cls, charset): 710 | """Retrieves the default collation for given character set 711 | 712 | Raises ProgrammingError when character set is not supported. 713 | 714 | Returns list (collation, charset, index) 715 | """ 716 | if isinstance(charset, int): 717 | try: 718 | c = cls.desc[charset] 719 | return c[1], c[0], charset 720 | except: 721 | ProgrammingError("Character set ID '%s' unsupported." % ( 722 | charset)) 723 | 724 | for cid, c in enumerate(cls.desc): 725 | if c is None: 726 | continue 727 | if c[0] == charset and c[2] is True: 728 | return c[1], c[0], cid 729 | 730 | raise ProgrammingError("Character set '%s' unsupported." % (charset)) 731 | 732 | @classmethod 733 | def get_charset_info(cls, charset=None, collation=None): 734 | """Get character set information using charset name and/or collation 735 | 736 | Retrieves character set and collation information given character 737 | set name and/or a collation name. 738 | If charset is an integer, it will look up the character set based 739 | on the MySQL's ID. 740 | For example: 741 | get_charset_info('utf8',None) 742 | get_charset_info(collation='utf8_general_ci') 743 | get_charset_info(47) 744 | 745 | Raises ProgrammingError when character set is not supported. 746 | 747 | Returns a tuple with (id, characterset name, collation) 748 | """ 749 | idx = None 750 | 751 | if isinstance(charset, int): 752 | try: 753 | info = cls.desc[charset] 754 | return (charset, info[0], info[1]) 755 | except IndexError: 756 | ProgrammingError("Character set ID %s unknown." % (charset)) 757 | 758 | if charset is not None and collation is None: 759 | info = cls.get_default_collation(charset) 760 | return (info[2], info[1], info[0]) 761 | elif charset is None and collation is not None: 762 | for cid, info in enumerate(cls.desc): 763 | if info is None: 764 | continue 765 | if collation == info[1]: 766 | return (cid, info[0], info[1]) 767 | raise ProgrammingError("Collation '%s' unknown." % (collation)) 768 | else: 769 | for cid, info in enumerate(cls.desc): 770 | if info is None: 771 | continue 772 | if info[0] == charset and info[1] == collation: 773 | return (cid, info[0], info[1]) 774 | raise ProgrammingError("Character set '%s' unknown." % (charset)) 775 | 776 | @classmethod 777 | def get_supported(cls): 778 | """Retrieves a list with names of all supproted character sets 779 | 780 | Returns a tuple. 781 | """ 782 | res = [] 783 | for info in cls.desc: 784 | if info and info[0] not in res: 785 | res.append(info[0]) 786 | return tuple(res) 787 | 788 | class SQLMode(_constants): 789 | """MySQL SQL Modes 790 | 791 | The numeric values of SQL Modes are not interesting, only the names 792 | are used when setting the SQL_MODE system variable using the MySQL 793 | SET command. 794 | 795 | See http://dev.mysql.com/doc/refman/5.6/en/server-sql-mode.html 796 | """ 797 | _prefix = 'MODE_' 798 | REAL_AS_FLOAT = 'REAL_AS_FLOAT' 799 | PIPES_AS_CONCAT = 'PIPES_AS_CONCAT' 800 | ANSI_QUOTES = 'ANSI_QUOTES' 801 | IGNORE_SPACE = 'IGNORE_SPACE' 802 | NOT_USED = 'NOT_USED' 803 | ONLY_FULL_GROUP_BY = 'ONLY_FULL_GROUP_BY' 804 | NO_UNSIGNED_SUBTRACTION = 'NO_UNSIGNED_SUBTRACTION' 805 | NO_DIR_IN_CREATE = 'NO_DIR_IN_CREATE' 806 | POSTGRESQL = 'POSTGRESQL' 807 | ORACLE = 'ORACLE' 808 | MSSQL = 'MSSQL' 809 | DB2 = 'DB2' 810 | MAXDB = 'MAXDB' 811 | NO_KEY_OPTIONS = 'NO_KEY_OPTIONS' 812 | NO_TABLE_OPTIONS = 'NO_TABLE_OPTIONS' 813 | NO_FIELD_OPTIONS = 'NO_FIELD_OPTIONS' 814 | MYSQL323 = 'MYSQL323' 815 | MYSQL40 = 'MYSQL40' 816 | ANSI = 'ANSI' 817 | NO_AUTO_VALUE_ON_ZERO = 'NO_AUTO_VALUE_ON_ZERO' 818 | NO_BACKSLASH_ESCAPES = 'NO_BACKSLASH_ESCAPES' 819 | STRICT_TRANS_TABLES = 'STRICT_TRANS_TABLES' 820 | STRICT_ALL_TABLES = 'STRICT_ALL_TABLES' 821 | NO_ZERO_IN_DATE = 'NO_ZERO_IN_DATE' 822 | NO_ZERO_DATE = 'NO_ZERO_DATE' 823 | INVALID_DATES = 'INVALID_DATES' 824 | ERROR_FOR_DIVISION_BY_ZERO = 'ERROR_FOR_DIVISION_BY_ZERO' 825 | TRADITIONAL = 'TRADITIONAL' 826 | NO_AUTO_CREATE_USER = 'NO_AUTO_CREATE_USER' 827 | HIGH_NOT_PRECEDENCE = 'HIGH_NOT_PRECEDENCE' 828 | NO_ENGINE_SUBSTITUTION = 'NO_ENGINE_SUBSTITUTION' 829 | PAD_CHAR_TO_FULL_LENGTH = 'PAD_CHAR_TO_FULL_LENGTH' 830 | 831 | @classmethod 832 | def get_desc(cls, name): 833 | raise NotImplementedError 834 | 835 | @classmethod 836 | def get_info(cls, number): 837 | raise NotImplementedError 838 | 839 | @classmethod 840 | def get_full_info(cls): 841 | """Returns a sequence of all availble SQL Modes 842 | 843 | This class method returns a tuple containing all SQL Mode names. The 844 | names will be alphabetically sorted. 845 | 846 | Returns a tuple. 847 | """ 848 | res = [] 849 | for key in vars(cls).keys(): 850 | if not key.startswith('_') and not callable(getattr(cls, key)): 851 | res.append(key) 852 | return tuple(sorted(res)) 853 | 854 | -------------------------------------------------------------------------------- /conversion.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Converting MySQL and Python types 25 | """ 26 | 27 | import struct 28 | import datetime 29 | import time 30 | from decimal import Decimal 31 | 32 | import errors 33 | from constants import FieldType, FieldFlag 34 | 35 | class ConverterBase(object): 36 | 37 | def __init__(self, charset='utf8', use_unicode=True): 38 | self.python_types = None 39 | self.mysql_types = None 40 | self.set_charset(charset) 41 | self.set_unicode(use_unicode) 42 | 43 | def set_charset(self, charset): 44 | if charset is not None: 45 | self.charset = charset 46 | else: 47 | # default to utf8 48 | self.charset = 'utf8' 49 | 50 | def set_unicode(self, value=True): 51 | self.use_unicode = value 52 | 53 | def to_mysql(self, value): 54 | return value 55 | 56 | def to_python(self, vtype, value): 57 | return value 58 | 59 | def escape(self, buf): 60 | return buf 61 | 62 | def quote(self, buf): 63 | return str(buf) 64 | 65 | class MySQLConverter(ConverterBase): 66 | """ 67 | A converted class grouping: 68 | o escape method: for escpaing values send to MySQL 69 | o quoting method: for quoting values send to MySQL in statements 70 | o conversion mapping: maps Python and MySQL data types to 71 | function for converting them. 72 | 73 | This class should be overloaded whenever one needs differences 74 | in how values are to be converted. Each MySQLConnection object 75 | has a default_converter property, which can be set like 76 | MySQL.converter(CustomMySQLConverter) 77 | 78 | """ 79 | def __init__(self, charset=None, use_unicode=True): 80 | ConverterBase.__init__(self, charset, use_unicode) 81 | 82 | def escape(self, value): 83 | """ 84 | Escapes special characters as they are expected to by when MySQL 85 | receives them. 86 | As found in MySQL source mysys/charset.c 87 | 88 | Returns the value if not a string, or the escaped string. 89 | """ 90 | if value is None: 91 | return value 92 | elif isinstance(value, (int,float,long,Decimal)): 93 | return value 94 | res = value 95 | res = res.replace('\\','\\\\') 96 | res = res.replace('\n','\\n') 97 | res = res.replace('\r','\\r') 98 | res = res.replace('\047','\134\047') # single quotes 99 | res = res.replace('\042','\134\042') # double quotes 100 | res = res.replace('\032','\134\032') # for Win32 101 | return res 102 | 103 | def quote(self, buf): 104 | """ 105 | Quote the parameters for commands. General rules: 106 | o numbers are returns as str type (because operation expect it) 107 | o None is returned as str('NULL') 108 | o String are quoted with single quotes '' 109 | 110 | Returns a string. 111 | """ 112 | if isinstance(buf, (int,float,long,Decimal)): 113 | return str(buf) 114 | elif isinstance(buf, type(None)): 115 | return "NULL" 116 | else: 117 | # Anything else would be a string 118 | return "'%s'" % buf 119 | 120 | def to_mysql(self, value): 121 | type_name = value.__class__.__name__.lower() 122 | return getattr(self, "_%s_to_mysql" % str(type_name))(value) 123 | 124 | def _int_to_mysql(self, value): 125 | return int(value) 126 | 127 | def _long_to_mysql(self, value): 128 | return long(value) 129 | 130 | def _float_to_mysql(self, value): 131 | return float(value) 132 | 133 | def _str_to_mysql(self, value): 134 | return str(value) 135 | 136 | def _unicode_to_mysql(self, value): 137 | """ 138 | Encodes value, a Python unicode string, to whatever the 139 | character set for this converter is set too. 140 | """ 141 | return value.encode(self.charset) 142 | 143 | def _bool_to_mysql(self, value): 144 | if value: 145 | return 1 146 | else: 147 | return 0 148 | 149 | def _nonetype_to_mysql(self, value): 150 | """ 151 | This would return what None would be in MySQL, but instead we 152 | leave it None and return it right away. The actual conversion 153 | from None to NULL happens in the quoting functionality. 154 | 155 | Return None. 156 | """ 157 | return None 158 | 159 | def _datetime_to_mysql(self, value): 160 | """ 161 | Converts a datetime instance to a string suitable for MySQL. 162 | The returned string has format: %Y-%m-%d %H:%M:%S[.%f] 163 | 164 | If the instance isn't a datetime.datetime type, it return None. 165 | 166 | Returns a string. 167 | """ 168 | if value.microsecond: 169 | return '%d-%02d-%02d %02d:%02d:%02d.%06d' % ( 170 | value.year, value.month, value.day, 171 | value.hour, value.minute, value.second, 172 | value.microsecond) 173 | return '%d-%02d-%02d %02d:%02d:%02d' % ( 174 | value.year, value.month, value.day, 175 | value.hour, value.minute, value.second) 176 | 177 | def _date_to_mysql(self, value): 178 | """ 179 | Converts a date instance to a string suitable for MySQL. 180 | The returned string has format: %Y-%m-%d 181 | 182 | If the instance isn't a datetime.date type, it return None. 183 | 184 | Returns a string. 185 | """ 186 | return '%d-%02d-%02d' % (value.year, value.month, value.day) 187 | 188 | def _time_to_mysql(self, value): 189 | """ 190 | Converts a time instance to a string suitable for MySQL. 191 | The returned string has format: %H:%M:%S[.%f] 192 | 193 | If the instance isn't a datetime.time type, it return None. 194 | 195 | Returns a string or None when not valid. 196 | """ 197 | if value.microsecond: 198 | return value.strftime('%H:%M:%S.%%06d') % value.microsecond 199 | return value.strftime('%H:%M:%S') 200 | 201 | def _struct_time_to_mysql(self, value): 202 | """ 203 | Converts a time.struct_time sequence to a string suitable 204 | for MySQL. 205 | The returned string has format: %Y-%m-%d %H:%M:%S 206 | 207 | Returns a string or None when not valid. 208 | """ 209 | return time.strftime('%Y-%m-%d %H:%M:%S', value) 210 | 211 | def _timedelta_to_mysql(self, value): 212 | """ 213 | Converts a timedelta instance to a string suitable for MySQL. 214 | The returned string has format: %H:%M:%S 215 | 216 | Returns a string. 217 | """ 218 | (hours, r) = divmod(value.seconds, 3600) 219 | (mins, secs) = divmod(r, 60) 220 | hours = hours + (value.days * 24) 221 | if value.microseconds: 222 | return '%02d:%02d:%02d.%06d' % (hours, mins, secs, 223 | value.microseconds) 224 | return '%02d:%02d:%02d' % (hours, mins, secs) 225 | 226 | def _decimal_to_mysql(self, value): 227 | """ 228 | Converts a decimal.Decimal instance to a string suitable for 229 | MySQL. 230 | 231 | Returns a string or None when not valid. 232 | """ 233 | if isinstance(value, Decimal): 234 | return str(value) 235 | 236 | return None 237 | 238 | def to_python(self, flddsc, value): 239 | """ 240 | Converts a given value coming from MySQL to a certain type in Python. 241 | The flddsc contains additional information for the field in the 242 | table. It's an element from MySQLCursor.description. 243 | 244 | Returns a mixed value. 245 | """ 246 | res = value 247 | 248 | if value == '\x00' and flddsc[1] != FieldType.BIT: 249 | # Don't go further when we hit a NULL value 250 | return None 251 | if value is None: 252 | return None 253 | 254 | type_name = FieldType.get_info(flddsc[1]) 255 | try: 256 | return getattr(self, '_%s_to_python' % type_name)(value, flddsc) 257 | except KeyError: 258 | # If one type is not defined, we just return the value as str 259 | return str(value) 260 | except ValueError, e: 261 | raise ValueError, "%s (field %s)" % (e, flddsc[0]) 262 | except TypeError, e: 263 | raise TypeError, "%s (field %s)" % (e, flddsc[0]) 264 | except: 265 | raise 266 | 267 | def _FLOAT_to_python(self, v, desc=None): 268 | """ 269 | Returns v as float type. 270 | """ 271 | return float(v) 272 | _DOUBLE_to_python = _FLOAT_to_python 273 | 274 | def _INT_to_python(self, v, desc=None): 275 | """ 276 | Returns v as int type. 277 | """ 278 | return int(v) 279 | _TINY_to_python = _INT_to_python 280 | _SHORT_to_python = _INT_to_python 281 | _INT24_to_python = _INT_to_python 282 | 283 | def _LONG_to_python(self, v, desc=None): 284 | """ 285 | Returns v as long type. 286 | """ 287 | return int(v) 288 | _LONGLONG_to_python = _LONG_to_python 289 | 290 | def _DECIMAL_to_python(self, v, desc=None): 291 | """ 292 | Returns v as a decimal.Decimal. 293 | """ 294 | return Decimal(v) 295 | _NEWDECIMAL_to_python = _DECIMAL_to_python 296 | 297 | def _str(self, v, desc=None): 298 | """ 299 | Returns v as str type. 300 | """ 301 | return str(v) 302 | 303 | def _BIT_to_python(self, v, dsc=None): 304 | """Returns BIT columntype as integer""" 305 | s = v 306 | if len(s) < 8: 307 | s = '\x00'*(8-len(s)) + s 308 | return struct.unpack('>Q', s)[0] 309 | 310 | def _DATE_to_python(self, v, dsc=None): 311 | """ 312 | Returns DATE column type as datetime.date type. 313 | """ 314 | pv = None 315 | try: 316 | pv = datetime.date(*[ int(s) for s in v.split('-')]) 317 | except ValueError: 318 | return None 319 | else: 320 | return pv 321 | _NEWDATE_to_python = _DATE_to_python 322 | 323 | def _TIME_to_python(self, v, dsc=None): 324 | """ 325 | Returns TIME column type as datetime.time type. 326 | """ 327 | pv = None 328 | try: 329 | (hms, fs) = v.split('.') 330 | fs = int(fs.ljust(6, '0')) 331 | except ValueError: 332 | hms = v 333 | fs = 0 334 | try: 335 | (h, m, s) = [ int(d) for d in hms.split(':')] 336 | pv = datetime.timedelta(hours=h, minutes=m, seconds=s, 337 | microseconds=fs) 338 | except ValueError, err: 339 | raise ValueError( 340 | "Could not convert %s to python datetime.timedelta" % v) 341 | else: 342 | return pv 343 | 344 | def _DATETIME_to_python(self, v, dsc=None): 345 | """ 346 | Returns DATETIME column type as datetime.datetime type. 347 | """ 348 | pv = None 349 | try: 350 | (sd, st) = v.split(' ') 351 | if len(st) > 8: 352 | (hms, fs) = st.split('.') 353 | fs = int(fs.ljust(6, '0')) 354 | else: 355 | hms = st 356 | fs = 0 357 | dt = [ int(v) for v in sd.split('-') ] +\ 358 | [ int(v) for v in hms.split(':') ] + [fs,] 359 | pv = datetime.datetime(*dt) 360 | except ValueError: 361 | pv = None 362 | 363 | return pv 364 | _TIMESTAMP_to_python = _DATETIME_to_python 365 | 366 | def _YEAR_to_python(self, v, desc=None): 367 | """Returns YEAR column type as integer""" 368 | try: 369 | year = int(v) 370 | except ValueError: 371 | raise ValueError("Failed converting YEAR to int (%s)" % v) 372 | 373 | return year 374 | 375 | def _SET_to_python(self, v, dsc=None): 376 | """Returns SET column typs as set 377 | 378 | Actually, MySQL protocol sees a SET as a string type field. So this 379 | code isn't called directly, but used by STRING_to_python() method. 380 | 381 | Returns SET column type as a set. 382 | """ 383 | pv = None 384 | try: 385 | pv = set(v.split(',')) 386 | except ValueError: 387 | raise ValueError, "Could not convert SET %s to a set." % v 388 | return pv 389 | 390 | def _STRING_to_python(self, v, dsc=None): 391 | """ 392 | Note that a SET is a string too, but using the FieldFlag we can see 393 | whether we have to split it. 394 | 395 | Returns string typed columns as string type. 396 | """ 397 | if dsc is not None: 398 | # Check if we deal with a SET 399 | if dsc[7] & FieldFlag.SET: 400 | return self._SET_to_python(v, dsc) 401 | if dsc[7] & FieldFlag.BINARY: 402 | return v 403 | 404 | if self.use_unicode: 405 | try: 406 | return unicode(v, self.charset) 407 | except: 408 | raise 409 | return str(v) 410 | _VAR_STRING_to_python = _STRING_to_python 411 | 412 | def _BLOB_to_python(self, v, dsc=None): 413 | if dsc is not None: 414 | if dsc[7] & FieldFlag.BINARY: 415 | return v 416 | 417 | return self._STRING_to_python(v, dsc) 418 | _LONG_BLOB_to_python = _BLOB_to_python 419 | _MEDIUM_BLOB_to_python = _BLOB_to_python 420 | _TINY_BLOB_to_python = _BLOB_to_python 421 | -------------------------------------------------------------------------------- /cursor.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Cursor classes 25 | """ 26 | 27 | import sys 28 | import weakref 29 | import re 30 | import itertools 31 | 32 | import errors 33 | 34 | RE_SQL_COMMENT = re.compile("\/\*.*\*\/") 35 | RE_SQL_INSERT_VALUES = re.compile( 36 | r'VALUES\s*(\(\s*(?:%(?:\(.*\)|)s\s*(?:,|)\s*)+\))', 37 | re.I | re.M) 38 | RE_SQL_INSERT_STMT = re.compile(r'INSERT\s+INTO', re.I) 39 | RE_SQL_SPLIT_STMTS = re.compile( 40 | r''';(?=(?:[^"'`]*["'`][^"'`]*["'`])*[^"'`]*$)''') 41 | 42 | class CursorBase(object): 43 | """ 44 | Base for defining MySQLCursor. This class is a skeleton and defines 45 | methods and members as required for the Python Database API 46 | Specification v2.0. 47 | 48 | It's better to inherite from MySQLCursor. 49 | """ 50 | 51 | def __init__(self): 52 | self._description = None 53 | self._rowcount = -1 54 | self._last_insert_id = None 55 | self.arraysize = 1 56 | 57 | def callproc(self, procname, args=()): 58 | pass 59 | 60 | def close(self): 61 | pass 62 | 63 | def execute(self, operation, params=()): 64 | pass 65 | 66 | def executemany(self, operation, seqparams): 67 | pass 68 | 69 | def fetchone(self): 70 | pass 71 | 72 | def fetchmany(self, size=1): 73 | pass 74 | 75 | def fetchall(self): 76 | pass 77 | 78 | def nextset(self): 79 | pass 80 | 81 | def setinputsizes(self, sizes): 82 | pass 83 | 84 | def setoutputsize(self, size, column=None): 85 | pass 86 | 87 | def reset(self): 88 | pass 89 | 90 | @property 91 | def description(self): 92 | """Returns description of columns in a result 93 | 94 | This property returns a list of tuples describing the columns in 95 | in a result set. A tuple is described as follows:: 96 | 97 | (column_name, 98 | type, 99 | None, 100 | None, 101 | None, 102 | None, 103 | null_ok, 104 | column_flags) # Addition to PEP-249 specs 105 | 106 | Returns a list of tuples. 107 | """ 108 | return self._description 109 | 110 | @property 111 | def rowcount(self): 112 | """Returns the number of rows produced or affected 113 | 114 | This property returns the number of rows produced by queries 115 | such as a SELECT, or affected rows when executing DML statements 116 | like INSERT or UPDATE. 117 | 118 | Note that for non-buffered cursors it is impossible to know the 119 | number of rows produced before having fetched them all. For those, 120 | the number of rows will be -1 right after execution, and 121 | incremented when fetching rows. 122 | 123 | Returns an integer. 124 | """ 125 | return self._rowcount 126 | 127 | @property 128 | def lastrowid(self): 129 | """Returns the value generated for an AUTO_INCREMENT column 130 | 131 | Returns the value generated for an AUTO_INCREMENT column by 132 | the previous INSERT or UPDATE statement or None when there is 133 | no such value available. 134 | 135 | Returns a long value or None. 136 | """ 137 | return self._last_insert_id 138 | 139 | class MySQLCursor(CursorBase): 140 | """Default cursor for interacting with MySQL 141 | 142 | This cursor will execute statements and handle the result. It will 143 | not automatically fetch all rows. 144 | 145 | MySQLCursor should be inherited whenever other functionallity is 146 | required. An example would to change the fetch* member functions 147 | to return dictionaries instead of lists of values. 148 | 149 | Implements the Python Database API Specification v2.0 (PEP-249) 150 | """ 151 | def __init__(self, connection=None): 152 | CursorBase.__init__(self) 153 | self._connection = None 154 | self._stored_results = [] 155 | self._nextrow = (None, None) 156 | self._warnings = None 157 | self._warning_count = 0 158 | self._executed = None 159 | self._executed_list = [] 160 | 161 | if connection is not None: 162 | self._set_connection(connection) 163 | 164 | def __iter__(self): 165 | """ 166 | Iteration over the result set which calls self.fetchone() 167 | and returns the next row. 168 | """ 169 | return iter(self.fetchone, None) 170 | 171 | def _set_connection(self, connection): 172 | try: 173 | self._connection = weakref.proxy(connection) 174 | self._connection._protocol 175 | except (AttributeError, TypeError): 176 | raise errors.InterfaceError(errno=2048) 177 | 178 | def _reset_result(self): 179 | self._rowcount = -1 180 | self._lastrowid = None 181 | self._nextrow = (None, None) 182 | self._stored_results = [] 183 | self._warnings = None 184 | self._warning_count = 0 185 | self._description = None 186 | self._executed = None 187 | self._executed_list = [] 188 | self.reset() 189 | 190 | def _have_unread_result(self): 191 | """Check whether there is an unread result""" 192 | try: 193 | return self._connection.unread_result 194 | except AttributeError: 195 | return False 196 | 197 | def next(self): 198 | """ 199 | Used for iterating over the result set. Calles self.fetchone() 200 | to get the next row. 201 | """ 202 | try: 203 | row = self.fetchone() 204 | except errors.InterfaceError: 205 | raise StopIteration 206 | if not row: 207 | raise StopIteration 208 | return row 209 | 210 | def close(self): 211 | """Close the cursor 212 | 213 | Returns True when successful, otherwise False. 214 | """ 215 | if self._connection is None: 216 | return False 217 | 218 | self._reset_result() 219 | self._connection = None 220 | 221 | return True 222 | 223 | def _process_params_dict(self, params): 224 | try: 225 | to_mysql = self._connection.converter.to_mysql 226 | escape = self._connection.converter.escape 227 | quote = self._connection.converter.quote 228 | res = {} 229 | for k,v in params.items(): 230 | c = v 231 | c = to_mysql(c) 232 | c = escape(c) 233 | c = quote(c) 234 | res[k] = c 235 | except StandardError, e: 236 | raise errors.ProgrammingError( 237 | "Failed processing pyformat-parameters; %s" % e) 238 | else: 239 | return res 240 | 241 | return None 242 | 243 | def _process_params(self, params): 244 | """ 245 | Process the parameters which were given when self.execute() was 246 | called. It does following using the MySQLConnection converter: 247 | * Convert Python types to MySQL types 248 | * Escapes characters required for MySQL. 249 | * Quote values when needed. 250 | 251 | Returns a list. 252 | """ 253 | if isinstance(params,dict): 254 | return self._process_params_dict(params) 255 | 256 | try: 257 | res = params 258 | res = map(self._connection.converter.to_mysql,res) 259 | res = map(self._connection.converter.escape,res) 260 | res = map(self._connection.converter.quote,res) 261 | except StandardError, e: 262 | raise errors.ProgrammingError( 263 | "Failed processing format-parameters; %s" % e) 264 | else: 265 | return tuple(res) 266 | return None 267 | 268 | def _row_to_python(self, rowdata, desc=None): 269 | res = () 270 | try: 271 | if not desc: 272 | desc = self.description 273 | for idx,v in enumerate(rowdata): 274 | flddsc = desc[idx] 275 | res += (self._connection.converter.to_python(flddsc, v),) 276 | except StandardError, e: 277 | raise errors.InterfaceError( 278 | "Failed converting row to Python types; %s" % e) 279 | else: 280 | return res 281 | 282 | return None 283 | 284 | def _handle_noresultset(self, res): 285 | """Handles result of execute() when there is no result set 286 | """ 287 | try: 288 | self._rowcount = res['affected_rows'] 289 | self._last_insert_id = res['insert_id'] 290 | self._warning_count = res['warning_count'] 291 | except (KeyError, TypeError), err: 292 | raise errors.ProgrammingError( 293 | "Failed handling non-resultset; %s" % err) 294 | 295 | if self._connection.get_warnings is True and self._warning_count: 296 | self._warnings = self._fetch_warnings() 297 | 298 | def _handle_resultset(self): 299 | pass 300 | 301 | def _handle_result(self, result): 302 | """ 303 | Handle the result after a command was send. The result can be either 304 | an OK-packet or a dictionary containing column/eof information. 305 | 306 | Raises InterfaceError when result is not a dict() or result is 307 | invalid. 308 | """ 309 | if not isinstance(result, dict): 310 | raise errors.InterfaceError('Result was not a dict()') 311 | 312 | if 'columns' in result: 313 | # Weak test, must be column/eof information 314 | self._description = result['columns'] 315 | self._connection.unread_result = True 316 | self._handle_resultset() 317 | elif 'affected_rows' in result: 318 | # Weak test, must be an OK-packet 319 | self._connection.unread_result = False 320 | self._handle_noresultset(result) 321 | else: 322 | raise errors.InterfaceError('Invalid result') 323 | 324 | def _execute_iter(self, query_iter): 325 | """Generator returns MySQLCursor objects for multiple statements 326 | 327 | This method is only used when multiple statements are executed 328 | by the execute() method. It uses itertools.izip to iterate over the 329 | given query_iter (result of MySQLConnection.cmd_query_iter()) and 330 | the list of statements that were executed. 331 | 332 | Yields a MySQLCursor instance. 333 | """ 334 | if not self._executed_list: 335 | self._executed_list = RE_SQL_SPLIT_STMTS.split(self._executed) 336 | 337 | for result, stmt in itertools.izip(query_iter, 338 | iter(self._executed_list)): 339 | self._reset_result() 340 | self._handle_result(result) 341 | self._executed = stmt 342 | yield self 343 | 344 | def execute(self, operation, params=None, multi=False): 345 | """Executes the given operation 346 | 347 | Executes the given operation substituting any markers with 348 | the given parameters. 349 | 350 | For example, getting all rows where id is 5: 351 | cursor.execute("SELECT * FROM t1 WHERE id = %s", (5,)) 352 | 353 | The multi argument should be set to True when executing multiple 354 | statements in one operation. If not set and multiple results are 355 | found, an InterfaceError will be raised. 356 | 357 | If warnings where generated, and connection.get_warnings is True, then 358 | self._warnings will be a list containing these warnings. 359 | 360 | Returns an iterator when multi is True, otherwise None. 361 | """ 362 | if not operation: 363 | return 364 | if self._have_unread_result(): 365 | raise errors.InternalError("Unread result found.") 366 | 367 | self._reset_result() 368 | stmt = '' 369 | 370 | try: 371 | if isinstance(operation, unicode): 372 | operation = operation.encode(self._connection.charset) 373 | except (UnicodeDecodeError, UnicodeEncodeError), e: 374 | raise errors.ProgrammingError(str(e)) 375 | 376 | if params is not None: 377 | try: 378 | stmt = operation % self._process_params(params) 379 | except TypeError: 380 | raise errors.ProgrammingError( 381 | "Wrong number of arguments during string formatting") 382 | else: 383 | stmt = operation 384 | 385 | if multi: 386 | self._executed = stmt 387 | self._executed_list = [] 388 | return self._execute_iter(self._connection.cmd_query_iter(stmt)) 389 | else: 390 | self._executed = stmt 391 | try: 392 | self._handle_result(self._connection.cmd_query(stmt)) 393 | except errors.InterfaceError, err: 394 | if self._connection._have_next_result: 395 | raise errors.InterfaceError( 396 | "Use multi=True when executing multiple statements") 397 | raise 398 | return None 399 | 400 | def executemany(self, operation, seq_params): 401 | """Execute the given operation multiple times 402 | 403 | The executemany() method will execute the operation iterating 404 | over the list of parameters in seq_params. 405 | 406 | Example: Inserting 3 new employees and their phone number 407 | 408 | data = [ 409 | ('Jane','555-001'), 410 | ('Joe', '555-001'), 411 | ('John', '555-003') 412 | ] 413 | stmt = "INSERT INTO employees (name, phone) VALUES ('%s','%s')" 414 | cursor.executemany(stmt, data) 415 | 416 | INSERT statements are optimized by batching the data, that is 417 | using the MySQL multiple rows syntax. 418 | 419 | Results are discarded. If they are needed, consider looping over 420 | data using the execute() method. 421 | """ 422 | if not operation: 423 | return 424 | if self._have_unread_result(): 425 | raise errors.InternalError("Unread result found.") 426 | elif len(RE_SQL_SPLIT_STMTS.split(operation)) > 1: 427 | raise errors.InternalError( 428 | "executemany() does not support multiple statements") 429 | 430 | # Optimize INSERTs by batching them 431 | if re.match(RE_SQL_INSERT_STMT,operation): 432 | opnocom = re.sub(RE_SQL_COMMENT, '', operation) 433 | m = re.search(RE_SQL_INSERT_VALUES, opnocom) 434 | fmt = m.group(1) 435 | values = [] 436 | for params in seq_params: 437 | values.append(fmt % self._process_params(params)) 438 | operation = operation.replace(m.group(1), ','.join(values), 1) 439 | return self.execute(operation) 440 | 441 | rowcnt = 0 442 | try: 443 | for params in seq_params: 444 | self.execute(operation, params) 445 | if self.with_rows and self._have_unread_result(): 446 | self.fetchall() 447 | rowcnt += self._rowcount 448 | except (ValueError, TypeError), err: 449 | raise errors.InterfaceError( 450 | "Failed executing the operation; %s" % err) 451 | except: 452 | # Raise whatever execute() raises 453 | raise 454 | self._rowcount = rowcnt 455 | 456 | def stored_results(self): 457 | """Returns an iterator for stored results 458 | 459 | This method returns an iterator over results which are stored when 460 | callproc() is called. The iterator will provide MySQLCursorBuffered 461 | instances. 462 | 463 | Returns a iterator. 464 | """ 465 | return iter(self._stored_results) 466 | 467 | def callproc(self, procname, args=()): 468 | """Calls a stored procedue with the given arguments 469 | 470 | The arguments will be set during this session, meaning 471 | they will be called like ___arg where 472 | is an enumeration (+1) of the arguments. 473 | 474 | Coding Example: 475 | 1) Definining the Stored Routine in MySQL: 476 | CREATE PROCEDURE multiply(IN pFac1 INT, IN pFac2 INT, OUT pProd INT) 477 | BEGIN 478 | SET pProd := pFac1 * pFac2; 479 | END 480 | 481 | 2) Executing in Python: 482 | args = (5,5,0) # 0 is to hold pprod 483 | cursor.callproc('multiply', args) 484 | print cursor.fetchone() 485 | 486 | Does not return a value, but a result set will be 487 | available when the CALL-statement execute successfully. 488 | Raises exceptions when something is wrong. 489 | """ 490 | if not procname or not isinstance(procname, str): 491 | raise ValueError("procname must be a string") 492 | 493 | if not isinstance(args, (tuple, list)): 494 | raise ValueError("args must be a sequence") 495 | 496 | argfmt = "@_%s_arg%d" 497 | self._stored_results = [] 498 | 499 | results = [] 500 | try: 501 | argnames = [] 502 | 503 | if args: 504 | for idx,arg in enumerate(args): 505 | argname = argfmt % (procname, idx+1) 506 | argnames.append(argname) 507 | self.execute("SET %s=%%s" % (argname), (arg,)) 508 | 509 | call = "CALL %s(%s)" % (procname,','.join(argnames)) 510 | 511 | for result in self._connection.cmd_query_iter(call): 512 | if 'columns' in result: 513 | tmp = MySQLCursorBuffered(self._connection._get_self()) 514 | tmp._handle_result(result) 515 | results.append(tmp) 516 | 517 | if argnames: 518 | select = "SELECT %s" % ','.join(argnames) 519 | self.execute(select) 520 | self._stored_results = results 521 | return self.fetchone() 522 | else: 523 | self._stored_results = results 524 | return () 525 | 526 | except errors.Error: 527 | raise 528 | except StandardError, e: 529 | raise errors.InterfaceError( 530 | "Failed calling stored routine; %s" % e) 531 | 532 | def getlastrowid(self): 533 | """Returns the value generated for an AUTO_INCREMENT column 534 | 535 | This method is kept for backward compatibility. Please use the 536 | property lastrowid instead. 537 | 538 | Returns a long value or None. 539 | """ 540 | return self.lastrowid 541 | 542 | def _fetch_warnings(self): 543 | """ 544 | Fetch warnings doing a SHOW WARNINGS. Can be called after getting 545 | the result. 546 | 547 | Returns a result set or None when there were no warnings. 548 | """ 549 | res = [] 550 | try: 551 | c = self._connection.cursor() 552 | cnt = c.execute("SHOW WARNINGS") 553 | res = c.fetchall() 554 | c.close() 555 | except StandardError, e: 556 | raise errors.InterfaceError, errors.InterfaceError( 557 | "Failed getting warnings; %s" % e), sys.exc_info()[2] 558 | 559 | if self._connection.raise_on_warnings is True: 560 | msg = '; '.join([ "(%s) %s" % (r[1],r[2]) for r in res]) 561 | raise errors.get_mysql_exception(res[0][1],res[0][2]) 562 | else: 563 | if len(res): 564 | return res 565 | 566 | return None 567 | 568 | def _handle_eof(self, eof): 569 | self._connection.unread_result = False 570 | self._nextrow = (None, None) 571 | self._warning_count = eof['warning_count'] 572 | if self._connection.get_warnings is True and eof['warning_count']: 573 | self._warnings = self._fetch_warnings() 574 | 575 | def _fetch_row(self): 576 | if not self._have_unread_result(): 577 | return None 578 | row = None 579 | try: 580 | if self._nextrow == (None, None): 581 | (row, eof) = self._connection.get_row() 582 | else: 583 | (row, eof) = self._nextrow 584 | if row: 585 | (foo, eof) = self._nextrow = self._connection.get_row() 586 | if eof is not None: 587 | self._handle_eof(eof) 588 | if self._rowcount == -1: 589 | self._rowcount = 1 590 | else: 591 | self._rowcount += 1 592 | if eof: 593 | self._handle_eof(eof) 594 | except: 595 | raise 596 | else: 597 | return row 598 | 599 | return None 600 | 601 | def fetchwarnings(self): 602 | return self._warnings 603 | 604 | def fetchone(self): 605 | row = self._fetch_row() 606 | if row: 607 | return self._row_to_python(row) 608 | return None 609 | 610 | def fetchmany(self,size=None): 611 | res = [] 612 | cnt = (size or self.arraysize) 613 | while cnt > 0 and self._have_unread_result(): 614 | cnt -= 1 615 | row = self.fetchone() 616 | if row: 617 | res.append(row) 618 | 619 | return res 620 | 621 | def fetchall(self): 622 | if not self._have_unread_result(): 623 | raise errors.InterfaceError("No result set to fetch from.") 624 | res = [] 625 | (rows, eof) = self._connection.get_rows() 626 | self._rowcount = len(rows) 627 | for i in xrange(0,self.rowcount): 628 | res.append(self._row_to_python(rows[i])) 629 | self._handle_eof(eof) 630 | return res 631 | 632 | @property 633 | def column_names(self): 634 | """Returns column names 635 | 636 | This property returns the columns names as a tuple. 637 | 638 | Returns a tuple. 639 | """ 640 | if not self.description: 641 | return () 642 | return tuple( [d[0].decode('utf8') for d in self.description] ) 643 | 644 | @property 645 | def statement(self): 646 | """Returns the executed statement 647 | 648 | This property returns the executed statement. When multiple 649 | statements were executed, the current statement in the iterator 650 | will be returned. 651 | """ 652 | return self._executed.strip() 653 | 654 | @property 655 | def with_rows(self): 656 | """Returns whether the cursor could have rows returned 657 | 658 | This property returns True when column descriptions are available 659 | and possibly also rows, which will need to be fetched. 660 | 661 | Returns True or False. 662 | """ 663 | if not self.description: 664 | return False 665 | return True 666 | 667 | def __unicode__(self): 668 | fmt = "MySQLCursor: %s" 669 | if self._executed: 670 | if len(self._executed) > 30: 671 | res = fmt % (self._executed[:30] + '..') 672 | else: 673 | res = fmt % (self._executed) 674 | else: 675 | res = fmt % '(Nothing executed yet)' 676 | return res 677 | 678 | def __str__(self): 679 | return repr(self.__unicode__()) 680 | 681 | class MySQLCursorBuffered(MySQLCursor): 682 | """Cursor which fetches rows within execute()""" 683 | 684 | def __init__(self, connection=None): 685 | MySQLCursor.__init__(self, connection) 686 | self._rows = None 687 | self._next_row = 0 688 | 689 | def _handle_resultset(self): 690 | (self._rows, eof) = self._connection.get_rows() 691 | self._rowcount = len(self._rows) 692 | self._handle_eof(eof) 693 | self._next_row = 0 694 | try: 695 | self._connection.unread_result = False 696 | except: 697 | pass 698 | 699 | def reset(self): 700 | self._rows = None 701 | 702 | def _fetch_row(self): 703 | row = None 704 | try: 705 | row = self._rows[self._next_row] 706 | except: 707 | return None 708 | else: 709 | self._next_row += 1 710 | return row 711 | return None 712 | 713 | def fetchall(self): 714 | if self._rows is None: 715 | raise errors.InterfaceError("No result set to fetch from.") 716 | res = [] 717 | for row in self._rows: 718 | res.append(self._row_to_python(row)) 719 | self._next_row = len(self._rows) 720 | return res 721 | 722 | def fetchmany(self,size=None): 723 | res = [] 724 | cnt = (size or self.arraysize) 725 | while cnt > 0: 726 | cnt -= 1 727 | row = self.fetchone() 728 | if row: 729 | res.append(row) 730 | 731 | return res 732 | 733 | @property 734 | def with_rows(self): 735 | return self._rows is not None 736 | 737 | class MySQLCursorRaw(MySQLCursor): 738 | 739 | def fetchone(self): 740 | row = self._fetch_row() 741 | if row: 742 | return row 743 | return None 744 | 745 | def fetchall(self): 746 | if not self._have_unread_result(): 747 | raise errors.InterfaceError("No result set to fetch from.") 748 | (rows, eof) = self._connection.get_rows() 749 | self._rowcount = len(rows) 750 | self._handle_eof(eof) 751 | return rows 752 | 753 | class MySQLCursorBufferedRaw(MySQLCursorBuffered): 754 | 755 | def fetchone(self): 756 | row = self._fetch_row() 757 | if row: 758 | return row 759 | return None 760 | 761 | def fetchall(self): 762 | if self._rows is None: 763 | raise errors.InterfaceError("No result set to fetch from.") 764 | return [ r for r in self._rows ] 765 | 766 | -------------------------------------------------------------------------------- /dbapi.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """ 25 | This module implements some constructors and singletons as required by the 26 | DB API v2.0 (PEP-249). 27 | """ 28 | 29 | import time 30 | import datetime 31 | 32 | import constants 33 | 34 | class _DBAPITypeObject: 35 | 36 | def __init__(self, *values): 37 | self.values = values 38 | 39 | def __cmp__(self, other): 40 | if other in self.values: 41 | return 0 42 | if other < self.values: 43 | return 1 44 | else: 45 | return -1 46 | 47 | Date = datetime.date 48 | Time = datetime.time 49 | Timestamp = datetime.datetime 50 | 51 | def DateFromTicks(ticks): 52 | return Date(*time.localtime(ticks)[:3]) 53 | 54 | def TimeFromTicks(ticks): 55 | return Time(*time.localtime(ticks)[3:6]) 56 | 57 | def TimestampFromTicks(ticks): 58 | return Timestamp(*time.localtime(ticks)[:6]) 59 | 60 | Binary = str 61 | 62 | STRING = _DBAPITypeObject(constants.FieldType.get_string_types()) 63 | BINARY = _DBAPITypeObject(constants.FieldType.get_binary_types()) 64 | NUMBER = _DBAPITypeObject(constants.FieldType.get_number_types()) 65 | DATETIME = _DBAPITypeObject(constants.FieldType.get_timestamp_types()) 66 | ROWID = _DBAPITypeObject() 67 | -------------------------------------------------------------------------------- /errorcode.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # MySQL Connector/Python - MySQL driver written in Python. 4 | # Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 5 | # 6 | # MySQL Connector/Python is licensed under the terms of the GPLv2 7 | # , like most 8 | # MySQL Connectors. There are special exceptions to the terms and 9 | # conditions of the GPLv2 as it is applied to this software, see the 10 | # FOSS License Exception 11 | # . 12 | # 13 | # This program is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 25 | 26 | # This file was auto-generated. 27 | _GENERATED_ON = '2013-01-28' 28 | _MYSQL_VERSION = (5, 6, 9) 29 | 30 | """This module contains the MySQL Server and Client error codes""" 31 | 32 | # Start MySQL Errors 33 | ER_HASHCHK = 1000 34 | ER_NISAMCHK = 1001 35 | ER_NO = 1002 36 | ER_YES = 1003 37 | ER_CANT_CREATE_FILE = 1004 38 | ER_CANT_CREATE_TABLE = 1005 39 | ER_CANT_CREATE_DB = 1006 40 | ER_DB_CREATE_EXISTS = 1007 41 | ER_DB_DROP_EXISTS = 1008 42 | ER_DB_DROP_DELETE = 1009 43 | ER_DB_DROP_RMDIR = 1010 44 | ER_CANT_DELETE_FILE = 1011 45 | ER_CANT_FIND_SYSTEM_REC = 1012 46 | ER_CANT_GET_STAT = 1013 47 | ER_CANT_GET_WD = 1014 48 | ER_CANT_LOCK = 1015 49 | ER_CANT_OPEN_FILE = 1016 50 | ER_FILE_NOT_FOUND = 1017 51 | ER_CANT_READ_DIR = 1018 52 | ER_CANT_SET_WD = 1019 53 | ER_CHECKREAD = 1020 54 | ER_DISK_FULL = 1021 55 | ER_DUP_KEY = 1022 56 | ER_ERROR_ON_CLOSE = 1023 57 | ER_ERROR_ON_READ = 1024 58 | ER_ERROR_ON_RENAME = 1025 59 | ER_ERROR_ON_WRITE = 1026 60 | ER_FILE_USED = 1027 61 | ER_FILSORT_ABORT = 1028 62 | ER_FORM_NOT_FOUND = 1029 63 | ER_GET_ERRNO = 1030 64 | ER_ILLEGAL_HA = 1031 65 | ER_KEY_NOT_FOUND = 1032 66 | ER_NOT_FORM_FILE = 1033 67 | ER_NOT_KEYFILE = 1034 68 | ER_OLD_KEYFILE = 1035 69 | ER_OPEN_AS_READONLY = 1036 70 | ER_OUTOFMEMORY = 1037 71 | ER_OUT_OF_SORTMEMORY = 1038 72 | ER_UNEXPECTED_EOF = 1039 73 | ER_CON_COUNT_ERROR = 1040 74 | ER_OUT_OF_RESOURCES = 1041 75 | ER_BAD_HOST_ERROR = 1042 76 | ER_HANDSHAKE_ERROR = 1043 77 | ER_DBACCESS_DENIED_ERROR = 1044 78 | ER_ACCESS_DENIED_ERROR = 1045 79 | ER_NO_DB_ERROR = 1046 80 | ER_UNKNOWN_COM_ERROR = 1047 81 | ER_BAD_NULL_ERROR = 1048 82 | ER_BAD_DB_ERROR = 1049 83 | ER_TABLE_EXISTS_ERROR = 1050 84 | ER_BAD_TABLE_ERROR = 1051 85 | ER_NON_UNIQ_ERROR = 1052 86 | ER_SERVER_SHUTDOWN = 1053 87 | ER_BAD_FIELD_ERROR = 1054 88 | ER_WRONG_FIELD_WITH_GROUP = 1055 89 | ER_WRONG_GROUP_FIELD = 1056 90 | ER_WRONG_SUM_SELECT = 1057 91 | ER_WRONG_VALUE_COUNT = 1058 92 | ER_TOO_LONG_IDENT = 1059 93 | ER_DUP_FIELDNAME = 1060 94 | ER_DUP_KEYNAME = 1061 95 | ER_DUP_ENTRY = 1062 96 | ER_WRONG_FIELD_SPEC = 1063 97 | ER_PARSE_ERROR = 1064 98 | ER_EMPTY_QUERY = 1065 99 | ER_NONUNIQ_TABLE = 1066 100 | ER_INVALID_DEFAULT = 1067 101 | ER_MULTIPLE_PRI_KEY = 1068 102 | ER_TOO_MANY_KEYS = 1069 103 | ER_TOO_MANY_KEY_PARTS = 1070 104 | ER_TOO_LONG_KEY = 1071 105 | ER_KEY_COLUMN_DOES_NOT_EXITS = 1072 106 | ER_BLOB_USED_AS_KEY = 1073 107 | ER_TOO_BIG_FIELDLENGTH = 1074 108 | ER_WRONG_AUTO_KEY = 1075 109 | ER_READY = 1076 110 | ER_NORMAL_SHUTDOWN = 1077 111 | ER_GOT_SIGNAL = 1078 112 | ER_SHUTDOWN_COMPLETE = 1079 113 | ER_FORCING_CLOSE = 1080 114 | ER_IPSOCK_ERROR = 1081 115 | ER_NO_SUCH_INDEX = 1082 116 | ER_WRONG_FIELD_TERMINATORS = 1083 117 | ER_BLOBS_AND_NO_TERMINATED = 1084 118 | ER_TEXTFILE_NOT_READABLE = 1085 119 | ER_FILE_EXISTS_ERROR = 1086 120 | ER_LOAD_INFO = 1087 121 | ER_ALTER_INFO = 1088 122 | ER_WRONG_SUB_KEY = 1089 123 | ER_CANT_REMOVE_ALL_FIELDS = 1090 124 | ER_CANT_DROP_FIELD_OR_KEY = 1091 125 | ER_INSERT_INFO = 1092 126 | ER_UPDATE_TABLE_USED = 1093 127 | ER_NO_SUCH_THREAD = 1094 128 | ER_KILL_DENIED_ERROR = 1095 129 | ER_NO_TABLES_USED = 1096 130 | ER_TOO_BIG_SET = 1097 131 | ER_NO_UNIQUE_LOGFILE = 1098 132 | ER_TABLE_NOT_LOCKED_FOR_WRITE = 1099 133 | ER_TABLE_NOT_LOCKED = 1100 134 | ER_BLOB_CANT_HAVE_DEFAULT = 1101 135 | ER_WRONG_DB_NAME = 1102 136 | ER_WRONG_TABLE_NAME = 1103 137 | ER_TOO_BIG_SELECT = 1104 138 | ER_UNKNOWN_ERROR = 1105 139 | ER_UNKNOWN_PROCEDURE = 1106 140 | ER_WRONG_PARAMCOUNT_TO_PROCEDURE = 1107 141 | ER_WRONG_PARAMETERS_TO_PROCEDURE = 1108 142 | ER_UNKNOWN_TABLE = 1109 143 | ER_FIELD_SPECIFIED_TWICE = 1110 144 | ER_INVALID_GROUP_FUNC_USE = 1111 145 | ER_UNSUPPORTED_EXTENSION = 1112 146 | ER_TABLE_MUST_HAVE_COLUMNS = 1113 147 | ER_RECORD_FILE_FULL = 1114 148 | ER_UNKNOWN_CHARACTER_SET = 1115 149 | ER_TOO_MANY_TABLES = 1116 150 | ER_TOO_MANY_FIELDS = 1117 151 | ER_TOO_BIG_ROWSIZE = 1118 152 | ER_STACK_OVERRUN = 1119 153 | ER_WRONG_OUTER_JOIN = 1120 154 | ER_NULL_COLUMN_IN_INDEX = 1121 155 | ER_CANT_FIND_UDF = 1122 156 | ER_CANT_INITIALIZE_UDF = 1123 157 | ER_UDF_NO_PATHS = 1124 158 | ER_UDF_EXISTS = 1125 159 | ER_CANT_OPEN_LIBRARY = 1126 160 | ER_CANT_FIND_DL_ENTRY = 1127 161 | ER_FUNCTION_NOT_DEFINED = 1128 162 | ER_HOST_IS_BLOCKED = 1129 163 | ER_HOST_NOT_PRIVILEGED = 1130 164 | ER_PASSWORD_ANONYMOUS_USER = 1131 165 | ER_PASSWORD_NOT_ALLOWED = 1132 166 | ER_PASSWORD_NO_MATCH = 1133 167 | ER_UPDATE_INFO = 1134 168 | ER_CANT_CREATE_THREAD = 1135 169 | ER_WRONG_VALUE_COUNT_ON_ROW = 1136 170 | ER_CANT_REOPEN_TABLE = 1137 171 | ER_INVALID_USE_OF_NULL = 1138 172 | ER_REGEXP_ERROR = 1139 173 | ER_MIX_OF_GROUP_FUNC_AND_FIELDS = 1140 174 | ER_NONEXISTING_GRANT = 1141 175 | ER_TABLEACCESS_DENIED_ERROR = 1142 176 | ER_COLUMNACCESS_DENIED_ERROR = 1143 177 | ER_ILLEGAL_GRANT_FOR_TABLE = 1144 178 | ER_GRANT_WRONG_HOST_OR_USER = 1145 179 | ER_NO_SUCH_TABLE = 1146 180 | ER_NONEXISTING_TABLE_GRANT = 1147 181 | ER_NOT_ALLOWED_COMMAND = 1148 182 | ER_SYNTAX_ERROR = 1149 183 | ER_DELAYED_CANT_CHANGE_LOCK = 1150 184 | ER_TOO_MANY_DELAYED_THREADS = 1151 185 | ER_ABORTING_CONNECTION = 1152 186 | ER_NET_PACKET_TOO_LARGE = 1153 187 | ER_NET_READ_ERROR_FROM_PIPE = 1154 188 | ER_NET_FCNTL_ERROR = 1155 189 | ER_NET_PACKETS_OUT_OF_ORDER = 1156 190 | ER_NET_UNCOMPRESS_ERROR = 1157 191 | ER_NET_READ_ERROR = 1158 192 | ER_NET_READ_INTERRUPTED = 1159 193 | ER_NET_ERROR_ON_WRITE = 1160 194 | ER_NET_WRITE_INTERRUPTED = 1161 195 | ER_TOO_LONG_STRING = 1162 196 | ER_TABLE_CANT_HANDLE_BLOB = 1163 197 | ER_TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164 198 | ER_DELAYED_INSERT_TABLE_LOCKED = 1165 199 | ER_WRONG_COLUMN_NAME = 1166 200 | ER_WRONG_KEY_COLUMN = 1167 201 | ER_WRONG_MRG_TABLE = 1168 202 | ER_DUP_UNIQUE = 1169 203 | ER_BLOB_KEY_WITHOUT_LENGTH = 1170 204 | ER_PRIMARY_CANT_HAVE_NULL = 1171 205 | ER_TOO_MANY_ROWS = 1172 206 | ER_REQUIRES_PRIMARY_KEY = 1173 207 | ER_NO_RAID_COMPILED = 1174 208 | ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175 209 | ER_KEY_DOES_NOT_EXITS = 1176 210 | ER_CHECK_NO_SUCH_TABLE = 1177 211 | ER_CHECK_NOT_IMPLEMENTED = 1178 212 | ER_CANT_DO_THIS_DURING_AN_TRANSACTION = 1179 213 | ER_ERROR_DURING_COMMIT = 1180 214 | ER_ERROR_DURING_ROLLBACK = 1181 215 | ER_ERROR_DURING_FLUSH_LOGS = 1182 216 | ER_ERROR_DURING_CHECKPOINT = 1183 217 | ER_NEW_ABORTING_CONNECTION = 1184 218 | ER_DUMP_NOT_IMPLEMENTED = 1185 219 | ER_FLUSH_MASTER_BINLOG_CLOSED = 1186 220 | ER_INDEX_REBUILD = 1187 221 | ER_MASTER = 1188 222 | ER_MASTER_NET_READ = 1189 223 | ER_MASTER_NET_WRITE = 1190 224 | ER_FT_MATCHING_KEY_NOT_FOUND = 1191 225 | ER_LOCK_OR_ACTIVE_TRANSACTION = 1192 226 | ER_UNKNOWN_SYSTEM_VARIABLE = 1193 227 | ER_CRASHED_ON_USAGE = 1194 228 | ER_CRASHED_ON_REPAIR = 1195 229 | ER_WARNING_NOT_COMPLETE_ROLLBACK = 1196 230 | ER_TRANS_CACHE_FULL = 1197 231 | ER_SLAVE_MUST_STOP = 1198 232 | ER_SLAVE_NOT_RUNNING = 1199 233 | ER_BAD_SLAVE = 1200 234 | ER_MASTER_INFO = 1201 235 | ER_SLAVE_THREAD = 1202 236 | ER_TOO_MANY_USER_CONNECTIONS = 1203 237 | ER_SET_CONSTANTS_ONLY = 1204 238 | ER_LOCK_WAIT_TIMEOUT = 1205 239 | ER_LOCK_TABLE_FULL = 1206 240 | ER_READ_ONLY_TRANSACTION = 1207 241 | ER_DROP_DB_WITH_READ_LOCK = 1208 242 | ER_CREATE_DB_WITH_READ_LOCK = 1209 243 | ER_WRONG_ARGUMENTS = 1210 244 | ER_NO_PERMISSION_TO_CREATE_USER = 1211 245 | ER_UNION_TABLES_IN_DIFFERENT_DIR = 1212 246 | ER_LOCK_DEADLOCK = 1213 247 | ER_TABLE_CANT_HANDLE_FT = 1214 248 | ER_CANNOT_ADD_FOREIGN = 1215 249 | ER_NO_REFERENCED_ROW = 1216 250 | ER_ROW_IS_REFERENCED = 1217 251 | ER_CONNECT_TO_MASTER = 1218 252 | ER_QUERY_ON_MASTER = 1219 253 | ER_ERROR_WHEN_EXECUTING_COMMAND = 1220 254 | ER_WRONG_USAGE = 1221 255 | ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222 256 | ER_CANT_UPDATE_WITH_READLOCK = 1223 257 | ER_MIXING_NOT_ALLOWED = 1224 258 | ER_DUP_ARGUMENT = 1225 259 | ER_USER_LIMIT_REACHED = 1226 260 | ER_SPECIFIC_ACCESS_DENIED_ERROR = 1227 261 | ER_LOCAL_VARIABLE = 1228 262 | ER_GLOBAL_VARIABLE = 1229 263 | ER_NO_DEFAULT = 1230 264 | ER_WRONG_VALUE_FOR_VAR = 1231 265 | ER_WRONG_TYPE_FOR_VAR = 1232 266 | ER_VAR_CANT_BE_READ = 1233 267 | ER_CANT_USE_OPTION_HERE = 1234 268 | ER_NOT_SUPPORTED_YET = 1235 269 | ER_MASTER_FATAL_ERROR_READING_BINLOG = 1236 270 | ER_SLAVE_IGNORED_TABLE = 1237 271 | ER_INCORRECT_GLOBAL_LOCAL_VAR = 1238 272 | ER_WRONG_FK_DEF = 1239 273 | ER_KEY_REF_DO_NOT_MATCH_TABLE_REF = 1240 274 | ER_OPERAND_COLUMNS = 1241 275 | ER_SUBQUERY_NO_1_ROW = 1242 276 | ER_UNKNOWN_STMT_HANDLER = 1243 277 | ER_CORRUPT_HELP_DB = 1244 278 | ER_CYCLIC_REFERENCE = 1245 279 | ER_AUTO_CONVERT = 1246 280 | ER_ILLEGAL_REFERENCE = 1247 281 | ER_DERIVED_MUST_HAVE_ALIAS = 1248 282 | ER_SELECT_REDUCED = 1249 283 | ER_TABLENAME_NOT_ALLOWED_HERE = 1250 284 | ER_NOT_SUPPORTED_AUTH_MODE = 1251 285 | ER_SPATIAL_CANT_HAVE_NULL = 1252 286 | ER_COLLATION_CHARSET_MISMATCH = 1253 287 | ER_SLAVE_WAS_RUNNING = 1254 288 | ER_SLAVE_WAS_NOT_RUNNING = 1255 289 | ER_TOO_BIG_FOR_UNCOMPRESS = 1256 290 | ER_ZLIB_Z_MEM_ERROR = 1257 291 | ER_ZLIB_Z_BUF_ERROR = 1258 292 | ER_ZLIB_Z_DATA_ERROR = 1259 293 | ER_CUT_VALUE_GROUP_CONCAT = 1260 294 | ER_WARN_TOO_FEW_RECORDS = 1261 295 | ER_WARN_TOO_MANY_RECORDS = 1262 296 | ER_WARN_NULL_TO_NOTNULL = 1263 297 | ER_WARN_DATA_OUT_OF_RANGE = 1264 298 | WARN_DATA_TRUNCATED = 1265 299 | ER_WARN_USING_OTHER_HANDLER = 1266 300 | ER_CANT_AGGREGATE_2COLLATIONS = 1267 301 | ER_DROP_USER = 1268 302 | ER_REVOKE_GRANTS = 1269 303 | ER_CANT_AGGREGATE_3COLLATIONS = 1270 304 | ER_CANT_AGGREGATE_NCOLLATIONS = 1271 305 | ER_VARIABLE_IS_NOT_STRUCT = 1272 306 | ER_UNKNOWN_COLLATION = 1273 307 | ER_SLAVE_IGNORED_SSL_PARAMS = 1274 308 | ER_SERVER_IS_IN_SECURE_AUTH_MODE = 1275 309 | ER_WARN_FIELD_RESOLVED = 1276 310 | ER_BAD_SLAVE_UNTIL_COND = 1277 311 | ER_MISSING_SKIP_SLAVE = 1278 312 | ER_UNTIL_COND_IGNORED = 1279 313 | ER_WRONG_NAME_FOR_INDEX = 1280 314 | ER_WRONG_NAME_FOR_CATALOG = 1281 315 | ER_WARN_QC_RESIZE = 1282 316 | ER_BAD_FT_COLUMN = 1283 317 | ER_UNKNOWN_KEY_CACHE = 1284 318 | ER_WARN_HOSTNAME_WONT_WORK = 1285 319 | ER_UNKNOWN_STORAGE_ENGINE = 1286 320 | ER_WARN_DEPRECATED_SYNTAX = 1287 321 | ER_NON_UPDATABLE_TABLE = 1288 322 | ER_FEATURE_DISABLED = 1289 323 | ER_OPTION_PREVENTS_STATEMENT = 1290 324 | ER_DUPLICATED_VALUE_IN_TYPE = 1291 325 | ER_TRUNCATED_WRONG_VALUE = 1292 326 | ER_TOO_MUCH_AUTO_TIMESTAMP_COLS = 1293 327 | ER_INVALID_ON_UPDATE = 1294 328 | ER_UNSUPPORTED_PS = 1295 329 | ER_GET_ERRMSG = 1296 330 | ER_GET_TEMPORARY_ERRMSG = 1297 331 | ER_UNKNOWN_TIME_ZONE = 1298 332 | ER_WARN_INVALID_TIMESTAMP = 1299 333 | ER_INVALID_CHARACTER_STRING = 1300 334 | ER_WARN_ALLOWED_PACKET_OVERFLOWED = 1301 335 | ER_CONFLICTING_DECLARATIONS = 1302 336 | ER_SP_NO_RECURSIVE_CREATE = 1303 337 | ER_SP_ALREADY_EXISTS = 1304 338 | ER_SP_DOES_NOT_EXIST = 1305 339 | ER_SP_DROP_FAILED = 1306 340 | ER_SP_STORE_FAILED = 1307 341 | ER_SP_LILABEL_MISMATCH = 1308 342 | ER_SP_LABEL_REDEFINE = 1309 343 | ER_SP_LABEL_MISMATCH = 1310 344 | ER_SP_UNINIT_VAR = 1311 345 | ER_SP_BADSELECT = 1312 346 | ER_SP_BADRETURN = 1313 347 | ER_SP_BADSTATEMENT = 1314 348 | ER_UPDATE_LOG_DEPRECATED_IGNORED = 1315 349 | ER_UPDATE_LOG_DEPRECATED_TRANSLATED = 1316 350 | ER_QUERY_INTERRUPTED = 1317 351 | ER_SP_WRONG_NO_OF_ARGS = 1318 352 | ER_SP_COND_MISMATCH = 1319 353 | ER_SP_NORETURN = 1320 354 | ER_SP_NORETURNEND = 1321 355 | ER_SP_BAD_CURSOR_QUERY = 1322 356 | ER_SP_BAD_CURSOR_SELECT = 1323 357 | ER_SP_CURSOR_MISMATCH = 1324 358 | ER_SP_CURSOR_ALREADY_OPEN = 1325 359 | ER_SP_CURSOR_NOT_OPEN = 1326 360 | ER_SP_UNDECLARED_VAR = 1327 361 | ER_SP_WRONG_NO_OF_FETCH_ARGS = 1328 362 | ER_SP_FETCH_NO_DATA = 1329 363 | ER_SP_DUP_PARAM = 1330 364 | ER_SP_DUP_VAR = 1331 365 | ER_SP_DUP_COND = 1332 366 | ER_SP_DUP_CURS = 1333 367 | ER_SP_CANT_ALTER = 1334 368 | ER_SP_SUBSELECT_NYI = 1335 369 | ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG = 1336 370 | ER_SP_VARCOND_AFTER_CURSHNDLR = 1337 371 | ER_SP_CURSOR_AFTER_HANDLER = 1338 372 | ER_SP_CASE_NOT_FOUND = 1339 373 | ER_FPARSER_TOO_BIG_FILE = 1340 374 | ER_FPARSER_BAD_HEADER = 1341 375 | ER_FPARSER_EOF_IN_COMMENT = 1342 376 | ER_FPARSER_ERROR_IN_PARAMETER = 1343 377 | ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER = 1344 378 | ER_VIEW_NO_EXPLAIN = 1345 379 | ER_FRM_UNKNOWN_TYPE = 1346 380 | ER_WRONG_OBJECT = 1347 381 | ER_NONUPDATEABLE_COLUMN = 1348 382 | ER_VIEW_SELECT_DERIVED = 1349 383 | ER_VIEW_SELECT_CLAUSE = 1350 384 | ER_VIEW_SELECT_VARIABLE = 1351 385 | ER_VIEW_SELECT_TMPTABLE = 1352 386 | ER_VIEW_WRONG_LIST = 1353 387 | ER_WARN_VIEW_MERGE = 1354 388 | ER_WARN_VIEW_WITHOUT_KEY = 1355 389 | ER_VIEW_INVALID = 1356 390 | ER_SP_NO_DROP_SP = 1357 391 | ER_SP_GOTO_IN_HNDLR = 1358 392 | ER_TRG_ALREADY_EXISTS = 1359 393 | ER_TRG_DOES_NOT_EXIST = 1360 394 | ER_TRG_ON_VIEW_OR_TEMP_TABLE = 1361 395 | ER_TRG_CANT_CHANGE_ROW = 1362 396 | ER_TRG_NO_SUCH_ROW_IN_TRG = 1363 397 | ER_NO_DEFAULT_FOR_FIELD = 1364 398 | ER_DIVISION_BY_ZERO = 1365 399 | ER_TRUNCATED_WRONG_VALUE_FOR_FIELD = 1366 400 | ER_ILLEGAL_VALUE_FOR_TYPE = 1367 401 | ER_VIEW_NONUPD_CHECK = 1368 402 | ER_VIEW_CHECK_FAILED = 1369 403 | ER_PROCACCESS_DENIED_ERROR = 1370 404 | ER_RELAY_LOG_FAIL = 1371 405 | ER_PASSWD_LENGTH = 1372 406 | ER_UNKNOWN_TARGET_BINLOG = 1373 407 | ER_IO_ERR_LOG_INDEX_READ = 1374 408 | ER_BINLOG_PURGE_PROHIBITED = 1375 409 | ER_FSEEK_FAIL = 1376 410 | ER_BINLOG_PURGE_FATAL_ERR = 1377 411 | ER_LOG_IN_USE = 1378 412 | ER_LOG_PURGE_UNKNOWN_ERR = 1379 413 | ER_RELAY_LOG_INIT = 1380 414 | ER_NO_BINARY_LOGGING = 1381 415 | ER_RESERVED_SYNTAX = 1382 416 | ER_WSAS_FAILED = 1383 417 | ER_DIFF_GROUPS_PROC = 1384 418 | ER_NO_GROUP_FOR_PROC = 1385 419 | ER_ORDER_WITH_PROC = 1386 420 | ER_LOGGING_PROHIBIT_CHANGING_OF = 1387 421 | ER_NO_FILE_MAPPING = 1388 422 | ER_WRONG_MAGIC = 1389 423 | ER_PS_MANY_PARAM = 1390 424 | ER_KEY_PART_0 = 1391 425 | ER_VIEW_CHECKSUM = 1392 426 | ER_VIEW_MULTIUPDATE = 1393 427 | ER_VIEW_NO_INSERT_FIELD_LIST = 1394 428 | ER_VIEW_DELETE_MERGE_VIEW = 1395 429 | ER_CANNOT_USER = 1396 430 | ER_XAER_NOTA = 1397 431 | ER_XAER_INVAL = 1398 432 | ER_XAER_RMFAIL = 1399 433 | ER_XAER_OUTSIDE = 1400 434 | ER_XAER_RMERR = 1401 435 | ER_XA_RBROLLBACK = 1402 436 | ER_NONEXISTING_PROC_GRANT = 1403 437 | ER_PROC_AUTO_GRANT_FAIL = 1404 438 | ER_PROC_AUTO_REVOKE_FAIL = 1405 439 | ER_DATA_TOO_LONG = 1406 440 | ER_SP_BAD_SQLSTATE = 1407 441 | ER_STARTUP = 1408 442 | ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR = 1409 443 | ER_CANT_CREATE_USER_WITH_GRANT = 1410 444 | ER_WRONG_VALUE_FOR_TYPE = 1411 445 | ER_TABLE_DEF_CHANGED = 1412 446 | ER_SP_DUP_HANDLER = 1413 447 | ER_SP_NOT_VAR_ARG = 1414 448 | ER_SP_NO_RETSET = 1415 449 | ER_CANT_CREATE_GEOMETRY_OBJECT = 1416 450 | ER_FAILED_ROUTINE_BREAK_BINLOG = 1417 451 | ER_BINLOG_UNSAFE_ROUTINE = 1418 452 | ER_BINLOG_CREATE_ROUTINE_NEED_SUPER = 1419 453 | ER_EXEC_STMT_WITH_OPEN_CURSOR = 1420 454 | ER_STMT_HAS_NO_OPEN_CURSOR = 1421 455 | ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG = 1422 456 | ER_NO_DEFAULT_FOR_VIEW_FIELD = 1423 457 | ER_SP_NO_RECURSION = 1424 458 | ER_TOO_BIG_SCALE = 1425 459 | ER_TOO_BIG_PRECISION = 1426 460 | ER_M_BIGGER_THAN_D = 1427 461 | ER_WRONG_LOCK_OF_SYSTEM_TABLE = 1428 462 | ER_CONNECT_TO_FOREIGN_DATA_SOURCE = 1429 463 | ER_QUERY_ON_FOREIGN_DATA_SOURCE = 1430 464 | ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST = 1431 465 | ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE = 1432 466 | ER_FOREIGN_DATA_STRING_INVALID = 1433 467 | ER_CANT_CREATE_FEDERATED_TABLE = 1434 468 | ER_TRG_IN_WRONG_SCHEMA = 1435 469 | ER_STACK_OVERRUN_NEED_MORE = 1436 470 | ER_TOO_LONG_BODY = 1437 471 | ER_WARN_CANT_DROP_DEFAULT_KEYCACHE = 1438 472 | ER_TOO_BIG_DISPLAYWIDTH = 1439 473 | ER_XAER_DUPID = 1440 474 | ER_DATETIME_FUNCTION_OVERFLOW = 1441 475 | ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG = 1442 476 | ER_VIEW_PREVENT_UPDATE = 1443 477 | ER_PS_NO_RECURSION = 1444 478 | ER_SP_CANT_SET_AUTOCOMMIT = 1445 479 | ER_MALFORMED_DEFINER = 1446 480 | ER_VIEW_FRM_NO_USER = 1447 481 | ER_VIEW_OTHER_USER = 1448 482 | ER_NO_SUCH_USER = 1449 483 | ER_FORBID_SCHEMA_CHANGE = 1450 484 | ER_ROW_IS_REFERENCED_2 = 1451 485 | ER_NO_REFERENCED_ROW_2 = 1452 486 | ER_SP_BAD_VAR_SHADOW = 1453 487 | ER_TRG_NO_DEFINER = 1454 488 | ER_OLD_FILE_FORMAT = 1455 489 | ER_SP_RECURSION_LIMIT = 1456 490 | ER_SP_PROC_TABLE_CORRUPT = 1457 491 | ER_SP_WRONG_NAME = 1458 492 | ER_TABLE_NEEDS_UPGRADE = 1459 493 | ER_SP_NO_AGGREGATE = 1460 494 | ER_MAX_PREPARED_STMT_COUNT_REACHED = 1461 495 | ER_VIEW_RECURSIVE = 1462 496 | ER_NON_GROUPING_FIELD_USED = 1463 497 | ER_TABLE_CANT_HANDLE_SPKEYS = 1464 498 | ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA = 1465 499 | ER_REMOVED_SPACES = 1466 500 | ER_AUTOINC_READ_FAILED = 1467 501 | ER_USERNAME = 1468 502 | ER_HOSTNAME = 1469 503 | ER_WRONG_STRING_LENGTH = 1470 504 | ER_NON_INSERTABLE_TABLE = 1471 505 | ER_ADMIN_WRONG_MRG_TABLE = 1472 506 | ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT = 1473 507 | ER_NAME_BECOMES_EMPTY = 1474 508 | ER_AMBIGUOUS_FIELD_TERM = 1475 509 | ER_FOREIGN_SERVER_EXISTS = 1476 510 | ER_FOREIGN_SERVER_DOESNT_EXIST = 1477 511 | ER_ILLEGAL_HA_CREATE_OPTION = 1478 512 | ER_PARTITION_REQUIRES_VALUES_ERROR = 1479 513 | ER_PARTITION_WRONG_VALUES_ERROR = 1480 514 | ER_PARTITION_MAXVALUE_ERROR = 1481 515 | ER_PARTITION_SUBPARTITION_ERROR = 1482 516 | ER_PARTITION_SUBPART_MIX_ERROR = 1483 517 | ER_PARTITION_WRONG_NO_PART_ERROR = 1484 518 | ER_PARTITION_WRONG_NO_SUBPART_ERROR = 1485 519 | ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR = 1486 520 | ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR = 1487 521 | ER_FIELD_NOT_FOUND_PART_ERROR = 1488 522 | ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR = 1489 523 | ER_INCONSISTENT_PARTITION_INFO_ERROR = 1490 524 | ER_PARTITION_FUNC_NOT_ALLOWED_ERROR = 1491 525 | ER_PARTITIONS_MUST_BE_DEFINED_ERROR = 1492 526 | ER_RANGE_NOT_INCREASING_ERROR = 1493 527 | ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR = 1494 528 | ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR = 1495 529 | ER_PARTITION_ENTRY_ERROR = 1496 530 | ER_MIX_HANDLER_ERROR = 1497 531 | ER_PARTITION_NOT_DEFINED_ERROR = 1498 532 | ER_TOO_MANY_PARTITIONS_ERROR = 1499 533 | ER_SUBPARTITION_ERROR = 1500 534 | ER_CANT_CREATE_HANDLER_FILE = 1501 535 | ER_BLOB_FIELD_IN_PART_FUNC_ERROR = 1502 536 | ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF = 1503 537 | ER_NO_PARTS_ERROR = 1504 538 | ER_PARTITION_MGMT_ON_NONPARTITIONED = 1505 539 | ER_FOREIGN_KEY_ON_PARTITIONED = 1506 540 | ER_DROP_PARTITION_NON_EXISTENT = 1507 541 | ER_DROP_LAST_PARTITION = 1508 542 | ER_COALESCE_ONLY_ON_HASH_PARTITION = 1509 543 | ER_REORG_HASH_ONLY_ON_SAME_NO = 1510 544 | ER_REORG_NO_PARAM_ERROR = 1511 545 | ER_ONLY_ON_RANGE_LIST_PARTITION = 1512 546 | ER_ADD_PARTITION_SUBPART_ERROR = 1513 547 | ER_ADD_PARTITION_NO_NEW_PARTITION = 1514 548 | ER_COALESCE_PARTITION_NO_PARTITION = 1515 549 | ER_REORG_PARTITION_NOT_EXIST = 1516 550 | ER_SAME_NAME_PARTITION = 1517 551 | ER_NO_BINLOG_ERROR = 1518 552 | ER_CONSECUTIVE_REORG_PARTITIONS = 1519 553 | ER_REORG_OUTSIDE_RANGE = 1520 554 | ER_PARTITION_FUNCTION_FAILURE = 1521 555 | ER_PART_STATE_ERROR = 1522 556 | ER_LIMITED_PART_RANGE = 1523 557 | ER_PLUGIN_IS_NOT_LOADED = 1524 558 | ER_WRONG_VALUE = 1525 559 | ER_NO_PARTITION_FOR_GIVEN_VALUE = 1526 560 | ER_FILEGROUP_OPTION_ONLY_ONCE = 1527 561 | ER_CREATE_FILEGROUP_FAILED = 1528 562 | ER_DROP_FILEGROUP_FAILED = 1529 563 | ER_TABLESPACE_AUTO_EXTEND_ERROR = 1530 564 | ER_WRONG_SIZE_NUMBER = 1531 565 | ER_SIZE_OVERFLOW_ERROR = 1532 566 | ER_ALTER_FILEGROUP_FAILED = 1533 567 | ER_BINLOG_ROW_LOGGING_FAILED = 1534 568 | ER_BINLOG_ROW_WRONG_TABLE_DEF = 1535 569 | ER_BINLOG_ROW_RBR_TO_SBR = 1536 570 | ER_EVENT_ALREADY_EXISTS = 1537 571 | ER_EVENT_STORE_FAILED = 1538 572 | ER_EVENT_DOES_NOT_EXIST = 1539 573 | ER_EVENT_CANT_ALTER = 1540 574 | ER_EVENT_DROP_FAILED = 1541 575 | ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG = 1542 576 | ER_EVENT_ENDS_BEFORE_STARTS = 1543 577 | ER_EVENT_EXEC_TIME_IN_THE_PAST = 1544 578 | ER_EVENT_OPEN_TABLE_FAILED = 1545 579 | ER_EVENT_NEITHER_M_EXPR_NOR_M_AT = 1546 580 | ER_OBSOLETE_COL_COUNT_DOESNT_MATCH_CORRUPTED = 1547 581 | ER_OBSOLETE_CANNOT_LOAD_FROM_TABLE = 1548 582 | ER_EVENT_CANNOT_DELETE = 1549 583 | ER_EVENT_COMPILE_ERROR = 1550 584 | ER_EVENT_SAME_NAME = 1551 585 | ER_EVENT_DATA_TOO_LONG = 1552 586 | ER_DROP_INDEX_FK = 1553 587 | ER_WARN_DEPRECATED_SYNTAX_WITH_VER = 1554 588 | ER_CANT_WRITE_LOCK_LOG_TABLE = 1555 589 | ER_CANT_LOCK_LOG_TABLE = 1556 590 | ER_FOREIGN_DUPLICATE_KEY_OLD_UNUSED = 1557 591 | ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE = 1558 592 | ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR = 1559 593 | ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT = 1560 594 | ER_NDB_CANT_SWITCH_BINLOG_FORMAT = 1561 595 | ER_PARTITION_NO_TEMPORARY = 1562 596 | ER_PARTITION_CONST_DOMAIN_ERROR = 1563 597 | ER_PARTITION_FUNCTION_IS_NOT_ALLOWED = 1564 598 | ER_DDL_LOG_ERROR = 1565 599 | ER_NULL_IN_VALUES_LESS_THAN = 1566 600 | ER_WRONG_PARTITION_NAME = 1567 601 | ER_CANT_CHANGE_TX_CHARACTERISTICS = 1568 602 | ER_DUP_ENTRY_AUTOINCREMENT_CASE = 1569 603 | ER_EVENT_MODIFY_QUEUE_ERROR = 1570 604 | ER_EVENT_SET_VAR_ERROR = 1571 605 | ER_PARTITION_MERGE_ERROR = 1572 606 | ER_CANT_ACTIVATE_LOG = 1573 607 | ER_RBR_NOT_AVAILABLE = 1574 608 | ER_BASE64_DECODE_ERROR = 1575 609 | ER_EVENT_RECURSION_FORBIDDEN = 1576 610 | ER_EVENTS_DB_ERROR = 1577 611 | ER_ONLY_INTEGERS_ALLOWED = 1578 612 | ER_UNSUPORTED_LOG_ENGINE = 1579 613 | ER_BAD_LOG_STATEMENT = 1580 614 | ER_CANT_RENAME_LOG_TABLE = 1581 615 | ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT = 1582 616 | ER_WRONG_PARAMETERS_TO_NATIVE_FCT = 1583 617 | ER_WRONG_PARAMETERS_TO_STORED_FCT = 1584 618 | ER_NATIVE_FCT_NAME_COLLISION = 1585 619 | ER_DUP_ENTRY_WITH_KEY_NAME = 1586 620 | ER_BINLOG_PURGE_EMFILE = 1587 621 | ER_EVENT_CANNOT_CREATE_IN_THE_PAST = 1588 622 | ER_EVENT_CANNOT_ALTER_IN_THE_PAST = 1589 623 | ER_SLAVE_INCIDENT = 1590 624 | ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT = 1591 625 | ER_BINLOG_UNSAFE_STATEMENT = 1592 626 | ER_SLAVE_FATAL_ERROR = 1593 627 | ER_SLAVE_RELAY_LOG_READ_FAILURE = 1594 628 | ER_SLAVE_RELAY_LOG_WRITE_FAILURE = 1595 629 | ER_SLAVE_CREATE_EVENT_FAILURE = 1596 630 | ER_SLAVE_MASTER_COM_FAILURE = 1597 631 | ER_BINLOG_LOGGING_IMPOSSIBLE = 1598 632 | ER_VIEW_NO_CREATION_CTX = 1599 633 | ER_VIEW_INVALID_CREATION_CTX = 1600 634 | ER_SR_INVALID_CREATION_CTX = 1601 635 | ER_TRG_CORRUPTED_FILE = 1602 636 | ER_TRG_NO_CREATION_CTX = 1603 637 | ER_TRG_INVALID_CREATION_CTX = 1604 638 | ER_EVENT_INVALID_CREATION_CTX = 1605 639 | ER_TRG_CANT_OPEN_TABLE = 1606 640 | ER_CANT_CREATE_SROUTINE = 1607 641 | ER_NEVER_USED = 1608 642 | ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT = 1609 643 | ER_SLAVE_CORRUPT_EVENT = 1610 644 | ER_LOAD_DATA_INVALID_COLUMN = 1611 645 | ER_LOG_PURGE_NO_FILE = 1612 646 | ER_XA_RBTIMEOUT = 1613 647 | ER_XA_RBDEADLOCK = 1614 648 | ER_NEED_REPREPARE = 1615 649 | ER_DELAYED_NOT_SUPPORTED = 1616 650 | WARN_NO_MASTER_INFO = 1617 651 | WARN_OPTION_IGNORED = 1618 652 | WARN_PLUGIN_DELETE_BUILTIN = 1619 653 | WARN_PLUGIN_BUSY = 1620 654 | ER_VARIABLE_IS_READONLY = 1621 655 | ER_WARN_ENGINE_TRANSACTION_ROLLBACK = 1622 656 | ER_SLAVE_HEARTBEAT_FAILURE = 1623 657 | ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE = 1624 658 | ER_NDB_REPLICATION_SCHEMA_ERROR = 1625 659 | ER_CONFLICT_FN_PARSE_ERROR = 1626 660 | ER_EXCEPTIONS_WRITE_ERROR = 1627 661 | ER_TOO_LONG_TABLE_COMMENT = 1628 662 | ER_TOO_LONG_FIELD_COMMENT = 1629 663 | ER_FUNC_INEXISTENT_NAME_COLLISION = 1630 664 | ER_DATABASE_NAME = 1631 665 | ER_TABLE_NAME = 1632 666 | ER_PARTITION_NAME = 1633 667 | ER_SUBPARTITION_NAME = 1634 668 | ER_TEMPORARY_NAME = 1635 669 | ER_RENAMED_NAME = 1636 670 | ER_TOO_MANY_CONCURRENT_TRXS = 1637 671 | WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED = 1638 672 | ER_DEBUG_SYNC_TIMEOUT = 1639 673 | ER_DEBUG_SYNC_HIT_LIMIT = 1640 674 | ER_DUP_SIGNAL_SET = 1641 675 | ER_SIGNAL_WARN = 1642 676 | ER_SIGNAL_NOT_FOUND = 1643 677 | ER_SIGNAL_EXCEPTION = 1644 678 | ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER = 1645 679 | ER_SIGNAL_BAD_CONDITION_TYPE = 1646 680 | WARN_COND_ITEM_TRUNCATED = 1647 681 | ER_COND_ITEM_TOO_LONG = 1648 682 | ER_UNKNOWN_LOCALE = 1649 683 | ER_SLAVE_IGNORE_SERVER_IDS = 1650 684 | ER_QUERY_CACHE_DISABLED = 1651 685 | ER_SAME_NAME_PARTITION_FIELD = 1652 686 | ER_PARTITION_COLUMN_LIST_ERROR = 1653 687 | ER_WRONG_TYPE_COLUMN_VALUE_ERROR = 1654 688 | ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR = 1655 689 | ER_MAXVALUE_IN_VALUES_IN = 1656 690 | ER_TOO_MANY_VALUES_ERROR = 1657 691 | ER_ROW_SINGLE_PARTITION_FIELD_ERROR = 1658 692 | ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD = 1659 693 | ER_PARTITION_FIELDS_TOO_LONG = 1660 694 | ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE = 1661 695 | ER_BINLOG_ROW_MODE_AND_STMT_ENGINE = 1662 696 | ER_BINLOG_UNSAFE_AND_STMT_ENGINE = 1663 697 | ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE = 1664 698 | ER_BINLOG_STMT_MODE_AND_ROW_ENGINE = 1665 699 | ER_BINLOG_ROW_INJECTION_AND_STMT_MODE = 1666 700 | ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE = 1667 701 | ER_BINLOG_UNSAFE_LIMIT = 1668 702 | ER_BINLOG_UNSAFE_INSERT_DELAYED = 1669 703 | ER_BINLOG_UNSAFE_SYSTEM_TABLE = 1670 704 | ER_BINLOG_UNSAFE_AUTOINC_COLUMNS = 1671 705 | ER_BINLOG_UNSAFE_UDF = 1672 706 | ER_BINLOG_UNSAFE_SYSTEM_VARIABLE = 1673 707 | ER_BINLOG_UNSAFE_SYSTEM_FUNCTION = 1674 708 | ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS = 1675 709 | ER_MESSAGE_AND_STATEMENT = 1676 710 | ER_SLAVE_CONVERSION_FAILED = 1677 711 | ER_SLAVE_CANT_CREATE_CONVERSION = 1678 712 | ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT = 1679 713 | ER_PATH_LENGTH = 1680 714 | ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT = 1681 715 | ER_WRONG_NATIVE_TABLE_STRUCTURE = 1682 716 | ER_WRONG_PERFSCHEMA_USAGE = 1683 717 | ER_WARN_I_S_SKIPPED_TABLE = 1684 718 | ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT = 1685 719 | ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT = 1686 720 | ER_SPATIAL_MUST_HAVE_GEOM_COL = 1687 721 | ER_TOO_LONG_INDEX_COMMENT = 1688 722 | ER_LOCK_ABORTED = 1689 723 | ER_DATA_OUT_OF_RANGE = 1690 724 | ER_WRONG_SPVAR_TYPE_IN_LIMIT = 1691 725 | ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE = 1692 726 | ER_BINLOG_UNSAFE_MIXED_STATEMENT = 1693 727 | ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN = 1694 728 | ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN = 1695 729 | ER_FAILED_READ_FROM_PAR_FILE = 1696 730 | ER_VALUES_IS_NOT_INT_TYPE_ERROR = 1697 731 | ER_ACCESS_DENIED_NO_PASSWORD_ERROR = 1698 732 | ER_SET_PASSWORD_AUTH_PLUGIN = 1699 733 | ER_GRANT_PLUGIN_USER_EXISTS = 1700 734 | ER_TRUNCATE_ILLEGAL_FK = 1701 735 | ER_PLUGIN_IS_PERMANENT = 1702 736 | ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN = 1703 737 | ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX = 1704 738 | ER_STMT_CACHE_FULL = 1705 739 | ER_MULTI_UPDATE_KEY_CONFLICT = 1706 740 | ER_TABLE_NEEDS_REBUILD = 1707 741 | WARN_OPTION_BELOW_LIMIT = 1708 742 | ER_INDEX_COLUMN_TOO_LONG = 1709 743 | ER_ERROR_IN_TRIGGER_BODY = 1710 744 | ER_ERROR_IN_UNKNOWN_TRIGGER_BODY = 1711 745 | ER_INDEX_CORRUPT = 1712 746 | ER_UNDO_RECORD_TOO_BIG = 1713 747 | ER_BINLOG_UNSAFE_INSERT_IGNORE_SELECT = 1714 748 | ER_BINLOG_UNSAFE_INSERT_SELECT_UPDATE = 1715 749 | ER_BINLOG_UNSAFE_REPLACE_SELECT = 1716 750 | ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT = 1717 751 | ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT = 1718 752 | ER_BINLOG_UNSAFE_UPDATE_IGNORE = 1719 753 | ER_PLUGIN_NO_UNINSTALL = 1720 754 | ER_PLUGIN_NO_INSTALL = 1721 755 | ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT = 1722 756 | ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC = 1723 757 | ER_BINLOG_UNSAFE_INSERT_TWO_KEYS = 1724 758 | ER_TABLE_IN_FK_CHECK = 1725 759 | ER_UNSUPPORTED_ENGINE = 1726 760 | ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST = 1727 761 | ER_CANNOT_LOAD_FROM_TABLE_V2 = 1728 762 | ER_MASTER_DELAY_VALUE_OUT_OF_RANGE = 1729 763 | ER_ONLY_FD_AND_RBR_EVENTS_ALLOWED_IN_BINLOG_STATEMENT = 1730 764 | ER_PARTITION_EXCHANGE_DIFFERENT_OPTION = 1731 765 | ER_PARTITION_EXCHANGE_PART_TABLE = 1732 766 | ER_PARTITION_EXCHANGE_TEMP_TABLE = 1733 767 | ER_PARTITION_INSTEAD_OF_SUBPARTITION = 1734 768 | ER_UNKNOWN_PARTITION = 1735 769 | ER_TABLES_DIFFERENT_METADATA = 1736 770 | ER_ROW_DOES_NOT_MATCH_PARTITION = 1737 771 | ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX = 1738 772 | ER_WARN_INDEX_NOT_APPLICABLE = 1739 773 | ER_PARTITION_EXCHANGE_FOREIGN_KEY = 1740 774 | ER_NO_SUCH_KEY_VALUE = 1741 775 | ER_RPL_INFO_DATA_TOO_LONG = 1742 776 | ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE = 1743 777 | ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE = 1744 778 | ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX = 1745 779 | ER_CANT_UPDATE_TABLE_IN_CREATE_TABLE_SELECT = 1746 780 | ER_PARTITION_CLAUSE_ON_NONPARTITIONED = 1747 781 | ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET = 1748 782 | ER_NO_SUCH_PARTITION__UNUSED = 1749 783 | ER_CHANGE_RPL_INFO_REPOSITORY_FAILURE = 1750 784 | ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE = 1751 785 | ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE = 1752 786 | ER_MTS_FEATURE_IS_NOT_SUPPORTED = 1753 787 | ER_MTS_UPDATED_DBS_GREATER_MAX = 1754 788 | ER_MTS_CANT_PARALLEL = 1755 789 | ER_MTS_INCONSISTENT_DATA = 1756 790 | ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING = 1757 791 | ER_DA_INVALID_CONDITION_NUMBER = 1758 792 | ER_INSECURE_PLAIN_TEXT = 1759 793 | ER_INSECURE_CHANGE_MASTER = 1760 794 | ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO = 1761 795 | ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO = 1762 796 | ER_SQLTHREAD_WITH_SECURE_SLAVE = 1763 797 | ER_TABLE_HAS_NO_FT = 1764 798 | ER_VARIABLE_NOT_SETTABLE_IN_SF_OR_TRIGGER = 1765 799 | ER_VARIABLE_NOT_SETTABLE_IN_TRANSACTION = 1766 800 | ER_GTID_NEXT_IS_NOT_IN_GTID_NEXT_LIST = 1767 801 | ER_CANT_CHANGE_GTID_NEXT_IN_TRANSACTION_WHEN_GTID_NEXT_LIST_IS_NULL = 1768 802 | ER_SET_STATEMENT_CANNOT_INVOKE_FUNCTION = 1769 803 | ER_GTID_NEXT_CANT_BE_AUTOMATIC_IF_GTID_NEXT_LIST_IS_NON_NULL = 1770 804 | ER_SKIPPING_LOGGED_TRANSACTION = 1771 805 | ER_MALFORMED_GTID_SET_SPECIFICATION = 1772 806 | ER_MALFORMED_GTID_SET_ENCODING = 1773 807 | ER_MALFORMED_GTID_SPECIFICATION = 1774 808 | ER_GNO_EXHAUSTED = 1775 809 | ER_BAD_SLAVE_AUTO_POSITION = 1776 810 | ER_AUTO_POSITION_REQUIRES_GTID_MODE_ON = 1777 811 | ER_CANT_DO_IMPLICIT_COMMIT_IN_TRX_WHEN_GTID_NEXT_IS_SET = 1778 812 | ER_GTID_MODE_2_OR_3_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON = 1779 813 | ER_GTID_MODE_REQUIRES_BINLOG = 1780 814 | ER_CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF = 1781 815 | ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON = 1782 816 | ER_CANT_SET_GTID_NEXT_LIST_TO_NON_NULL_WHEN_GTID_MODE_IS_OFF = 1783 817 | ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF = 1784 818 | ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE = 1785 819 | ER_GTID_UNSAFE_CREATE_SELECT = 1786 820 | ER_GTID_UNSAFE_CREATE_DROP_TEMPORARY_TABLE_IN_TRANSACTION = 1787 821 | ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME = 1788 822 | ER_MASTER_HAS_PURGED_REQUIRED_GTIDS = 1789 823 | ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID = 1790 824 | ER_UNKNOWN_EXPLAIN_FORMAT = 1791 825 | ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION = 1792 826 | ER_TOO_LONG_TABLE_PARTITION_COMMENT = 1793 827 | ER_SLAVE_CONFIGURATION = 1794 828 | ER_INNODB_FT_LIMIT = 1795 829 | ER_INNODB_NO_FT_TEMP_TABLE = 1796 830 | ER_INNODB_FT_WRONG_DOCID_COLUMN = 1797 831 | ER_INNODB_FT_WRONG_DOCID_INDEX = 1798 832 | ER_INNODB_ONLINE_LOG_TOO_BIG = 1799 833 | ER_UNKNOWN_ALTER_ALGORITHM = 1800 834 | ER_UNKNOWN_ALTER_LOCK = 1801 835 | ER_MTS_CHANGE_MASTER_CANT_RUN_WITH_GAPS = 1802 836 | ER_MTS_RECOVERY_FAILURE = 1803 837 | ER_MTS_RESET_WORKERS = 1804 838 | ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2 = 1805 839 | ER_SLAVE_SILENT_RETRY_TRANSACTION = 1806 840 | ER_DISCARD_FK_CHECKS_RUNNING = 1807 841 | ER_TABLE_SCHEMA_MISMATCH = 1808 842 | ER_TABLE_IN_SYSTEM_TABLESPACE = 1809 843 | ER_IO_READ_ERROR = 1810 844 | ER_IO_WRITE_ERROR = 1811 845 | ER_TABLESPACE_MISSING = 1812 846 | ER_TABLESPACE_EXISTS = 1813 847 | ER_TABLESPACE_DISCARDED = 1814 848 | ER_INTERNAL_ERROR = 1815 849 | ER_INNODB_IMPORT_ERROR = 1816 850 | ER_INNODB_INDEX_CORRUPT = 1817 851 | ER_INVALID_YEAR_COLUMN_LENGTH = 1818 852 | ER_NOT_VALID_PASSWORD = 1819 853 | ER_MUST_CHANGE_PASSWORD = 1820 854 | ER_FK_NO_INDEX_CHILD = 1821 855 | ER_FK_NO_INDEX_PARENT = 1822 856 | ER_FK_FAIL_ADD_SYSTEM = 1823 857 | ER_FK_CANNOT_OPEN_PARENT = 1824 858 | ER_FK_INCORRECT_OPTION = 1825 859 | ER_FK_DUP_NAME = 1826 860 | ER_PASSWORD_FORMAT = 1827 861 | ER_FK_COLUMN_CANNOT_DROP = 1828 862 | ER_FK_COLUMN_CANNOT_DROP_CHILD = 1829 863 | ER_FK_COLUMN_NOT_NULL = 1830 864 | ER_DUP_INDEX = 1831 865 | ER_FK_COLUMN_CANNOT_CHANGE = 1832 866 | ER_FK_COLUMN_CANNOT_CHANGE_CHILD = 1833 867 | ER_FK_CANNOT_DELETE_PARENT = 1834 868 | ER_MALFORMED_PACKET = 1835 869 | ER_READ_ONLY_MODE = 1836 870 | ER_GTID_NEXT_TYPE_UNDEFINED_GROUP = 1837 871 | ER_VARIABLE_NOT_SETTABLE_IN_SP = 1838 872 | ER_CANT_SET_GTID_PURGED_WHEN_GTID_MODE_IS_OFF = 1839 873 | ER_CANT_SET_GTID_PURGED_WHEN_GTID_EXECUTED_IS_NOT_EMPTY = 1840 874 | ER_CANT_SET_GTID_PURGED_WHEN_OWNED_GTIDS_IS_NOT_EMPTY = 1841 875 | ER_GTID_PURGED_WAS_CHANGED = 1842 876 | ER_GTID_EXECUTED_WAS_CHANGED = 1843 877 | ER_BINLOG_STMT_MODE_AND_NO_REPL_TABLES = 1844 878 | CR_UNKNOWN_ERROR = 2000 879 | CR_SOCKET_CREATE_ERROR = 2001 880 | CR_CONNECTION_ERROR = 2002 881 | CR_CONN_HOST_ERROR = 2003 882 | CR_IPSOCK_ERROR = 2004 883 | CR_UNKNOWN_HOST = 2005 884 | CR_SERVER_GONE_ERROR = 2006 885 | CR_VERSION_ERROR = 2007 886 | CR_OUT_OF_MEMORY = 2008 887 | CR_WRONG_HOST_INFO = 2009 888 | CR_LOCALHOST_CONNECTION = 2010 889 | CR_TCP_CONNECTION = 2011 890 | CR_SERVER_HANDSHAKE_ERR = 2012 891 | CR_SERVER_LOST = 2013 892 | CR_COMMANDS_OUT_OF_SYNC = 2014 893 | CR_NAMEDPIPE_CONNECTION = 2015 894 | CR_NAMEDPIPEWAIT_ERROR = 2016 895 | CR_NAMEDPIPEOPEN_ERROR = 2017 896 | CR_NAMEDPIPESETSTATE_ERROR = 2018 897 | CR_CANT_READ_CHARSET = 2019 898 | CR_NET_PACKET_TOO_LARGE = 2020 899 | CR_EMBEDDED_CONNECTION = 2021 900 | CR_PROBE_SLAVE_STATUS = 2022 901 | CR_PROBE_SLAVE_HOSTS = 2023 902 | CR_PROBE_SLAVE_CONNECT = 2024 903 | CR_PROBE_MASTER_CONNECT = 2025 904 | CR_SSL_CONNECTION_ERROR = 2026 905 | CR_MALFORMED_PACKET = 2027 906 | CR_WRONG_LICENSE = 2028 907 | CR_NULL_POINTER = 2029 908 | CR_NO_PREPARE_STMT = 2030 909 | CR_PARAMS_NOT_BOUND = 2031 910 | CR_DATA_TRUNCATED = 2032 911 | CR_NO_PARAMETERS_EXISTS = 2033 912 | CR_INVALID_PARAMETER_NO = 2034 913 | CR_INVALID_BUFFER_USE = 2035 914 | CR_UNSUPPORTED_PARAM_TYPE = 2036 915 | CR_SHARED_MEMORY_CONNECTION = 2037 916 | CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR = 2038 917 | CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR = 2039 918 | CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR = 2040 919 | CR_SHARED_MEMORY_CONNECT_MAP_ERROR = 2041 920 | CR_SHARED_MEMORY_FILE_MAP_ERROR = 2042 921 | CR_SHARED_MEMORY_MAP_ERROR = 2043 922 | CR_SHARED_MEMORY_EVENT_ERROR = 2044 923 | CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR = 2045 924 | CR_SHARED_MEMORY_CONNECT_SET_ERROR = 2046 925 | CR_CONN_UNKNOW_PROTOCOL = 2047 926 | CR_INVALID_CONN_HANDLE = 2048 927 | CR_SECURE_AUTH = 2049 928 | CR_FETCH_CANCELED = 2050 929 | CR_NO_DATA = 2051 930 | CR_NO_STMT_METADATA = 2052 931 | CR_NO_RESULT_SET = 2053 932 | CR_NOT_IMPLEMENTED = 2054 933 | CR_SERVER_LOST_EXTENDED = 2055 934 | CR_STMT_CLOSED = 2056 935 | CR_NEW_STMT_METADATA = 2057 936 | CR_ALREADY_CONNECTED = 2058 937 | CR_AUTH_PLUGIN_CANNOT_LOAD = 2059 938 | CR_DUPLICATE_CONNECTION_ATTR = 2060 939 | # End MySQL Errors 940 | 941 | -------------------------------------------------------------------------------- /errors.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """This module implements Exception classes 25 | """ 26 | 27 | import utils 28 | import errorcode 29 | from locales import get_client_error 30 | 31 | _CUSTOM_ERROR_EXCEPTIONS = {} 32 | 33 | def custom_error_exception(error=None, exception=None): 34 | """Define custom exceptions for MySQL server errors 35 | 36 | This function defines custom exceptions for MySQL server errors and 37 | returns the current set customizations. 38 | 39 | If error is a MySQL Server error number, then you have to pass also the 40 | exception class. 41 | 42 | The error argument can also be a dictionary in which case the key is 43 | the server error number, and value the exception to be raised. 44 | 45 | If none of the arguments are given, then custom_error_exception() will 46 | simply return the current set customizations. 47 | 48 | To reset the customizations, simply supply an empty dictionary. 49 | 50 | Examples: 51 | import mysql.connector 52 | from mysql.connector import errorcode 53 | 54 | # Server error 1028 should raise a DatabaseError 55 | mysql.connector.custom_error_exception( 56 | 1028, mysql.connector.DatabaseError) 57 | 58 | # Or using a dictionary: 59 | mysql.connector.custom_error_exception({ 60 | 1028: mysql.connector.DatabaseError, 61 | 1029: mysql.connector.OperationalError, 62 | }) 63 | 64 | # Reset 65 | mysql.connector.custom_error_exception({}) 66 | 67 | Returns a dictionary. 68 | """ 69 | global _CUSTOM_ERROR_EXCEPTIONS 70 | 71 | if isinstance(error, dict) and not len(error): 72 | _CUSTOM_ERROR_EXCEPTIONS = {} 73 | return _CUSTOM_ERROR_EXCEPTIONS 74 | 75 | if not error and not exception: 76 | return _CUSTOM_ERROR_EXCEPTIONS 77 | 78 | if not isinstance(error, (int, dict)): 79 | raise ValueError( 80 | "The error argument should be either an integer or dictionary") 81 | 82 | if isinstance(error, int): 83 | error = { error: exception } 84 | 85 | for errno, exception in error.items(): 86 | if not isinstance(errno, int): 87 | raise ValueError("error number should be an integer") 88 | try: 89 | if not issubclass(exception, Exception): 90 | raise TypeError 91 | except TypeError: 92 | raise ValueError("exception should be subclass of Exception") 93 | _CUSTOM_ERROR_EXCEPTIONS[errno] = exception 94 | 95 | return _CUSTOM_ERROR_EXCEPTIONS 96 | 97 | def get_mysql_exception(errno, msg, sqlstate=None): 98 | """Get the exception matching the MySQL error 99 | 100 | This function will return an exception based on the SQLState. The given 101 | message will be passed on in the returned exception. 102 | 103 | The exception returned can be customized using the 104 | mysql.connector.custom_error_exception() function. 105 | 106 | Returns an Exception 107 | """ 108 | try: 109 | return _CUSTOM_ERROR_EXCEPTIONS[errno]( 110 | msg=msg, errno=errno, sqlstate=sqlstate) 111 | except KeyError: 112 | # Error was not mapped to particular exception 113 | pass 114 | 115 | if not sqlstate: 116 | return DatabaseError(msg=msg, errno=errno) 117 | 118 | try: 119 | return _SQLSTATE_CLASS_EXCEPTION[sqlstate[0:2]]( 120 | msg=msg, errno=errno, sqlstate=sqlstate) 121 | except KeyError: 122 | # Return default InterfaceError 123 | return DatabaseError(msg=msg, errno=errno, sqlstate=sqlstate) 124 | 125 | def get_exception(packet): 126 | """Returns an exception object based on the MySQL error 127 | 128 | Returns an exception object based on the MySQL error in the given 129 | packet. 130 | 131 | Returns an Error-Object. 132 | """ 133 | errno = errmsg = None 134 | 135 | if packet[4] != '\xff': 136 | raise ValueError("Packet is not an error packet") 137 | 138 | sqlstate = None 139 | try: 140 | packet = packet[5:] 141 | (packet, errno) = utils.read_int(packet, 2) 142 | if packet[0] != '\x23': 143 | # Error without SQLState 144 | errmsg = packet 145 | else: 146 | (packet, sqlstate) = utils.read_bytes(packet[1:], 5) 147 | errmsg = packet 148 | except Exception, err: 149 | return InterfaceError("Failed getting Error information (%r)" % err) 150 | else: 151 | return get_mysql_exception(errno, errmsg, sqlstate) 152 | 153 | class Error(StandardError): 154 | """Exception that is base class for all other error exceptions""" 155 | def __init__(self, msg=None, errno=None, values=None, sqlstate=None): 156 | self.msg = msg 157 | self.errno = errno or -1 158 | self.sqlstate = sqlstate 159 | 160 | if not self.msg and (2000 <= self.errno < 3000): 161 | errmsg = get_client_error(self.errno) 162 | if values is not None: 163 | try: 164 | errmsg = errmsg % values 165 | except TypeError, err: 166 | errmsg = errmsg + " (Warning: %s)" % err 167 | self.msg = errmsg 168 | elif not self.msg: 169 | self.msg = 'Unknown error' 170 | 171 | if self.msg and self.errno != -1: 172 | if self.sqlstate: 173 | self.msg = '%d (%s): %s' % (self.errno, self.sqlstate, 174 | self.msg) 175 | else: 176 | self.msg = '%d: %s' % (self.errno, self.msg) 177 | 178 | def __str__(self): 179 | return self.msg 180 | 181 | class Warning(StandardError): 182 | """Exception for important warnings""" 183 | pass 184 | 185 | class InterfaceError(Error): 186 | """Exception for errors related to the interface""" 187 | pass 188 | 189 | class DatabaseError(Error): 190 | """Exception for errors related to the database""" 191 | pass 192 | 193 | class InternalError(DatabaseError): 194 | """Exception for errors internal database errors""" 195 | pass 196 | 197 | class OperationalError(DatabaseError): 198 | """Exception for errors related to the database's operation""" 199 | pass 200 | 201 | class ProgrammingError(DatabaseError): 202 | """Exception for errors programming errors""" 203 | pass 204 | 205 | class IntegrityError(DatabaseError): 206 | """Exception for errors regarding relational integrity""" 207 | pass 208 | 209 | class DataError(DatabaseError): 210 | """Exception for errors reporting problems with processed data""" 211 | pass 212 | 213 | class NotSupportedError(DatabaseError): 214 | """Exception for errors when an unsupported database feature was used""" 215 | pass 216 | 217 | _SQLSTATE_CLASS_EXCEPTION = { 218 | '02': DataError, # no data 219 | '07': DatabaseError, # dynamic SQL error 220 | '08': OperationalError, # connection exception 221 | '0A': NotSupportedError, # feature not supported 222 | '21': DataError, # cardinality violation 223 | '22': DataError, # data exception 224 | '23': IntegrityError, # integrity constraint violation 225 | '24': ProgrammingError, # invalid cursor state 226 | '25': ProgrammingError, # invalid transaction state 227 | '26': ProgrammingError, # invalid SQL statement name 228 | '27': ProgrammingError, # triggered data change violation 229 | '28': ProgrammingError, # invalid authorization specification 230 | '2A': ProgrammingError, # direct SQL syntax error or access rule violation 231 | '2B': DatabaseError, # dependent privilege descriptors still exist 232 | '2C': ProgrammingError, # invalid character set name 233 | '2D': DatabaseError, # invalid transaction termination 234 | '2E': DatabaseError, # invalid connection name 235 | '33': DatabaseError, # invalid SQL descriptor name 236 | '34': ProgrammingError, # invalid cursor name 237 | '35': ProgrammingError, # invalid condition number 238 | '37': ProgrammingError, # dynamic SQL syntax error or access rule violation 239 | '3C': ProgrammingError, # ambiguous cursor name 240 | '3D': ProgrammingError, # invalid catalog name 241 | '3F': ProgrammingError, # invalid schema name 242 | '40': InternalError, # transaction rollback 243 | '42': ProgrammingError, # syntax error or access rule violation 244 | '44': InternalError, # with check option violation 245 | 'HZ': OperationalError, # remote database access 246 | 'XA': IntegrityError, 247 | '0K': OperationalError, 248 | 'HY': DatabaseError, # default when no SQLState provided by MySQL server 249 | } 250 | 251 | -------------------------------------------------------------------------------- /locales.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | 25 | __all__ = [ 26 | 'get_client_error' 27 | ] 28 | 29 | import errorcode 30 | 31 | def get_client_error(error, language='eng'): 32 | """Lookup client error 33 | 34 | This function will lookup the client error message based on the given 35 | error and return the error message. If the error was not found, 36 | None will be returned. 37 | 38 | Error can be either an integer or a string. For example: 39 | error: 2000 40 | error: CR_UNKNOWN_ERROR 41 | 42 | The language attribute can be used to retrieve a localized message, when 43 | available. 44 | 45 | Returns a string or None. 46 | """ 47 | try: 48 | tmp = __import__('locales.%s' % language, 49 | globals(), locals(), ['client_error']) 50 | except ImportError: 51 | raise ImportError("No localization support for language '%s'" % ( 52 | language)) 53 | client_error = tmp.client_error 54 | 55 | if isinstance(error, int): 56 | errno = error 57 | for key, value in errorcode.__dict__.items(): 58 | if value == errno: 59 | error = key 60 | break 61 | 62 | if isinstance(error, (str)): 63 | try: 64 | return getattr(client_error, error) 65 | except AttributeError: 66 | return None 67 | 68 | raise ValueError("error argument needs to be either an integer or string") 69 | 70 | -------------------------------------------------------------------------------- /mysqldb.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """ 25 | MySQL Connector/Python - MySQL drive written in Python 26 | """ 27 | 28 | # Python Db API v2 29 | apilevel = '2.0' 30 | threadsafety = 1 31 | paramstyle = 'pyformat' 32 | 33 | from connection import MySQLConnection 34 | from errors import ( 35 | Error, Warning, InterfaceError, DatabaseError, 36 | NotSupportedError, DataError, IntegrityError, ProgrammingError, 37 | OperationalError, InternalError, custom_error_exception) 38 | from constants import (FieldFlag, FieldType, CharacterSet, 39 | RefreshOption, ClientFlag) 40 | from dbapi import * 41 | 42 | def Connect(*args, **kwargs): 43 | """Shortcut for creating a connection.MySQLConnection object.""" 44 | return MySQLConnection(*args, **kwargs) 45 | connect = Connect 46 | 47 | __all__ = [ 48 | 'MySQLConnection', 'Connect', 'custom_error_exception', 49 | 50 | # Some useful constants 51 | 'FieldType','FieldFlag','ClientFlag','CharacterSet','RefreshOption', 52 | 53 | # Error handling 54 | 'Error','Warning', 55 | 'InterfaceError','DatabaseError', 56 | 'NotSupportedError','DataError','IntegrityError','ProgrammingError', 57 | 'OperationalError','InternalError', 58 | 59 | # DBAPI PEP 249 required exports 60 | 'connect','apilevel','threadsafety','paramstyle', 61 | 'Date', 'Time', 'Timestamp', 'Binary', 62 | 'DateFromTicks', 'DateFromTicks', 'TimestampFromTicks', 63 | 'STRING', 'BINARY', 'NUMBER', 64 | 'DATETIME', 'ROWID', 65 | ] 66 | -------------------------------------------------------------------------------- /network.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Module implementing low-level socket communication with MySQL servers. 25 | """ 26 | 27 | import os 28 | import socket 29 | import struct 30 | from collections import deque 31 | import zlib 32 | try: 33 | import ssl 34 | except ImportError: 35 | # If import fails, we don't have SSL support. 36 | pass 37 | 38 | import constants, errors, utils 39 | 40 | def _prepare_packets(buf, pktnr): 41 | """Prepare a packet for sending to the MySQL server""" 42 | pkts = [] 43 | buflen = len(buf) 44 | maxpktlen = constants.MAX_PACKET_LENGTH 45 | while buflen > maxpktlen: 46 | pkts.append('\xff\xff\xff' + struct.pack(' maxpktlen: 116 | pkts = _prepare_packets(buf, pktnr) 117 | tmpbuf = ''.join(pkts) 118 | del pkts 119 | seqid = 0 120 | zbuf = zlib.compress(tmpbuf[:16384]) 121 | zpkts.append(struct.pack(' maxpktlen: 128 | zbuf = zlib.compress(tmpbuf[:maxpktlen]) 129 | zpkts.append(struct.pack(' 50: 148 | zbuf = zlib.compress(pkt) 149 | zpkts.append(struct.pack(' 0: 184 | chunk = self.sock.recv(rest) 185 | if not chunk: 186 | raise errors.InterfaceError(errno=2013) 187 | packet += chunk 188 | rest = packet_totlen - len(packet) 189 | 190 | return packet 191 | except socket.timeout, err: 192 | raise errors.InterfaceError(errno=2013) 193 | except socket.error, err: 194 | try: 195 | msg = err.errno 196 | if msg is None: 197 | msg = str(err) 198 | except AttributeError: 199 | msg = str(err) 200 | raise errors.InterfaceError(errno=2055, 201 | values=(self.get_address(), msg)) 202 | recv = recv_plain 203 | 204 | def _split_zipped_payload(self, packet_bunch): 205 | """Split compressed payload""" 206 | while packet_bunch: 207 | payload_length = struct.unpack(", like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Implementing the MySQL Client/Server protocol 25 | """ 26 | 27 | import struct 28 | from decimal import Decimal 29 | 30 | try: 31 | from hashlib import sha1 32 | except ImportError: 33 | from sha import new as sha1 34 | 35 | from constants import (FieldFlag, ServerCmd) 36 | import errors, utils 37 | 38 | class MySQLProtocol(object): 39 | def _scramble_password(self, passwd, seed): 40 | """Scramble a password ready to send to MySQL""" 41 | hash4 = None 42 | try: 43 | hash1 = sha1(passwd).digest() 44 | hash2 = sha1(hash1).digest() # Password as found in mysql.user() 45 | hash3 = sha1(seed + hash2).digest() 46 | xored = [ utils.intread(h1) ^ utils.intread(h3) 47 | for (h1,h3) in zip(hash1, hash3) ] 48 | hash4 = struct.pack('20B', *xored) 49 | except Exception, err: 50 | raise errors.InterfaceError( 51 | 'Failed scrambling password; %s' % err) 52 | 53 | return hash4 54 | 55 | def _prepare_auth(self, usr, pwd, db, flags, seed): 56 | """Prepare elements of the authentication packet""" 57 | 58 | if usr is not None and len(usr) > 0: 59 | if isinstance(usr, unicode): 60 | usr = usr.encode('utf8') 61 | _username = usr + '\x00' 62 | else: 63 | _username = '\x00' 64 | 65 | if pwd is not None and len(pwd) > 0: 66 | if isinstance(pwd, unicode): 67 | pwd = pwd.encode('utf8') 68 | _password = utils.int1store(20) +\ 69 | self._scramble_password(pwd,seed) 70 | else: 71 | _password = '\x00' 72 | 73 | if db is not None and len(db): 74 | _database = db + '\x00' 75 | else: 76 | _database = '\x00' 77 | 78 | return (_username, _password, _database) 79 | 80 | def make_auth(self, seed, username=None, password=None, database=None, 81 | charset=33, client_flags=0, 82 | max_allowed_packet=1073741824): 83 | """Make a MySQL Authentication packet""" 84 | if not seed: 85 | raise errors.ProgrammingError('Seed missing') 86 | 87 | auth = self._prepare_auth(username, password, database, 88 | client_flags, seed) 89 | return utils.int4store(client_flags) +\ 90 | utils.int4store(max_allowed_packet) +\ 91 | utils.int1store(charset) +\ 92 | '\x00' * 23 + auth[0] + auth[1] + auth[2] 93 | 94 | def make_auth_ssl(self, charset=33, client_flags=0, 95 | max_allowed_packet=1073741824): 96 | """Make a SSL authentication packet""" 97 | return utils.int4store(client_flags) +\ 98 | utils.int4store(max_allowed_packet) +\ 99 | utils.int1store(charset) +\ 100 | '\x00' * 23 101 | 102 | def make_command(self, command, argument=None): 103 | """Make a MySQL packet containing a command""" 104 | data = utils.int1store(command) 105 | if argument is not None: 106 | data += str(argument) 107 | return data 108 | 109 | def make_change_user(self, seed, username=None, password=None, 110 | database=None, charset=33, client_flags=0): 111 | """Make a MySQL packet with the Change User command""" 112 | if not seed: 113 | raise errors.ProgrammingError('Seed missing') 114 | 115 | auth = self._prepare_auth(username, password, database, 116 | client_flags, seed) 117 | data = utils.int1store(ServerCmd.CHANGE_USER) +\ 118 | auth[0] + auth[1] + auth[2] + utils.int2store(charset) 119 | return data 120 | 121 | def parse_handshake(self, packet): 122 | """Parse a MySQL Handshake-packet""" 123 | res = {} 124 | (packet, res['protocol']) = utils.read_int(packet[4:], 1) 125 | (packet, res['server_version_original']) = utils.read_string( 126 | packet, end='\x00') 127 | (packet, res['server_threadid']) = utils.read_int(packet, 4) 128 | (packet, res['scramble']) = utils.read_bytes(packet, 8) 129 | packet = packet[1:] # Filler 1 * \x00 130 | (packet, res['capabilities']) = utils.read_int(packet, 2) 131 | (packet, res['charset']) = utils.read_int(packet, 1) 132 | (packet, res['server_status']) = utils.read_int(packet, 2) 133 | packet = packet[13:] # Filler 13 * \x00 134 | (packet, scramble_next) = utils.read_bytes(packet, 12) 135 | res['scramble'] += scramble_next 136 | return res 137 | 138 | def parse_ok(self, packet): 139 | """Parse a MySQL OK-packet""" 140 | if not packet[4] == '\x00': 141 | raise errors.InterfaceError("Failed parsing OK packet.") 142 | 143 | ok = {} 144 | try: 145 | (packet, ok['field_count']) = utils.read_int(packet[4:], 1) 146 | (packet, ok['affected_rows']) = utils.read_lc_int(packet) 147 | (packet, ok['insert_id']) = utils.read_lc_int(packet) 148 | (packet, ok['server_status']) = utils.read_int(packet, 2) 149 | (packet, ok['warning_count']) = utils.read_int(packet, 2) 150 | if packet: 151 | (packet, ok['info_msg']) = utils.read_lc_string(packet) 152 | except ValueError: 153 | raise errors.InterfaceError("Failed parsing OK packet.") 154 | return ok 155 | 156 | def parse_column_count(self, packet): 157 | """Parse a MySQL packet with the number of columns in result set""" 158 | return utils.read_lc_int(packet[4:])[1] 159 | 160 | def parse_column(self, packet): 161 | """Parse a MySQL column-packet""" 162 | column = {} 163 | (packet, column['catalog']) = utils.read_lc_string(packet[4:]) 164 | (packet, column['db']) = utils.read_lc_string(packet) 165 | (packet, column['table']) = utils.read_lc_string(packet) 166 | (packet, column['org_table']) = utils.read_lc_string(packet) 167 | (packet, column['name']) = utils.read_lc_string(packet) 168 | (packet, column['org_name']) = utils.read_lc_string(packet) 169 | packet = packet[1:] # filler 1 * \x00 170 | (packet, column['charset']) = utils.read_int(packet, 2) 171 | (packet, column['length']) = utils.read_int(packet, 4) 172 | (packet, column['type']) = utils.read_int(packet, 1) 173 | (packet, column['flags']) = utils.read_int(packet, 2) 174 | (packet, column['decimal']) = utils.read_int(packet, 1) 175 | packet = packet[2:] # filler 2 * \x00 176 | 177 | return ( 178 | column['name'], 179 | column['type'], 180 | None, # display_size 181 | None, # internal_size 182 | None, # precision 183 | None, # scale 184 | ~column['flags'] & FieldFlag.NOT_NULL, # null_ok 185 | column['flags'], # MySQL specific 186 | ) 187 | 188 | def parse_eof(self, packet): 189 | """Parse a MySQL EOF-packet""" 190 | if not (packet[4] == '\xfe' and len(packet) <= 9): 191 | raise errors.InterfaceError("Failed parsing EOF packet.") 192 | 193 | res = {} 194 | packet = packet[5:] # disregard the first checking byte 195 | (packet, res['warning_count']) = utils.read_int(packet, 2) 196 | (packet, res['status_flag']) = utils.read_int(packet, 2) 197 | return res 198 | 199 | def parse_statistics(self, packet): 200 | """Parse the statistics packet""" 201 | errmsg = "Failed getting COM_STATISTICS information" 202 | res = {} 203 | # Information is separated by 2 spaces 204 | pairs = packet[4:].split('\x20\x20') 205 | for pair in pairs: 206 | try: 207 | (lbl, val) = [ v.strip() for v in pair.split(':', 2) ] 208 | except: 209 | raise errors.InterfaceError(errmsg) 210 | 211 | # It's either an integer or a decimal 212 | try: 213 | res[lbl] = long(val) 214 | except: 215 | try: 216 | res[lbl] = Decimal(val) 217 | except: 218 | raise errors.InterfaceError( 219 | "%s (%s:%s)." % (errmsg, lbl, val)) 220 | return res 221 | 222 | def read_text_result(self, sock, count=1): 223 | """Read MySQL text result 224 | 225 | Reads all or given number of rows from the socket. 226 | 227 | Returns a tuple with 2 elements: a list with all rows and 228 | the EOF packet. 229 | """ 230 | rows = [] 231 | eof = None 232 | rowdata = None 233 | i = 0 234 | while True: 235 | if eof is not None: 236 | break 237 | if i == count: 238 | break 239 | packet = sock.recv() 240 | if packet[0:3] == '\xff\xff\xff': 241 | data = packet[4:] 242 | packet = sock.recv() 243 | while packet[0:3] == '\xff\xff\xff': 244 | data += packet[4:] 245 | packet = sock.recv() 246 | if packet[4] == '\xfe': 247 | eof = self.parse_eof(packet) 248 | else: 249 | data += packet[4:] 250 | rowdata = utils.read_lc_string_list(data) 251 | elif packet[4] == '\xfe': 252 | eof = self.parse_eof(packet) 253 | rowdata = None 254 | else: 255 | eof = None 256 | rowdata = utils.read_lc_string_list(packet[4:]) 257 | if eof is None and rowdata is not None: 258 | rows.append(rowdata) 259 | i += 1 260 | return (rows, eof) 261 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Utilities 25 | """ 26 | 27 | __MYSQL_DEBUG__ = False 28 | 29 | import struct 30 | 31 | def intread(b): 32 | """Unpacks the given buffer to an integer""" 33 | try: 34 | if isinstance(b,int): 35 | return b 36 | l = len(b) 37 | if l == 1: 38 | return int(ord(b)) 39 | if l <= 4: 40 | tmp = b + '\x00'*(4-l) 41 | return struct.unpack(' 255: 55 | raise ValueError('int1store requires 0 <= i <= 255') 56 | else: 57 | return struct.pack(' 65535: 66 | raise ValueError('int2store requires 0 <= i <= 65535') 67 | else: 68 | return struct.pack(' 16777215: 77 | raise ValueError('int3store requires 0 <= i <= 16777215') 78 | else: 79 | return struct.pack(' 4294967295L: 88 | raise ValueError('int4store requires 0 <= i <= 4294967295') 89 | else: 90 | return struct.pack(' 18446744073709551616L: 99 | raise ValueError('int4store requires 0 <= i <= 2^64') 100 | else: 101 | return struct.pack(' 18446744073709551616: 113 | raise ValueError('intstore requires 0 <= i <= 2^64') 114 | 115 | if i <= 255: 116 | fs = int1store 117 | elif i <= 65535: 118 | fs = int2store 119 | elif i <= 16777215: 120 | fs = int3store 121 | elif i <= 4294967295L: 122 | fs = int4store 123 | else: 124 | fs = int8store 125 | 126 | return fs(i) 127 | 128 | def read_bytes(buf, size): 129 | """ 130 | Reads bytes from a buffer. 131 | 132 | Returns a tuple with buffer less the read bytes, and the bytes. 133 | """ 134 | s = buf[0:size] 135 | return (buf[size:], s) 136 | 137 | def read_lc_string(buf): 138 | """ 139 | Takes a buffer and reads a length coded string from the start. 140 | 141 | This is how Length coded strings work 142 | 143 | If the string is 250 bytes long or smaller, then it looks like this: 144 | 145 | <-- 1b --> 146 | +----------+------------------------- 147 | | length | a string goes here 148 | +----------+------------------------- 149 | 150 | If the string is bigger than 250, then it looks like this: 151 | 152 | <- 1b -><- 2/3/8 -> 153 | +------+-----------+------------------------- 154 | | type | length | a string goes here 155 | +------+-----------+------------------------- 156 | 157 | if type == \xfc: 158 | length is code in next 2 bytes 159 | elif type == \xfd: 160 | length is code in next 3 bytes 161 | elif type == \xfe: 162 | length is code in next 8 bytes 163 | 164 | NULL has a special value. If the buffer starts with \xfb then 165 | it's a NULL and we return None as value. 166 | 167 | Returns a tuple (trucated buffer, string). 168 | """ 169 | if buf[0] == '\xfb': 170 | # NULL value 171 | return (buf[1:], None) 172 | 173 | l = lsize = 0 174 | fst = ord(buf[0]) 175 | 176 | if fst <= 250: 177 | l = fst 178 | return (buf[1+l:], buf[1:l+1]) 179 | elif fst == 252: 180 | lsize = 2 181 | elif fst == 253: 182 | lsize = 3 183 | if fst == 254: 184 | lsize = 8 185 | 186 | l = intread(buf[1:lsize+1]) 187 | return (buf[lsize+l+1:], buf[lsize+1:l+lsize+1]) 188 | 189 | def read_lc_string_list(buf): 190 | """Reads all length encoded strings from the given buffer 191 | 192 | Returns a list of strings 193 | """ 194 | strlst = [] 195 | 196 | while buf: 197 | if buf[0] == '\xfb': 198 | # NULL value 199 | strlst.append(None) 200 | buf = buf[1:] 201 | continue 202 | 203 | l = lsize = 0 204 | fst = ord(buf[0]) 205 | 206 | if fst <= 250: 207 | l = fst 208 | strlst.append(buf[1:l+1]) 209 | buf = buf[1+l:] 210 | continue 211 | elif fst == 252: 212 | lsize = 2 213 | elif fst == 253: 214 | lsize = 3 215 | if fst == 254: 216 | lsize = 8 217 | 218 | l = intread(buf[1:lsize+1]) 219 | strlst.append(buf[lsize+1:l+lsize+1]) 220 | buf = buf[lsize+l+1:] 221 | 222 | return tuple(strlst) 223 | 224 | def read_string(buf, end=None, size=None): 225 | """ 226 | Reads a string up until a character or for a given size. 227 | 228 | Returns a tuple (trucated buffer, string). 229 | """ 230 | if end is None and size is None: 231 | raise ValueError('read_string() needs either end or size') 232 | 233 | if end is not None: 234 | try: 235 | idx = buf.index(end) 236 | except (ValueError), e: 237 | raise ValueError("end byte not precent in buffer") 238 | return (buf[idx+1:], buf[0:idx]) 239 | elif size is not None: 240 | return read_bytes(buf,size) 241 | 242 | raise ValueError('read_string() needs either end or size (weird)') 243 | 244 | def read_int(buf, size): 245 | """Read an integer from buffer 246 | 247 | Returns a tuple (truncated buffer, int) 248 | """ 249 | 250 | try: 251 | res = intread(buf[0:size]) 252 | except: 253 | raise 254 | 255 | return (buf[size:], res) 256 | 257 | def read_lc_int(buf): 258 | """ 259 | Takes a buffer and reads an length code string from the start. 260 | 261 | Returns a tuple with buffer less the integer and the integer read. 262 | """ 263 | if len(buf) == 0: 264 | raise ValueError("Empty buffer.") 265 | 266 | (buf,s) = read_int(buf,1) 267 | if s == 251: 268 | l = 0 269 | return (buf,None) 270 | elif s == 252: 271 | (buf,i) = read_int(buf,2) 272 | elif s == 253: 273 | (buf,i) = read_int(buf,3) 274 | elif s == 254: 275 | (buf,i) = read_int(buf,8) 276 | else: 277 | i = s 278 | 279 | return (buf, int(i)) 280 | 281 | # 282 | # For debugging 283 | # 284 | def _digest_buffer(buf): 285 | return ''.join([ "\\x%02x" % ord(c) for c in buf ]) 286 | 287 | -------------------------------------------------------------------------------- /version.py: -------------------------------------------------------------------------------- 1 | VERSION = (1, 0, 10, None, 0) 2 | 3 | --------------------------------------------------------------------------------