Skip to content

Commit a28ba4d

Browse files
author
Geert Vanderkelen
committed
BUG19169990: Fix sending/receiving using compressed connection
We fix the the send and receiving of compressed packages when the compress connection argument is set too True. A test case for BUG#19169990 was added.
1 parent baa7aeb commit a28ba4d

File tree

3 files changed

+64
-23
lines changed

3 files changed

+64
-23
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Full release notes:
1111
v2.0.0a1
1212
========
1313

14+
- BUG19169990: Fix sending/receiving using compressed connection
1415
- BUG18956789: Fix Django TimeField 00:00:00 converting to MySQL NULL
1516
- WL7228: Allow Connector/Python to use MySQL option files
1617
- BUG18843153: Fix Django to check connection on each request

lib/mysql/connector/network.py

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -139,34 +139,50 @@ def send_compressed(self, buf, packet_number=None):
139139
maxpktlen = constants.MAX_PACKET_LENGTH
140140
if pllen > maxpktlen:
141141
pkts = _prepare_packets(buf, pktnr)
142-
tmpbuf = b''.join(pkts)
142+
if PY2:
143+
tmpbuf = bytearray()
144+
for pkt in pkts:
145+
tmpbuf += pkt
146+
tmpbuf = buffer(tmpbuf)
147+
else:
148+
tmpbuf = b''.join(pkts)
143149
del pkts
144150
seqid = 0
145151
zbuf = zlib.compress(tmpbuf[:16384])
146-
zpkts.append(struct.pack('<I', len(zbuf))[0:3]
147-
+ struct.pack('<B', seqid)
148-
+ b'\x00\x40\x00' + zbuf)
152+
header = (struct.pack('<I', len(zbuf))[0:3]
153+
+ struct.pack('<B', seqid)
154+
+ b'\x00\x40\x00')
155+
if PY2:
156+
header = buffer(header)
157+
zpkts.append(header + zbuf)
149158
tmpbuf = tmpbuf[16384:]
150159
pllen = len(tmpbuf)
151160
seqid = seqid + 1
152161
while pllen > maxpktlen:
153162
zbuf = zlib.compress(tmpbuf[:maxpktlen])
154-
zpkts.append(struct.pack('<I', len(zbuf))[0:3]
155-
+ struct.pack('<B', seqid)
156-
+ b'\xff\xff\xff' + zbuf)
163+
header = (struct.pack('<I', len(zbuf))[0:3]
164+
+ struct.pack('<B', seqid)
165+
+ b'\xff\xff\xff')
166+
if PY2:
167+
header = buffer(header)
168+
zpkts.append(header + zbuf)
157169
tmpbuf = tmpbuf[maxpktlen:]
158170
pllen = len(tmpbuf)
159171
seqid = seqid + 1
160172
if tmpbuf:
161173
zbuf = zlib.compress(tmpbuf)
162-
zpkts.append(struct.pack('<I', len(zbuf))[0:3]
163-
+ struct.pack('<B', seqid)
164-
+ struct.pack('<I', pllen)[0:3]
165-
+ zbuf)
174+
header = (struct.pack('<I', len(zbuf))[0:3]
175+
+ struct.pack('<B', seqid)
176+
+ struct.pack('<I', pllen)[0:3])
177+
if PY2:
178+
header = buffer(header)
179+
zpkts.append(header + zbuf)
166180
del tmpbuf
167181
else:
168182
pkt = (struct.pack('<I', pllen)[0:3] +
169183
struct.pack('<B', pktnr) + buf)
184+
if PY2:
185+
pkt = buffer(pkt)
170186
pllen = len(pkt)
171187
if pllen > 50:
172188
zbuf = zlib.compress(pkt)
@@ -175,10 +191,12 @@ def send_compressed(self, buf, packet_number=None):
175191
+ struct.pack('<I', pllen)[0:3]
176192
+ zbuf)
177193
else:
178-
zpkts.append(struct.pack('<I', pllen)[0:3]
179-
+ struct.pack('<B', 0)
180-
+ struct.pack('<I', 0)[0:3]
181-
+ pkt)
194+
header = (struct.pack('<I', pllen)[0:3]
195+
+ struct.pack('<B', 0)
196+
+ struct.pack('<I', 0)[0:3])
197+
if PY2:
198+
header = buffer(header)
199+
zpkts.append(header + pkt)
182200

183201
for zip_packet in zpkts:
184202
try:
@@ -228,6 +246,7 @@ def recv_py26_plain(self):
228246
try:
229247
# Read the header of the MySQL packet, 4 bytes
230248
header = bytearray(b'')
249+
231250
while len(header) < 4:
232251
chunk = self.sock.recv(4)
233252
if not chunk:
@@ -273,7 +292,7 @@ def recv_compressed(self):
273292
except IndexError:
274293
pass
275294

276-
header = init_bytearray(b'')
295+
header = bytearray(b'')
277296
packets = []
278297
try:
279298
abyte = self.sock.recv(1)
@@ -308,19 +327,19 @@ def recv_compressed(self):
308327
raise errors.OperationalError(
309328
errno=2055, values=(self.get_address(), _strioerror(err)))
310329

311-
tmp = []
330+
tmp = init_bytearray(b'')
312331
for packet in packets:
313332
payload_length = struct_unpack("<I", header[4:7] + b'\x00')[0]
314333
if payload_length == 0:
315334
tmp.append(packet[7:])
316335
else:
317336
if PY2:
318-
tmp.append(zlib.decompress(
319-
buffer(packet[7:]))) # pylint: disable=E0602
337+
tmp += zlib.decompress(
338+
buffer(packet[7:])) # pylint: disable=E0602
320339
else:
321-
tmp.append(zlib.decompress(packet[7:]))
340+
tmp += zlib.decompress(packet[7:])
322341

323-
self._split_zipped_payload(b''.join(tmp))
342+
self._split_zipped_payload(tmp)
324343
del tmp
325344

326345
try:

tests/test_bugs.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,18 @@
3636
"""
3737

3838
import os
39-
import sys
4039
import gc
4140
import tempfile
4241
from datetime import datetime, timedelta
4342
from threading import Thread
43+
import traceback
4444
import time
4545
import unittest
4646

4747
import tests
4848
from . import PY2
4949
from mysql.connector import (connection, cursor, conversion, protocol,
5050
errors, constants, pooling)
51-
from mysql.connector import connect, _CONNECTION_POOLS
5251
import mysql.connector
5352

5453

@@ -2613,3 +2612,25 @@ def test_columns(self):
26132612
self.cursor.execute(stmt, (0,))
26142613
self.assertEqual(exp, self.cursor.fetchone())
26152614

2615+
2616+
class BugOra19169990(tests.MySQLConnectorTests):
2617+
"""BUG#19169990: Issue with compressed cnx using Python 2
2618+
"""
2619+
def setUp(self):
2620+
self.config = tests.get_mysql_config()
2621+
self.config['compress'] = True
2622+
2623+
def test_compress(self):
2624+
for charset in ('utf8', 'latin1', 'latin7'):
2625+
self.config['charset'] = charset
2626+
try:
2627+
cnx = connection.MySQLConnection(**self.config)
2628+
cur = cnx.cursor()
2629+
cur.execute("SELECT %s", ('mysql'*10000,))
2630+
except TypeError:
2631+
traceback.print_exc()
2632+
self.fail("Failed setting up compressed cnx using {0}".format(
2633+
charset
2634+
))
2635+
except errors.Error:
2636+
self.fail("Failed sending/retrieving compressed data")

0 commit comments

Comments
 (0)