Skip to content

Commit b7e7a6c

Browse files
committed
Handling UInt8, UInt16
1 parent 6c309d5 commit b7e7a6c

File tree

2 files changed

+75
-4
lines changed

2 files changed

+75
-4
lines changed

mysql_ch_replicator/converter.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,12 @@ class MysqlToClickhouseConverter:
6363
def __init__(self, db_replicator: 'DbReplicator' = None):
6464
self.db_replicator = db_replicator
6565

66-
def convert_type(self, mysql_type):
66+
def convert_type(self, mysql_type, parameters):
67+
68+
is_unsigned = 'unsigned' in parameters.lower()
69+
70+
print(" === check mysql_type", mysql_type, parameters)
71+
6772
if mysql_type == 'int':
6873
return 'Int32'
6974
if mysql_type == 'integer':
@@ -82,10 +87,14 @@ def convert_type(self, mysql_type):
8287
return 'Bool'
8388
if mysql_type == 'bool':
8489
return 'Bool'
85-
if mysql_type == 'smallint':
90+
if 'smallint' in mysql_type:
91+
if is_unsigned:
92+
return 'UInt16'
8693
return 'Int16'
8794
if 'tinyint' in mysql_type:
88-
return 'Int16'
95+
if is_unsigned:
96+
return 'UInt8'
97+
return 'Int8'
8998
if 'datetime' in mysql_type:
9099
return mysql_type.replace('datetime', 'DateTime64')
91100
if 'longtext' in mysql_type:
@@ -120,7 +129,8 @@ def convert_field_type(self, mysql_type, mysql_parameters):
120129
mysql_type = mysql_type.lower()
121130
mysql_parameters = mysql_parameters.lower()
122131
not_null = 'not null' in mysql_parameters
123-
clickhouse_type = self.convert_type(mysql_type)
132+
clickhouse_type = self.convert_type(mysql_type, mysql_parameters)
133+
print(" === result type:", clickhouse_type)
124134
if not not_null:
125135
clickhouse_type = f'Nullable({clickhouse_type})'
126136
return clickhouse_type
@@ -159,6 +169,10 @@ def convert_record(self, mysql_record, mysql_field_types, clickhouse_field_types
159169
if mysql_field_type == 'json' and 'String' in clickhouse_field_type:
160170
if not isinstance(clickhouse_field_value, str):
161171
clickhouse_field_value = json.dumps(convert_bytes(clickhouse_field_value))
172+
if 'UInt16' in clickhouse_field_type and clickhouse_field_value < 0:
173+
clickhouse_field_value = 65536 + clickhouse_field_value
174+
if 'UInt8' in clickhouse_field_type and clickhouse_field_value < 0:
175+
clickhouse_field_value = 256 + clickhouse_field_value
162176
clickhouse_record.append(clickhouse_field_value)
163177
return tuple(clickhouse_record)
164178

test_mysql_ch_replicator.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,3 +581,60 @@ def test_different_types_1():
581581
commit=True,
582582
)
583583
assert_wait(lambda: len(ch.select(TEST_TABLE_NAME)) == 3)
584+
585+
586+
def test_numeric_types_and_limits():
587+
cfg = config.Settings()
588+
cfg.load(CONFIG_FILE)
589+
590+
mysql = mysql_api.MySQLApi(
591+
database=None,
592+
mysql_settings=cfg.mysql,
593+
)
594+
595+
ch = clickhouse_api.ClickhouseApi(
596+
database=TEST_DB_NAME,
597+
clickhouse_settings=cfg.clickhouse,
598+
)
599+
600+
prepare_env(cfg, mysql, ch)
601+
602+
mysql.execute("SET sql_mode = 'ALLOW_INVALID_DATES';")
603+
604+
mysql.execute(f'''
605+
CREATE TABLE {TEST_TABLE_NAME} (
606+
`id` int unsigned NOT NULL AUTO_INCREMENT,
607+
name varchar(255),
608+
test1 smallint,
609+
test2 smallint unsigned,
610+
test3 TINYINT,
611+
test4 TINYINT UNSIGNED,
612+
PRIMARY KEY (id)
613+
);
614+
''')
615+
616+
mysql.execute(
617+
f"INSERT INTO {TEST_TABLE_NAME} (name, test1, test2, test3, test4) VALUES ('Ivan', -20000, 50000, -30, 100);",
618+
commit=True,
619+
)
620+
621+
binlog_replicator_runner = BinlogReplicatorRunner()
622+
binlog_replicator_runner.run()
623+
db_replicator_runner = DbReplicatorRunner(TEST_DB_NAME)
624+
db_replicator_runner.run()
625+
626+
assert_wait(lambda: TEST_DB_NAME in ch.get_databases())
627+
628+
ch.execute_command(f'USE {TEST_DB_NAME}')
629+
630+
assert_wait(lambda: TEST_TABLE_NAME in ch.get_tables())
631+
assert_wait(lambda: len(ch.select(TEST_TABLE_NAME)) == 1)
632+
633+
mysql.execute(
634+
f"INSERT INTO {TEST_TABLE_NAME} (name, test1, test2, test3, test4) VALUES ('Peter', -10000, 60000, -120, 250);",
635+
commit=True,
636+
)
637+
assert_wait(lambda: len(ch.select(TEST_TABLE_NAME)) == 2)
638+
assert_wait(lambda: len(ch.select(TEST_TABLE_NAME, 'test2=60000')) == 1)
639+
640+
assert_wait(lambda: len(ch.select(TEST_TABLE_NAME, 'test4=250')) == 1)

0 commit comments

Comments
 (0)