Skip to content

Commit e991f4e

Browse files
committed
Support for custom types mapping, support for UUID
1 parent ca057c1 commit e991f4e

File tree

5 files changed

+31
-4
lines changed

5 files changed

+31
-4
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ indexes: # optional
170170
http_host: '0.0.0.0' # optional
171171
http_port: 9128 # optional
172172

173+
types_mapping: # optional
174+
'char(36)': 'UUID'
175+
176+
173177
```
174178

175179
#### Required settings
@@ -188,6 +192,7 @@ http_port: 9128 # optional
188192
- `auto_restart_interval` - interval (seconds) between automatic db_replicator restart. Default 3600 (1 hour). This is done to reduce memory usage.
189193
- `indexes` - you may want to add some indexes to accelerate performance, eg. ngram index for full-test search, etc. To apply indexes you need to start replication from scratch.
190194
- `http_host`, `http_port` - http endpoint to control replication, use `/docs` for abailable commands
195+
- `types_mappings` - custom types mapping, eg. you can map char(36) to UUID instead of String, etc.
191196

192197
Few more tables / dbs examples:
193198

mysql_ch_replicator/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ def __init__(self):
110110
self.auto_restart_interval = 0
111111
self.http_host = ''
112112
self.http_port = 0
113+
self.types_mapping = {}
113114

114115
def load(self, settings_file):
115116
data = open(settings_file, 'r').read()
@@ -130,6 +131,7 @@ def load(self, settings_file):
130131
self.auto_restart_interval = data.pop(
131132
'auto_restart_interval', Settings.DEFAULT_AUTO_RESTART_INTERVAL,
132133
)
134+
self.types_mapping = data.pop('types_mapping', {})
133135
self.http_host = data.pop('http_host', '')
134136
self.http_port = data.pop('http_port', 0)
135137

mysql_ch_replicator/converter.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import struct
22
import json
3+
import uuid
34
import sqlparse
45
import re
56
from pyparsing import Suppress, CaselessKeyword, Word, alphas, alphanums, delimitedList
@@ -180,10 +181,15 @@ def convert_timestamp_to_datetime64(input_str):
180181
class MysqlToClickhouseConverter:
181182
def __init__(self, db_replicator: 'DbReplicator' = None):
182183
self.db_replicator = db_replicator
184+
self.types_mapping = db_replicator.config.types_mapping
183185

184186
def convert_type(self, mysql_type, parameters):
185187
is_unsigned = 'unsigned' in parameters.lower()
186188

189+
result_type = self.types_mapping.get(mysql_type)
190+
if result_type is not None:
191+
return result_type
192+
187193
if mysql_type == 'point':
188194
return 'Tuple(x Float32, y Float32)'
189195

@@ -329,6 +335,12 @@ def convert_record(
329335
clickhouse_field_value = json.dumps(convert_bytes(clickhouse_field_value))
330336

331337
if clickhouse_field_value is not None:
338+
if 'UUID' in clickhouse_field_type:
339+
if len(clickhouse_field_value) == 36:
340+
if isinstance(clickhouse_field_value, bytes):
341+
clickhouse_field_value = clickhouse_field_value.decode('utf-8')
342+
clickhouse_field_value = uuid.UUID(clickhouse_field_value).bytes
343+
332344
if 'UInt16' in clickhouse_field_type and clickhouse_field_value < 0:
333345
clickhouse_field_value = 65536 + clickhouse_field_value
334346
if 'UInt8' in clickhouse_field_type and clickhouse_field_value < 0:

test_mysql_ch_replicator.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import time
55
import subprocess
66
import json
7+
import uuid
8+
79
import pytest
810
import requests
911

@@ -890,13 +892,14 @@ def test_different_types_2():
890892
test3 binary(16),
891893
test4 set('1','2','3','4','5','6','7'),
892894
test5 timestamp(0),
895+
test6 char(36),
893896
PRIMARY KEY (id)
894897
);
895898
''')
896899

897900
mysql.execute(
898-
f"INSERT INTO `{TEST_TABLE_NAME}` (test1, test2, test3, test4, test5) VALUES "
899-
f"(0, POINT(10.0, 20.0), 'azaza', '1,3,5', '2023-08-15 14:30:00');",
901+
f"INSERT INTO `{TEST_TABLE_NAME}` (test1, test2, test3, test4, test5, test6) VALUES "
902+
f"(0, POINT(10.0, 20.0), 'azaza', '1,3,5', '2023-08-15 14:30:00', '550e8400-e29b-41d4-a716-446655440000');",
900903
commit=True,
901904
)
902905

@@ -913,8 +916,8 @@ def test_different_types_2():
913916
assert_wait(lambda: len(ch.select(TEST_TABLE_NAME)) == 1)
914917

915918
mysql.execute(
916-
f"INSERT INTO `{TEST_TABLE_NAME}` (test1, test2, test4, test5) VALUES "
917-
f"(1, POINT(15.0, 14.0), '2,4,5', '2023-08-15 14:40:00');",
919+
f"INSERT INTO `{TEST_TABLE_NAME}` (test1, test2, test4, test5, test6) VALUES "
920+
f"(1, POINT(15.0, 14.0), '2,4,5', '2023-08-15 14:40:00', '110e6103-e39b-51d4-a716-826755413099');",
918921
commit=True,
919922
)
920923

@@ -932,6 +935,8 @@ def test_different_types_2():
932935
assert isinstance(value, datetime.datetime)
933936
assert str(value) == '2023-08-15 14:40:00+00:00'
934937

938+
assert ch.select(TEST_TABLE_NAME, 'test1=True')[0]['test6'] == uuid.UUID('110e6103-e39b-51d4-a716-826755413099')
939+
935940
mysql.execute(
936941
f"INSERT INTO `{TEST_TABLE_NAME}` (test1, test2) VALUES "
937942
f"(0, NULL);",

tests_config.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,6 @@ indexes:
2727

2828
http_host: 'localhost'
2929
http_port: 9128
30+
31+
types_mapping:
32+
'char(36)': 'UUID'

0 commit comments

Comments
 (0)