Skip to content

Commit

Permalink
related issue: python-mysql-replication issue#380, pg_cameleon commit…
Browse files Browse the repository at this point in the history
…#38c7a90

Analysis
- Could not parse status variables in query events for MariaDB
- Because the library was not aware of MariaDB-exclusive status variables

Implementation
- Added MariaDB-only status variables
- Added Exception to raise when status variable parse failed
- Added tests for parsing query events for MariaDB
  • Loading branch information
dongwook-chan committed Feb 25, 2023
1 parent 7e007c9 commit ef7fc4b
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 2 deletions.
6 changes: 4 additions & 2 deletions pymysqlreplication/constants/STATUS_VAR_KEY.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@
Q_TABLE_MAP_FOR_UPDATE_CODE = 0x09
Q_MASTER_DATA_WRITTEN_CODE = 0x0A
Q_INVOKER = 0x0B
Q_UPDATED_DB_NAMES = 0x0C
Q_MICROSECONDS = 0x0D
Q_UPDATED_DB_NAMES = 0x0C # MySQL only
Q_MICROSECONDS = 0x0D # MySQL only
Q_COMMIT_TS = 0x0E
Q_COMMIT_TS2 = 0X0F
Q_EXPLICIT_DEFAULTS_FOR_TIMESTAMP = 0X10
Q_DDL_LOGGED_WITH_XID = 0X11
Q_DEFAULT_COLLATION_FOR_UTF8MB4 = 0X12
Q_SQL_REQUIRE_PRIMARY_KEY = 0X13
Q_DEFAULT_TABLE_ENCRYPTION = 0X14
Q_HRNOW = 0x80 # MariaDB only
Q_XID = 0x81 # MariaDB only
7 changes: 7 additions & 0 deletions pymysqlreplication/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import struct
import datetime
from pymysqlreplication.constants.STATUS_VAR_KEY import *
from pymysqlreplication.exceptions import StatusVariableMismatch


class BinLogEvent(object):
Expand Down Expand Up @@ -291,6 +292,12 @@ def _read_status_vars_value_for_key(self, key):
self.sql_require_primary_key = self.packet.read_uint8()
elif key == Q_DEFAULT_TABLE_ENCRYPTION: # 0x14
self.default_table_encryption = self.packet.read_uint8()
elif key == Q_HRNOW:
self.hrnow = self.packet.read_uint24()
elif key == Q_XID:
self.xid = self.packet.read_uint64()
else:
raise StatusVariableMismatch

class BeginLoadQueryEvent(BinLogEvent):
"""
Expand Down
11 changes: 11 additions & 0 deletions pymysqlreplication/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,14 @@ def __init__(self, table):
class BinLogNotEnabled(Exception):
def __init__(self):
Exception.__init__(self, "MySQL binary logging is not enabled.")


class StatusVariableMismatch(Exception):
def __init__(self):
Exception.__init__(self, " ".join(
"Unknown status variable in query event."
, "Possible parse failure in preceding fields"
, "or outdated constants.STATUS_VAR_KEY"
, "Refer to MySQL documentation/source code"
, "or create an issue on GitHub"
))
6 changes: 6 additions & 0 deletions pymysqlreplication/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def setUp(self):
self.stream = None
self.resetBinLog()
self.isMySQL56AndMore()
self.__is_mariaDB = None

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

def isMariaDB(self):
if self.__is_mariaDB is None:
self.__is_mariaDB = "MariaDB" in self.execute("SELECT VERSION()").fetchone()
return self.__is_mariaDB

@property
def supportsGTID(self):
if not self.isMySQL56AndMore():
Expand Down
26 changes: 26 additions & 0 deletions pymysqlreplication/tests/test_data_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -773,5 +773,31 @@ def test_null_bitmask(self):
self.assertEqual(event.event_type, TABLE_MAP_EVENT)
self.assertEqual(event.null_bitmask, bit_mask)

def test_mariadb_only_status_vars(self):
"""Test parse of mariadb exclusive status variables (a field in query event)
A query event for mariadb must be parsed successfully
since mariadb exclusive status variables are now taken to account
(Q_HRNOW, Q_XID)
Test if was parse successful by asserting the last field of the event,
'SQL statement'.
Raises:
StatusVariableMismatch: This is the case where new status variables are added to
mysql server. Same set of status variables must be added to the library as well.
"""
if not self.isMariaDB():
return

create_query = "CREATE TABLE test (id INTEGER)"
event = self.create_table(create_query)

# skip dummy events with empty schema
while event.schema == b'':
event = self.stream.fetchone()

self.assertEqual(event.query, create_query)


if __name__ == "__main__":
unittest.main()

0 comments on commit ef7fc4b

Please sign in to comment.