Skip to content

Commit 65292f5

Browse files
committed
Squash consecutive packs and unpacks, make them zero-copy.
To minimize function call number we should do one call to struct.unpack with long format string instead of series of calls with one-field format strings. This change also provides helper method to make all such unpacks with no extra data copying.
1 parent 4faf21c commit 65292f5

1 file changed

Lines changed: 15 additions & 23 deletions

File tree

pymysql/connections.py

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,12 @@ def read_length_coded_string(self):
352352
return None
353353
return self.read(length)
354354

355+
def read_struct(self, fmt):
356+
s = struct.Struct(fmt)
357+
result = s.unpack_from(self._data, self._position)
358+
self._position += s.size
359+
return result
360+
355361
def is_ok_packet(self):
356362
return self._data[0:1] == b'\0'
357363

@@ -405,13 +411,8 @@ def __parse_field_descriptor(self, encoding):
405411
self.org_table = self.read_length_coded_string().decode(encoding)
406412
self.name = self.read_length_coded_string().decode(encoding)
407413
self.org_name = self.read_length_coded_string().decode(encoding)
408-
self.advance(1) # non-null filler
409-
self.charsetnr = self.read_uint16()
410-
self.length = self.read_uint32()
411-
self.type_code = self.read_uint8()
412-
self.flags = self.read_uint16()
413-
self.scale = self.read_uint8() # "decimals"
414-
self.advance(2) # filler (always 0x00)
414+
self.charsetnr, self.length, self.type_code, self.flags, self.scale = (
415+
self.read_struct('<xHIBHBxx'))
415416
# 'default' is a length coded binary and is still in the buffer?
416417
# not used for normal result sets...
417418

@@ -455,8 +456,7 @@ def __init__(self, from_packet):
455456

456457
self.affected_rows = self.packet.read_length_encoded_integer()
457458
self.insert_id = self.packet.read_length_encoded_integer()
458-
self.server_status = struct.unpack('<H', self.packet.read(2))[0]
459-
self.warning_count = struct.unpack('<H', self.packet.read(2))[0]
459+
self.server_status, self.warning_count = self.read_struct('<HH')
460460
self.message = self.packet.read_all()
461461
self.has_next = self.server_status & SERVER_STATUS.SERVER_MORE_RESULTS_EXISTS
462462

@@ -478,9 +478,7 @@ def __init__(self, from_packet):
478478
self.__class__))
479479

480480
self.packet = from_packet
481-
from_packet.advance(1)
482-
self.warning_count = struct.unpack('<h', from_packet.read(2))[0]
483-
self.server_status = struct.unpack('<h', self.packet.read(2))[0]
481+
self.warning_count, self.server_status = self.packet.read_struct('<xhh')
484482
if DEBUG: print("server_status=", self.server_status)
485483
self.has_next = self.server_status & SERVER_STATUS.SERVER_MORE_RESULTS_EXISTS
486484

@@ -666,7 +664,7 @@ def close(self):
666664
''' Send the quit message and close the socket '''
667665
if self.socket is None:
668666
raise Error("Already closed")
669-
send_data = struct.pack('<i', 1) + int2byte(COMMAND.COM_QUIT)
667+
send_data = struct.pack('<iB', 1, COMMAND.COM_QUIT)
670668
try:
671669
self._write_bytes(send_data)
672670
except Exception:
@@ -885,14 +883,9 @@ def _read_packet(self, packet_type=MysqlPacket):
885883
while True:
886884
packet_header = self._read_bytes(4)
887885
if DEBUG: dump_packet(packet_header)
888-
packet_length_bin = packet_header[:3]
889-
886+
btrl, btrh, packet_number = struct.unpack('<HBB', packet_header)
887+
bytes_to_read = btrl + btrh * 65536
890888
#TODO: check sequence id
891-
# packet_number
892-
byte2int(packet_header[3])
893-
894-
bin_length = packet_length_bin + b'\0' # pad little-endian number
895-
bytes_to_read = struct.unpack('<I', bin_length)[0]
896889
recv_data = self._read_bytes(bytes_to_read)
897890
if DEBUG: dump_packet(recv_data)
898891
buff += recv_data
@@ -961,7 +954,7 @@ def _execute_command(self, command, sql):
961954

962955
chunk_size = min(MAX_PACKET_LEN, len(sql) + 1) # +1 is for command
963956

964-
prelude = struct.pack('<i', chunk_size) + int2byte(command)
957+
prelude = struct.pack('<iB', chunk_size, command)
965958
self._write_bytes(prelude + sql[:chunk_size-1])
966959
if DEBUG: dump_packet(prelude + sql)
967960

@@ -993,8 +986,7 @@ def _request_authentication(self):
993986
if isinstance(self.user, text_type):
994987
self.user = self.user.encode(self.encoding)
995988

996-
data_init = (struct.pack('<i', self.client_flag) + struct.pack("<I", 1) +
997-
int2byte(charset_id) + int2byte(0)*23)
989+
data_init = struct.pack('<iIB23s', self.client_flag, 1, charset_id, b'')
998990

999991
next_packet = 1
1000992

0 commit comments

Comments
 (0)