Skip to content

Commit bc0f9ed

Browse files
committed
Fix an issue in parsing default column charset
When parsing the default charset optional metadata, when handling the column index/collation number pairs, the column index is in the range of the number of columns with charset (not the number of all the columns).
1 parent 6850c0d commit bc0f9ed

File tree

2 files changed

+45
-3
lines changed

2 files changed

+45
-3
lines changed

pymysqlreplication/row_event.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,14 +1005,17 @@ def _parsed_column_charset_by_default_charset(
10051005
column_type_detect_function,
10061006
):
10071007
column_charset = []
1008+
position = 0
10081009
for i in range(self.column_count):
10091010
column_type = self.columns[i].type
10101011
if not column_type_detect_function(column_type, dbms=self.dbms):
10111012
continue
1012-
elif i not in column_charset_collation.keys():
1013-
column_charset.append(default_charset_collation)
10141013
else:
1015-
column_charset.append(column_charset_collation[i])
1014+
if position not in column_charset_collation.keys():
1015+
column_charset.append(default_charset_collation)
1016+
else:
1017+
column_charset.append(column_charset_collation[position])
1018+
position += 1
10161019

10171020
return column_charset
10181021

pymysqlreplication/tests/test_basic.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import io
22
import time
33
import unittest
4+
from random import randbytes, shuffle
45

56
from pymysqlreplication.json_binary import JsonDiff, JsonDiffOperation
67
from pymysqlreplication.tests import base
@@ -420,6 +421,44 @@ def test_minimal_image_update_row_event(self):
420421
self.assertEqual(event.rows[0]["after_values"]["id"], None)
421422
self.assertEqual(event.rows[0]["after_values"]["data"], "World")
422423

424+
def test_charset_parsing(self):
425+
char_columns = {
426+
f"c_utf8_{i}": ("VARCHAR(255) NOT NULL", "Hello")
427+
for i in range(3)
428+
}
429+
char_columns["c_binary"] = ("LONGBLOB NOT NULL", randbytes(1024))
430+
int_columns = {f"i_{i}": ("INTEGER NOT NULL", i) for i in range(3)}
431+
columns = list({**char_columns, **int_columns}.items())
432+
shuffle(columns)
433+
column_types = ", ".join(f"{name} {type}" for name, (type, _) in columns)
434+
column_names = ", ".join(name for name, _ in columns)
435+
column_value_placeholders = ", ".join("%s" for _ in range(len(columns)))
436+
column_values = [value for _, (_, value) in columns]
437+
query = f"CREATE TABLE test (id INT NOT NULL AUTO_INCREMENT, {column_types}, PRIMARY KEY (id)) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;"
438+
self.execute(query)
439+
query = f"INSERT INTO test ({column_names}) VALUES({column_value_placeholders})"
440+
self.execute_with_args(query, column_values)
441+
self.execute("COMMIT")
442+
443+
self.assertIsInstance(self.stream.fetchone(), RotateEvent)
444+
self.assertIsInstance(self.stream.fetchone(), FormatDescriptionEvent)
445+
# QueryEvent for the Create Table
446+
self.assertIsInstance(self.stream.fetchone(), QueryEvent)
447+
# QueryEvent for the BEGIN
448+
self.assertIsInstance(self.stream.fetchone(), QueryEvent)
449+
450+
event = self.stream.fetchone()
451+
self.assertIsInstance(event, TableMapEvent)
452+
if event.table_map[event.table_id].column_name_flag:
453+
columns = {c.name: c for c in event.columns}
454+
for name, column in columns.items():
455+
if name.startswith("c_utf8_"):
456+
assert column.character_set_name == "utf8"
457+
assert column.collation_name == "utf8mb3_unicode_ci"
458+
assert columns["c_binary"].character_set_name == "binary"
459+
assert columns["c_binary"].collation_name == "binary"
460+
461+
423462
def test_log_pos(self):
424463
query = "CREATE TABLE test (id INT NOT NULL AUTO_INCREMENT, data VARCHAR (50) NOT NULL, PRIMARY KEY (id))"
425464
self.execute(query)

0 commit comments

Comments
 (0)