Skip to content

Commit d2ef033

Browse files
authored
Merge pull request #602 from dongwook-chan/fix/rows-query-parsing
Fix parsing of query field of RowsQueryEvent
2 parents fb82d6d + 7d1cc41 commit d2ef033

File tree

3 files changed

+36
-4
lines changed

3 files changed

+36
-4
lines changed

pymysqlreplication/event.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -872,20 +872,18 @@ class RowsQueryLogEvent(BinLogEvent):
872872
More details are available in the MySQL Knowledge Base:
873873
https://dev.mysql.com/doc/dev/mysql-server/latest/classRows__query__log__event.html
874874
875-
:ivar query_length: uint - Length of the SQL statement
876875
:ivar query: str - The executed SQL statement
877876
"""
878877

879878
def __init__(self, from_packet, event_size, table_map, ctl_connection, **kwargs):
880879
super(RowsQueryLogEvent, self).__init__(
881880
from_packet, event_size, table_map, ctl_connection, **kwargs
882881
)
883-
self.query_length = self.packet.read_uint8()
884-
self.query = self.packet.read(self.query_length).decode("utf-8")
882+
self.packet.advance(1)
883+
self.query = self.packet.read_available().decode("utf-8")
885884

886885
def dump(self):
887886
print(f"=== {self.__class__.__name__} ===")
888-
print(f"Query length: {self.query_length}")
889887
print(f"Query: {self.query}")
890888

891889

pymysqlreplication/packet.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from pymysqlreplication import constants, event, row_event
22
from pymysqlreplication.json_binary import parse_json, JsonDiff, JsonDiffOperation
33
from pymysqlreplication.util.bytes import *
4+
from pymysqlreplication.constants import BINLOG
45

56
# Constants from PyMYSQL source code
67
NULL_COLUMN = 251
@@ -384,3 +385,6 @@ def read_string(self):
384385

385386
def bytes_to_read(self):
386387
return len(self.packet._data) - self.packet._position
388+
389+
def read_available(self):
390+
return self.packet.read(self.bytes_to_read() - BINLOG.BINLOG_CHECKSUM_LEN)

pymysqlreplication/tests/test_basic.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,6 +1567,36 @@ def test_rows_query_log_event(self):
15671567
event = self.stream.fetchone()
15681568
self.assertIsInstance(event, RowsQueryLogEvent)
15691569

1570+
def test_long_query(self):
1571+
"""
1572+
Address issue #601
1573+
Do not use the first byte of the body to determine the length of the query.
1574+
1 byte can not represent the length of a query that is longer than 255 bytes.
1575+
"""
1576+
1577+
self.stream.close()
1578+
self.stream = BinLogStreamReader(
1579+
self.database,
1580+
server_id=1024,
1581+
only_events=[RowsQueryLogEvent],
1582+
)
1583+
1584+
self.execute(
1585+
"CREATE TABLE IF NOT EXISTS test (id INT AUTO_INCREMENT PRIMARY KEY, long_text VARCHAR(256))"
1586+
)
1587+
long_query = (
1588+
"INSERT INTO test (long_text) VALUES ('"
1589+
"What is the longest word in english?"
1590+
"Pneumonoultramicroscopicsilicovolcanoconiosis is the longest word in the English language."
1591+
"This text has 256 characters and hence its length can not be represented in a single byte."
1592+
"')"
1593+
)
1594+
self.execute(long_query)
1595+
self.execute("COMMIT")
1596+
event = self.stream.fetchone()
1597+
self.assertIsInstance(event, RowsQueryLogEvent)
1598+
self.assertEqual(event.query, long_query)
1599+
15701600

15711601
class TestLatin1(base.PyMySQLReplicationTestCase):
15721602
def setUp(self):

0 commit comments

Comments
 (0)