Skip to content

Commit 3957b7e

Browse files
Merge pull request #397 from dongwook-chan/fix-mariadb-only-status-vars
Fix parse error for query_events (fix for PR#360)
2 parents 7e007c9 + ef7fc4b commit 3957b7e

File tree

5 files changed

+54
-2
lines changed

5 files changed

+54
-2
lines changed

pymysqlreplication/constants/STATUS_VAR_KEY.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@
2727
Q_TABLE_MAP_FOR_UPDATE_CODE = 0x09
2828
Q_MASTER_DATA_WRITTEN_CODE = 0x0A
2929
Q_INVOKER = 0x0B
30-
Q_UPDATED_DB_NAMES = 0x0C
31-
Q_MICROSECONDS = 0x0D
30+
Q_UPDATED_DB_NAMES = 0x0C # MySQL only
31+
Q_MICROSECONDS = 0x0D # MySQL only
3232
Q_COMMIT_TS = 0x0E
3333
Q_COMMIT_TS2 = 0X0F
3434
Q_EXPLICIT_DEFAULTS_FOR_TIMESTAMP = 0X10
3535
Q_DDL_LOGGED_WITH_XID = 0X11
3636
Q_DEFAULT_COLLATION_FOR_UTF8MB4 = 0X12
3737
Q_SQL_REQUIRE_PRIMARY_KEY = 0X13
3838
Q_DEFAULT_TABLE_ENCRYPTION = 0X14
39+
Q_HRNOW = 0x80 # MariaDB only
40+
Q_XID = 0x81 # MariaDB only

pymysqlreplication/event.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import struct
55
import datetime
66
from pymysqlreplication.constants.STATUS_VAR_KEY import *
7+
from pymysqlreplication.exceptions import StatusVariableMismatch
78

89

910
class BinLogEvent(object):
@@ -291,6 +292,12 @@ def _read_status_vars_value_for_key(self, key):
291292
self.sql_require_primary_key = self.packet.read_uint8()
292293
elif key == Q_DEFAULT_TABLE_ENCRYPTION: # 0x14
293294
self.default_table_encryption = self.packet.read_uint8()
295+
elif key == Q_HRNOW:
296+
self.hrnow = self.packet.read_uint24()
297+
elif key == Q_XID:
298+
self.xid = self.packet.read_uint64()
299+
else:
300+
raise StatusVariableMismatch
294301

295302
class BeginLoadQueryEvent(BinLogEvent):
296303
"""

pymysqlreplication/exceptions.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,14 @@ def __init__(self, table):
66
class BinLogNotEnabled(Exception):
77
def __init__(self):
88
Exception.__init__(self, "MySQL binary logging is not enabled.")
9+
10+
11+
class StatusVariableMismatch(Exception):
12+
def __init__(self):
13+
Exception.__init__(self, " ".join(
14+
"Unknown status variable in query event."
15+
, "Possible parse failure in preceding fields"
16+
, "or outdated constants.STATUS_VAR_KEY"
17+
, "Refer to MySQL documentation/source code"
18+
, "or create an issue on GitHub"
19+
))

pymysqlreplication/tests/base.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def setUp(self):
4343
self.stream = None
4444
self.resetBinLog()
4545
self.isMySQL56AndMore()
46+
self.__is_mariaDB = None
4647

4748
def getMySQLVersion(self):
4849
"""Return the MySQL version of the server
@@ -64,6 +65,11 @@ def isMySQL80AndMore(self):
6465
version = float(self.getMySQLVersion().rsplit('.', 1)[0])
6566
return version >= 8.0
6667

68+
def isMariaDB(self):
69+
if self.__is_mariaDB is None:
70+
self.__is_mariaDB = "MariaDB" in self.execute("SELECT VERSION()").fetchone()
71+
return self.__is_mariaDB
72+
6773
@property
6874
def supportsGTID(self):
6975
if not self.isMySQL56AndMore():

pymysqlreplication/tests/test_data_type.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,5 +773,31 @@ def test_null_bitmask(self):
773773
self.assertEqual(event.event_type, TABLE_MAP_EVENT)
774774
self.assertEqual(event.null_bitmask, bit_mask)
775775

776+
def test_mariadb_only_status_vars(self):
777+
"""Test parse of mariadb exclusive status variables (a field in query event)
778+
779+
A query event for mariadb must be parsed successfully
780+
since mariadb exclusive status variables are now taken to account
781+
(Q_HRNOW, Q_XID)
782+
Test if was parse successful by asserting the last field of the event,
783+
'SQL statement'.
784+
785+
Raises:
786+
StatusVariableMismatch: This is the case where new status variables are added to
787+
mysql server. Same set of status variables must be added to the library as well.
788+
"""
789+
if not self.isMariaDB():
790+
return
791+
792+
create_query = "CREATE TABLE test (id INTEGER)"
793+
event = self.create_table(create_query)
794+
795+
# skip dummy events with empty schema
796+
while event.schema == b'':
797+
event = self.stream.fetchone()
798+
799+
self.assertEqual(event.query, create_query)
800+
801+
776802
if __name__ == "__main__":
777803
unittest.main()

0 commit comments

Comments
 (0)