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 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 binlog_dump(self, log_file, offset): """ COM_BINLOG_DUMP +=============================================+ | packet header | packet length 0 : 3 | | +-------------------------+ | | sequence number 3 : 1 | +============================================+ | command packet | command code 4 : 1 | COM_BINLOG_DUMP | +------------------------―+ | | offset 5 : 4 | | +-------------------------+ | | flags 9 : 2 | | +-------------------------+ | | server id 11 : 4| | +-------------------------+ | | log name 15 : x| +============================================+ """ payload = '' payload += utils.int1store(ServerCmd.BINLOG_DUMP) payload += utils.int4store(offset) payload += utils.int2store(0) payload += utils.int4store(self.get_server_id()) payload += log_file payload += '\x00' log.debug("len(payload) = %d" % len(payload)) # send BIGLOGDUMP command and parse ok packet response. self._socket.send(payload, 0) ok_packet = self._socket.recv() parser = MySQLProtocol() ok_packet = parser.parse_ok(ok_packet) print ok_packet
def make_auth( self, seed, username=None, password=None, database=None, charset=33, client_flags=0, max_allowed_packet=1073741824, ): """Make a MySQL Authentication packet""" if not seed: raise errors.ProgrammingError("Seed missing") auth = self._prepare_auth(username, password, database, client_flags, seed) data = ( utils.int4store(client_flags) + utils.int4store(max_allowed_packet) + utils.int1store(charset) + b"\x00" * 23 + auth[0] + auth[1] + auth[2] ) return data
def binlog_dump(self, log_file, offset): """ COM_BINLOG_DUMP +=============================================+ | packet header | packet length 0 : 3 | | +-------------------------+ | | sequence number 3 : 1 | +============================================+ | command packet | command code 4 : 1 | COM_BINLOG_DUMP | +------------------------―+ | | offset 5 : 4 | | +-------------------------+ | | flags 9 : 2 | | +-------------------------+ | | server id 11 : 4| | +-------------------------+ | | log name 15 : x| +============================================+ """ payload = "" payload += utils.int1store(ServerCmd.BINLOG_DUMP) payload += utils.int4store(offset) payload += utils.int2store(0) payload += utils.int4store(self.get_server_id()) payload += log_file payload += "\x00" log.debug("len(payload) = %d" % len(payload)) # send BIGLOGDUMP command and parse ok packet response. self._socket.send(payload, 0) ok_packet = self._socket.recv() parser = MySQLProtocol() ok_packet = parser.parse_ok(ok_packet) print ok_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) + \ '\x00' * 23
def make_change_user(self, seed, username=None, password=None, database=None, charset=33, client_flags=0): """Make a MySQL packet with the Change User command""" if not seed: raise errors.ProgrammingError("Seed missing") auth = self._prepare_auth(username, password, database, client_flags, seed) data = utils.int1store(ServerCmd.CHANGE_USER) + auth[0] + auth[1] + auth[2] + utils.int2store(charset) return data
def test_int1store(self): """Use int1store to pack an integer (2^8) as a string.""" data = 2**(8 - 1) exp = struct.pack('<B', data) try: result = utils.int1store(data) except ValueError, e: self.fail("int1store failed: %s" % e)
def test_int1store(self): """Use int1store to pack an integer (2^8) as a string.""" data = 2**(8-1) exp = struct.pack('<B',data) try: result = utils.int1store(data) except ValueError, e: self.fail("int1store failed: %s" % e)
def test_read_lc_string_1(self): """Read a length code string from a buffer ( <= 250 bytes)""" exp = b"a" * 2**(8 - 1) expsize = len(exp) lcs = utils.int1store(expsize) + exp (rest, result) = utils.read_lc_string(lcs) if result != exp or len(result) != expsize: self.fail("Wrong result. Expected '%d', got '%d'" %\ expsize, len(result))
def test_read_lc_string_1(self): """Read a length code string from a buffer ( <= 250 bytes)""" exp = bytearray(b"a" * 2 ** (8 - 1)) expsize = len(exp) lcs = utils.int1store(expsize) + exp (_, result) = utils.read_lc_string(lcs) if result != exp or len(result) != expsize: self.fail("Wrong result. Expected '{0}', got '{1}'".format( expsize, len(result)))
def test_read_lc_string_1(self): """Read a length code string from a buffer ( <= 250 bytes)""" exp = "a" * 2**(8-1) expsize = len(exp) lcs = utils.int1store(expsize) + exp (rest, result) = utils.read_lc_string(lcs) if result != exp or len(result) != expsize: self.fail("Wrong result. Expected '%d', got '%d'" %\ expsize, len(result))
def test_read_lc_string_1(self): """Read a length code string from a buffer ( <= 250 bytes)""" exp = bytearray(b"a" * 2**(8 - 1)) expsize = len(exp) lcs = utils.int1store(expsize) + exp (_, result) = utils.read_lc_string(lcs) if result != exp or len(result) != expsize: self.fail("Wrong result. Expected '{0}', got '{1}'".format( expsize, len(result)))
def test_int1store(self): """Use int1store to pack an integer (2^8) as a string.""" data = 2 ** (8 - 1) exp = struct.pack('<B', data) try: result = utils.int1store(data) except ValueError as err: self.fail("int1store failed: {0}".format(str(err))) else: self._check_int_result(result, exp, data)
def test_int1store(self): """Use int1store to pack an integer (2^8) as a string.""" data = 2**(8 - 1) exp = struct.pack('<B', data) try: result = utils.int1store(data) except ValueError as err: self.fail("int1store failed: {0}".format(str(err))) else: self._check_int_result(result, exp, data)
def make_change_user(self, seed, username=None, password=None, database=None, charset=33, client_flags=0): """Make a MySQL packet with the Change User command""" if not seed: raise errors.ProgrammingError('Seed missing') auth = self._prepare_auth(username, password, database, client_flags, seed) data = utils.int1store(ServerCmd.CHANGE_USER) +\ auth[0] + auth[1] + auth[2] + utils.int2store(charset) return data
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 make_auth(self, seed, username=None, password=None, database=None, charset=33, client_flags=0, max_allowed_packet=1073741824): """Make a MySQL Authentication packet""" if not seed: raise errors.ProgrammingError('Seed missing') auth = self._prepare_auth(username, password, database, client_flags, seed) return utils.int4store(client_flags) +\ utils.int4store(max_allowed_packet) +\ utils.int1store(charset) +\ '\x00' * 23 + auth[0] + auth[1] + auth[2]
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 test_int1store(self): """Use int1store to pack an integer (2^8) as a string.""" data = 2**(8-1) exp = struct.pack('<B',data) try: result = utils.int1store(data) except ValueError as e: self.fail("int1store failed: %s" % e) else: if not isinstance(result, str): self.fail("Wrong result. Expected %s, we got %s" %\ (type(exp), type(result))) elif exp != result: self.fail("Wrong result. Expected %s, we got %s" %\ (data, result))
def test_int1store(self): """Use int1store to pack an integer (2^8) as a string.""" data = 2**(8 - 1) exp = struct.pack('<B', data) try: result = utils.int1store(data) except ValueError as e: self.fail("int1store failed: %s" % e) else: if not isinstance(result, bytes): self.fail("Wrong result. Expected %s, we got %s" %\ (type(exp), type(result))) elif exp != result: self.fail("Wrong result. Expected %s, we got %s" %\ (data, result))
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 = '' 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_auth(self, usr, pwd, dbname, flags, seed): """Prepare elements of the authentication packet""" if usr is not None and len(usr) > 0: _username = usr.encode("utf-8") + b"\x00" else: _username = b"\x00" if pwd is not None and len(pwd) > 0: _password = utils.int1store(20) + self._scramble_password(pwd.encode("utf-8"), seed) else: _password = b"\x00" if dbname is not None and len(dbname): _database = dbname.encode("utf-8") + b"\x00" else: _database = b"\x00" return (_username, _password, _database)
def _prepare_auth(self, usr, pwd, db, flags, seed): """Prepare elements of the authentication packet""" if usr is not None and len(usr) > 0: _username = usr.encode('utf-8') + b'\x00' else: _username = b'\x00' if pwd is not None and len(pwd) > 0: _password = utils.int1store(20) +\ self._scramble_password(pwd.encode('utf-8'),seed) else: _password = b'\x00' if db is not None and len(db): _database = db.encode('utf-8') + b'\x00' else: _database = b'\x00' return (_username, _password, _database)
def _prepare_auth(self, usr, pwd, db, flags, seed): """Prepare elements of the authentication packet""" if usr is not None and len(usr) > 0: _username = usr + '\x00' else: _username = '******' if pwd is not None and len(pwd) > 0: _password = utils.int1store(20) +\ self._scramble_password(pwd,seed) else: _password = '******' if db is not None and len(db): _database = db + '\x00' else: _database = '\x00' return (_username, _password, _database)
def _prepare_auth(self, usr, pwd, dbname, flags, seed): """Prepare elements of the authentication packet""" if usr is not None and len(usr) > 0: if isinstance(usr, unicode): usr = usr.encode('utf8') _username = usr + '\x00' else: _username = '******' if pwd is not None and len(pwd) > 0: if isinstance(pwd, unicode): pwd = pwd.encode('utf8') _password = utils.int1store(20) +\ self._scramble_password(pwd, seed) else: _password = '******' if dbname is not None and len(dbname): _database = dbname.encode('utf8') + '\x00' else: _database = '\x00' return (_username, _password, _database)
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 = '' 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) 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, long)): (packed, field_type, flags) = self._prepare_binary_integer(value) values.append(packed) elif isinstance(value, str): values.append(utils.intstore(len(value)) + value) field_type = FieldType.VARCHAR elif isinstance(value, unicode): value = value.encode(charset) values.append(utils.intstore(len(value)) + value) field_type = FieldType.VARCHAR elif isinstance(value, Decimal): values.append(utils.intstore(len(str(value))) + str(value)) 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), ''.join([struct.pack('B', bit) for bit in null_bitmap]), utils.int1store(1), ''.join(types), ''.join(values) ) return ''.join(packet)
def make_command(self, command, argument=None): """Make a MySQL packet containing a command""" data = utils.int1store(command) if argument is not None: data += str(argument) return data
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) 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): value = value.encode(charset) values.append( utils.intstore(len(value)) + value) field_type = FieldType.VARCHAR elif isinstance(value, bytes): values.append(utils.intstore(len(value)) + value) field_type = FieldType.BLOB elif isinstance(value, Decimal): values.append( utils.intstore(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), b''.join(types), b''.join(values) ) return b''.join(packet)
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