opt
/
hc_python
/
lib
/
python3.12
/
site-packages
/
mysql
/
connector
/
Go to Home Directory
+
Upload
Create File
root@0UT1S:~$
Execute
By Order of Mr.0UT1S
[DIR] ..
N/A
[DIR] __pycache__
N/A
[DIR] django
N/A
[DIR] fabric
N/A
[DIR] locales
N/A
__init__.py
7.06 KB
Rename
Delete
abstracts.py
38.65 KB
Rename
Delete
authentication.py
6.33 KB
Rename
Delete
catch23.py
3.49 KB
Rename
Delete
charsets.py
12.04 KB
Rename
Delete
connection.py
38.05 KB
Rename
Delete
connection_cext.py
20.29 KB
Rename
Delete
constants.py
23.21 KB
Rename
Delete
conversion.py
19.25 KB
Rename
Delete
cursor.py
43.89 KB
Rename
Delete
cursor_cext.py
25.19 KB
Rename
Delete
custom_types.py
1.63 KB
Rename
Delete
dbapi.py
2.28 KB
Rename
Delete
errorcode.py
38.25 KB
Rename
Delete
errors.py
9.99 KB
Rename
Delete
network.py
18.67 KB
Rename
Delete
optionfiles.py
13.53 KB
Rename
Delete
pooling.py
12.09 KB
Rename
Delete
protocol.py
27.29 KB
Rename
Delete
utils.py
8.95 KB
Rename
Delete
version.py
1.52 KB
Rename
Delete
# MySQL Connector/Python - MySQL driver written in Python. # Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most # MySQL Connectors. There are special exceptions to the terms and # conditions of the GPLv2 as it is applied to this software, see the # FOSS License Exception # <http://www.mysql.com/about/legal/licensing/foss-exception.html>. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """Implements the MySQL Client/Server protocol """ import struct import datetime from decimal import Decimal from .constants import ( FieldFlag, ServerCmd, FieldType, ClientFlag, MAX_MYSQL_TABLE_COLUMNS) from . import errors, utils from .authentication import get_auth_plugin from .catch23 import PY2, struct_unpack from .errors import get_exception class MySQLProtocol(object): """Implements MySQL client/server protocol Create and parses MySQL packets. """ def _connect_with_db(self, client_flags, database): """Prepare database string for handshake response""" if client_flags & ClientFlag.CONNECT_WITH_DB and database: return database.encode('utf8') + b'\x00' return b'\x00' def _auth_response(self, client_flags, username, password, database, auth_plugin, auth_data, ssl_enabled): """Prepare the authentication response""" if not password: return b'\x00' try: auth = get_auth_plugin(auth_plugin)( auth_data, username=username, password=password, database=database, ssl_enabled=ssl_enabled) plugin_auth_response = auth.auth_response() except (TypeError, errors.InterfaceError) as exc: raise errors.ProgrammingError( "Failed authentication: {0}".format(str(exc))) if client_flags & ClientFlag.SECURE_CONNECTION: resplen = len(plugin_auth_response) auth_response = struct.pack('<B', resplen) + plugin_auth_response else: auth_response = plugin_auth_response + b'\x00' return auth_response def make_auth(self, handshake, username=None, password=None, database=None, charset=33, client_flags=0, max_allowed_packet=1073741824, ssl_enabled=False, auth_plugin=None): """Make a MySQL Authentication packet""" try: auth_data = handshake['auth_data'] auth_plugin = auth_plugin or handshake['auth_plugin'] except (TypeError, KeyError) as exc: raise errors.ProgrammingError( "Handshake misses authentication info ({0})".format(exc)) if not username: username = b'' try: username_bytes = username.encode('utf8') # pylint: disable=E1103 except AttributeError: # Username is already bytes username_bytes = username packet = struct.pack('<IIB{filler}{usrlen}sx'.format( filler='x' * 23, usrlen=len(username_bytes)), client_flags, max_allowed_packet, charset, username_bytes) packet += self._auth_response(client_flags, username, password, database, auth_plugin, auth_data, ssl_enabled) packet += self._connect_with_db(client_flags, database) if client_flags & ClientFlag.PLUGIN_AUTH: packet += auth_plugin.encode('utf8') + b'\x00' return packet def make_auth_ssl(self, charset=33, client_flags=0, max_allowed_packet=1073741824): """Make a SSL authentication packet""" return utils.int4store(client_flags) + \ utils.int4store(max_allowed_packet) + \ utils.int1store(charset) + \ b'\x00' * 23 def make_command(self, command, argument=None): """Make a MySQL packet containing a command""" data = utils.int1store(command) if argument is not None: data += argument return data def make_change_user(self, handshake, username=None, password=None, database=None, charset=33, client_flags=0, ssl_enabled=False, auth_plugin=None): """Make a MySQL packet with the Change User command""" try: auth_data = handshake['auth_data'] auth_plugin = auth_plugin or handshake['auth_plugin'] except (TypeError, KeyError) as exc: raise errors.ProgrammingError( "Handshake misses authentication info ({0})".format(exc)) if not username: username = b'' try: username_bytes = username.encode('utf8') # pylint: disable=E1103 except AttributeError: # Username is already bytes username_bytes = username packet = struct.pack('<B{usrlen}sx'.format(usrlen=len(username_bytes)), ServerCmd.CHANGE_USER, username_bytes) packet += self._auth_response(client_flags, username, password, database, auth_plugin, auth_data, ssl_enabled) packet += self._connect_with_db(client_flags, database) packet += struct.pack('<H', charset) if client_flags & ClientFlag.PLUGIN_AUTH: packet += auth_plugin.encode('utf8') + b'\x00' return packet def parse_handshake(self, packet): """Parse a MySQL Handshake-packet""" res = {} res['protocol'] = struct_unpack('<xxxxB', packet[0:5])[0] (packet, res['server_version_original']) = utils.read_string( packet[5:], end=b'\x00') (res['server_threadid'], auth_data1, capabilities1, res['charset'], res['server_status'], capabilities2, auth_data_length ) = struct_unpack('<I8sx2sBH2sBxxxxxxxxxx', packet[0:31]) res['server_version_original'] = res['server_version_original'].decode() packet = packet[31:] capabilities = utils.intread(capabilities1 + capabilities2) auth_data2 = b'' if capabilities & ClientFlag.SECURE_CONNECTION: size = min(13, auth_data_length - 8) if auth_data_length else 13 auth_data2 = packet[0:size] packet = packet[size:] if auth_data2[-1] == 0: auth_data2 = auth_data2[:-1] if capabilities & ClientFlag.PLUGIN_AUTH: if (b'\x00' not in packet and res['server_version_original'].startswith("5.5.8")): # MySQL server 5.5.8 has a bug where end byte is not send (packet, res['auth_plugin']) = (b'', packet) else: (packet, res['auth_plugin']) = utils.read_string( packet, end=b'\x00') res['auth_plugin'] = res['auth_plugin'].decode('utf-8') else: res['auth_plugin'] = 'mysql_native_password' res['auth_data'] = auth_data1 + auth_data2 res['capabilities'] = capabilities return res def parse_ok(self, packet): """Parse a MySQL OK-packet""" if not packet[4] == 0: raise errors.InterfaceError("Failed parsing OK packet (invalid).") ok_packet = {} try: ok_packet['field_count'] = struct_unpack('<xxxxB', packet[0:5])[0] (packet, ok_packet['affected_rows']) = utils.read_lc_int(packet[5:]) (packet, ok_packet['insert_id']) = utils.read_lc_int(packet) (ok_packet['status_flag'], ok_packet['warning_count']) = struct_unpack('<HH', packet[0:4]) packet = packet[4:] if packet: (packet, ok_packet['info_msg']) = utils.read_lc_string(packet) ok_packet['info_msg'] = ok_packet['info_msg'].decode('utf-8') except ValueError: raise errors.InterfaceError("Failed parsing OK packet.") return ok_packet def parse_column_count(self, packet): """Parse a MySQL packet with the number of columns in result set""" try: count = utils.read_lc_int(packet[4:])[1] if count > MAX_MYSQL_TABLE_COLUMNS: return None return count except (struct.error, ValueError): raise errors.InterfaceError("Failed parsing column count") def parse_column(self, packet, charset='utf-8'): """Parse a MySQL column-packet""" (packet, _) = utils.read_lc_string(packet[4:]) # catalog (packet, _) = utils.read_lc_string(packet) # db (packet, _) = utils.read_lc_string(packet) # table (packet, _) = utils.read_lc_string(packet) # org_table (packet, name) = utils.read_lc_string(packet) # name (packet, _) = utils.read_lc_string(packet) # org_name try: (_, _, field_type, flags, _) = struct_unpack('<xHIBHBxx', packet) except struct.error: raise errors.InterfaceError("Failed parsing column information") return ( name.decode(charset), field_type, None, # display_size None, # internal_size None, # precision None, # scale ~flags & FieldFlag.NOT_NULL, # null_ok flags, # MySQL specific ) def parse_eof(self, packet): """Parse a MySQL EOF-packet""" if packet[4] == 0: # EOF packet deprecation return self.parse_ok(packet) err_msg = "Failed parsing EOF packet." res = {} try: unpacked = struct_unpack('<xxxBBHH', packet) except struct.error: raise errors.InterfaceError(err_msg) if not (unpacked[1] == 254 and len(packet) <= 9): raise errors.InterfaceError(err_msg) res['warning_count'] = unpacked[2] res['status_flag'] = unpacked[3] return res def parse_statistics(self, packet, with_header=True): """Parse the statistics packet""" errmsg = "Failed getting COM_STATISTICS information" res = {} # Information is separated by 2 spaces if with_header: pairs = packet[4:].split(b'\x20\x20') else: pairs = packet.split(b'\x20\x20') for pair in pairs: try: (lbl, val) = [v.strip() for v in pair.split(b':', 2)] except: raise errors.InterfaceError(errmsg) # It's either an integer or a decimal lbl = lbl.decode('utf-8') try: res[lbl] = int(val) except: try: res[lbl] = Decimal(val.decode('utf-8')) except: raise errors.InterfaceError( "{0} ({1}:{2}).".format(errmsg, lbl, val)) return res def read_text_result(self, sock, version, count=1): """Read MySQL text result Reads all or given number of rows from the socket. Returns a tuple with 2 elements: a list with all rows and the EOF packet. """ rows = [] eof = None rowdata = None i = 0 eof57 = version >= (5, 7, 5) while True: if eof or i == count: break packet = sock.recv() if packet.startswith(b'\xff\xff\xff'): datas = [packet[4:]] packet = sock.recv() while packet.startswith(b'\xff\xff\xff'): datas.append(packet[4:]) packet = sock.recv() datas.append(packet[4:]) rowdata = utils.read_lc_string_list(bytearray(b'').join(datas)) elif (packet[4] == 254 and packet[0] < 7): eof = self.parse_eof(packet) rowdata = None elif eof57 and (packet[4] == 0 and packet[0] > 9): # EOF deprecation: make sure we catch it whether flag is set or not eof = self.parse_ok(packet) rowdata = None else: eof = None rowdata = utils.read_lc_string_list(packet[4:]) if eof is None and rowdata is not None: rows.append(rowdata) elif eof is None and rowdata is None: raise get_exception(packet) i += 1 return rows, eof def _parse_binary_integer(self, packet, field): """Parse an integer from a binary packet""" if field[1] == FieldType.TINY: format_ = 'b' length = 1 elif field[1] == FieldType.SHORT: format_ = 'h' length = 2 elif field[1] in (FieldType.INT24, FieldType.LONG): format_ = 'i' length = 4 elif field[1] == FieldType.LONGLONG: format_ = 'q' length = 8 if field[7] & FieldFlag.UNSIGNED: format_ = format_.upper() return (packet[length:], struct_unpack(format_, packet[0:length])[0]) def _parse_binary_float(self, packet, field): """Parse a float/double from a binary packet""" if field[1] == FieldType.DOUBLE: length = 8 format_ = 'd' else: length = 4 format_ = 'f' return (packet[length:], struct_unpack(format_, packet[0:length])[0]) def _parse_binary_timestamp(self, packet, field): """Parse a timestamp from a binary packet""" length = packet[0] value = None if length == 4: value = datetime.date( year=struct_unpack('H', packet[1:3])[0], month=packet[3], day=packet[4]) elif length >= 7: mcs = 0 if length == 11: mcs = struct_unpack('I', packet[8:length + 1])[0] value = datetime.datetime( year=struct_unpack('H', packet[1:3])[0], month=packet[3], day=packet[4], hour=packet[5], minute=packet[6], second=packet[7], microsecond=mcs) return (packet[length + 1:], value) def _parse_binary_time(self, packet, field): """Parse a time value from a binary packet""" length = packet[0] data = packet[1:length + 1] mcs = 0 if length > 8: mcs = struct_unpack('I', data[8:])[0] days = struct_unpack('I', data[1:5])[0] if data[0] == 1: days *= -1 tmp = datetime.timedelta(days=days, seconds=data[7], microseconds=mcs, minutes=data[6], hours=data[5]) return (packet[length + 1:], tmp) def _parse_binary_values(self, fields, packet): """Parse values from a binary result packet""" null_bitmap_length = (len(fields) + 7 + 2) // 8 null_bitmap = [int(i) for i in packet[0:null_bitmap_length]] packet = packet[null_bitmap_length:] values = [] for pos, field in enumerate(fields): if null_bitmap[int((pos+2)/8)] & (1 << (pos + 2) % 8): values.append(None) continue elif field[1] in (FieldType.TINY, FieldType.SHORT, FieldType.INT24, FieldType.LONG, FieldType.LONGLONG): (packet, value) = self._parse_binary_integer(packet, field) values.append(value) elif field[1] in (FieldType.DOUBLE, FieldType.FLOAT): (packet, value) = self._parse_binary_float(packet, field) values.append(value) elif field[1] in (FieldType.DATETIME, FieldType.DATE, FieldType.TIMESTAMP): (packet, value) = self._parse_binary_timestamp(packet, field) values.append(value) elif field[1] == FieldType.TIME: (packet, value) = self._parse_binary_time(packet, field) values.append(value) else: (packet, value) = utils.read_lc_string(packet) values.append(value) return tuple(values) def read_binary_result(self, sock, columns, count=1): """Read MySQL binary protocol result Reads all or given number of binary resultset rows from the socket. """ rows = [] eof = None values = None i = 0 while True: if eof is not None: break if i == count: break packet = sock.recv() if packet[4] == 254: eof = self.parse_eof(packet) values = None elif packet[4] == 0: eof = None values = self._parse_binary_values(columns, packet[5:]) if eof is None and values is not None: rows.append(values) elif eof is None and values is None: raise get_exception(packet) i += 1 return (rows, eof) def parse_binary_prepare_ok(self, packet): """Parse a MySQL Binary Protocol OK packet""" if not packet[4] == 0: raise errors.InterfaceError("Failed parsing Binary OK packet") ok_pkt = {} try: (packet, ok_pkt['statement_id']) = utils.read_int(packet[5:], 4) (packet, ok_pkt['num_columns']) = utils.read_int(packet, 2) (packet, ok_pkt['num_params']) = utils.read_int(packet, 2) packet = packet[1:] # Filler 1 * \x00 (packet, ok_pkt['warning_count']) = utils.read_int(packet, 2) except ValueError: raise errors.InterfaceError("Failed parsing Binary OK packet") return ok_pkt def _prepare_binary_integer(self, value): """Prepare an integer for the MySQL binary protocol""" field_type = None flags = 0 if value < 0: if value >= -128: format_ = 'b' field_type = FieldType.TINY elif value >= -32768: format_ = 'h' field_type = FieldType.SHORT elif value >= -2147483648: format_ = 'i' field_type = FieldType.LONG else: format_ = 'q' field_type = FieldType.LONGLONG else: flags = 128 if value <= 255: format_ = 'B' field_type = FieldType.TINY elif value <= 65535: format_ = 'H' field_type = FieldType.SHORT elif value <= 4294967295: format_ = 'I' field_type = FieldType.LONG else: field_type = FieldType.LONGLONG format_ = 'Q' return (struct.pack(format_, value), field_type, flags) def _prepare_binary_timestamp(self, value): """Prepare a timestamp object for the MySQL binary protocol This method prepares a timestamp of type datetime.datetime or datetime.date for sending over the MySQL binary protocol. A tuple is returned with the prepared value and field type as elements. Raises ValueError when the argument value is of invalid type. Returns a tuple. """ if isinstance(value, datetime.datetime): field_type = FieldType.DATETIME elif isinstance(value, datetime.date): field_type = FieldType.DATE else: raise ValueError( "Argument must a datetime.datetime or datetime.date") packed = (utils.int2store(value.year) + utils.int1store(value.month) + utils.int1store(value.day)) if isinstance(value, datetime.datetime): packed = (packed + utils.int1store(value.hour) + utils.int1store(value.minute) + utils.int1store(value.second)) if value.microsecond > 0: packed += utils.int4store(value.microsecond) packed = utils.int1store(len(packed)) + packed return (packed, field_type) def _prepare_binary_time(self, value): """Prepare a time object for the MySQL binary protocol This method prepares a time object of type datetime.timedelta or datetime.time for sending over the MySQL binary protocol. A tuple is returned with the prepared value and field type as elements. Raises ValueError when the argument value is of invalid type. Returns a tuple. """ if not isinstance(value, (datetime.timedelta, datetime.time)): raise ValueError( "Argument must a datetime.timedelta or datetime.time") field_type = FieldType.TIME negative = 0 mcs = None packed = b'' if isinstance(value, datetime.timedelta): if value.days < 0: negative = 1 (hours, remainder) = divmod(value.seconds, 3600) (mins, secs) = divmod(remainder, 60) packed += (utils.int4store(abs(value.days)) + utils.int1store(hours) + utils.int1store(mins) + utils.int1store(secs)) mcs = value.microseconds else: packed += (utils.int4store(0) + utils.int1store(value.hour) + utils.int1store(value.minute) + utils.int1store(value.second)) mcs = value.microsecond if mcs: packed += utils.int4store(mcs) packed = utils.int1store(negative) + packed packed = utils.int1store(len(packed)) + packed return (packed, field_type) def _prepare_stmt_send_long_data(self, statement, param, data): """Prepare long data for prepared statements Returns a string. """ packet = ( utils.int4store(statement) + utils.int2store(param) + data) return packet def make_stmt_execute(self, statement_id, data=(), parameters=(), flags=0, long_data_used=None, charset='utf8'): """Make a MySQL packet with the Statement Execute command""" iteration_count = 1 null_bitmap = [0] * ((len(data) + 7) // 8) values = [] types = [] packed = b'' if long_data_used is None: long_data_used = {} if parameters and data: if len(data) != len(parameters): raise errors.InterfaceError( "Failed executing prepared statement: data values does not" " match number of parameters") for pos, _ in enumerate(parameters): value = data[pos] flags = 0 if value is None: null_bitmap[(pos // 8)] |= 1 << (pos % 8) types.append(utils.int1store(FieldType.NULL) + utils.int1store(flags)) continue elif pos in long_data_used: if long_data_used[pos][0]: # We suppose binary data field_type = FieldType.BLOB else: # We suppose text data field_type = FieldType.STRING elif isinstance(value, int): (packed, field_type, flags) = self._prepare_binary_integer(value) values.append(packed) elif isinstance(value, str): if PY2: values.append(utils.lc_int(len(value)) + value) else: value = value.encode(charset) values.append( utils.lc_int(len(value)) + value) field_type = FieldType.VARCHAR elif isinstance(value, bytes): values.append(utils.lc_int(len(value)) + value) field_type = FieldType.BLOB elif PY2 and \ isinstance(value, unicode): # pylint: disable=E0602 value = value.encode(charset) values.append(utils.lc_int(len(value)) + value) field_type = FieldType.VARCHAR elif isinstance(value, Decimal): values.append( utils.lc_int(len(str(value).encode( charset))) + str(value).encode(charset)) field_type = FieldType.DECIMAL elif isinstance(value, float): values.append(struct.pack('d', value)) field_type = FieldType.DOUBLE elif isinstance(value, (datetime.datetime, datetime.date)): (packed, field_type) = self._prepare_binary_timestamp( value) values.append(packed) elif isinstance(value, (datetime.timedelta, datetime.time)): (packed, field_type) = self._prepare_binary_time(value) values.append(packed) else: raise errors.ProgrammingError( "MySQL binary protocol can not handle " "'{classname}' objects".format( classname=value.__class__.__name__)) types.append(utils.int1store(field_type) + utils.int1store(flags)) packet = ( utils.int4store(statement_id) + utils.int1store(flags) + utils.int4store(iteration_count) + b''.join([struct.pack('B', bit) for bit in null_bitmap]) + utils.int1store(1) ) for a_type in types: packet += a_type for a_value in values: packet += a_value return packet def parse_auth_switch_request(self, packet): """Parse a MySQL AuthSwitchRequest-packet""" if not packet[4] == 254: raise errors.InterfaceError( "Failed parsing AuthSwitchRequest packet") (packet, plugin_name) = utils.read_string(packet[5:], end=b'\x00') if packet and packet[-1] == 0: packet = packet[:-1] return plugin_name.decode('utf8'), packet def parse_auth_more_data(self, packet): """Parse a MySQL AuthMoreData-packet""" if not packet[4] == 1: raise errors.InterfaceError( "Failed parsing AuthMoreData packet") return packet[5:]
Save