Skip to content

Commit a6dee95

Browse files
authored
MySQL: Reworked Varchar/Varbinary column identification (#234)
* MySQL: Reworked Varchar/Varbinary column identification * Added comments explaining some of the mysql type mappings
1 parent a11a1bf commit a6dee95

File tree

5 files changed

+57
-6
lines changed

5 files changed

+57
-6
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@powersync/service-module-mysql': patch
3+
---
4+
5+
Fixed mysql varchar column identification for binary encoded varchar columns
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
services:
2+
mysql:
3+
image: mysql:5.7
4+
environment:
5+
MYSQL_ROOT_PASSWORD: root_password
6+
MYSQL_DATABASE: mydatabase
7+
MYSQL_USER: myuser
8+
MYSQL_PASSWORD: mypassword
9+
ports:
10+
- '3306:3306'
11+
volumes:
12+
- ./init-scripts/my.cnf:/etc/mysql/my.cnf
13+
- ./init-scripts/mysql_57.sql:/docker-entrypoint-initdb.d/init_user.sql
14+
- mysql_data_57:/var/lib/mysql
15+
16+
volumes:
17+
mysql_data_57:
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- Create a user with necessary privileges
2+
CREATE USER 'repl_user'@'%' IDENTIFIED BY 'good_password';
3+
4+
-- Grant replication client privilege
5+
GRANT REPLICATION SLAVE, REPLICATION CLIENT, RELOAD ON *.* TO 'repl_user'@'%';
6+
GRANT REPLICATION SLAVE, REPLICATION CLIENT, RELOAD ON *.* TO 'myuser'@'%';
7+
8+
-- Grant access to the specific database
9+
GRANT ALL PRIVILEGES ON mydatabase.* TO 'repl_user'@'%';
10+
11+
-- Apply changes
12+
FLUSH PRIVILEGES;

modules/module-mysql/src/common/mysql-to-sqlite.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,26 +41,28 @@ export function toColumnDescriptors(columns: mysql.FieldPacket[] | TableMapEntry
4141

4242
export function toColumnDescriptorFromFieldPacket(column: mysql.FieldPacket): ColumnDescriptor {
4343
let typeId = column.type!;
44-
const BINARY_FLAG = 128;
4544
const MYSQL_ENUM_FLAG = 256;
4645
const MYSQL_SET_FLAG = 2048;
46+
const MYSQL_BINARY_ENCODING = 'binary';
4747

4848
switch (column.type) {
49+
// STRING is overloaded to also include Binary, Enum and Set types
4950
case mysql.Types.STRING:
50-
if (((column.flags as number) & BINARY_FLAG) !== 0) {
51+
if (column.encoding === MYSQL_BINARY_ENCODING) {
5152
typeId = ADDITIONAL_MYSQL_TYPES.BINARY;
5253
} else if (((column.flags as number) & MYSQL_ENUM_FLAG) !== 0) {
5354
typeId = mysql.Types.ENUM;
5455
} else if (((column.flags as number) & MYSQL_SET_FLAG) !== 0) {
5556
typeId = mysql.Types.SET;
5657
}
5758
break;
58-
59+
// VAR_STRING represents both VARCHAR and VARBINARY types
5960
case mysql.Types.VAR_STRING:
60-
typeId = ((column.flags as number) & BINARY_FLAG) !== 0 ? ADDITIONAL_MYSQL_TYPES.VARBINARY : column.type;
61+
typeId = column.encoding === MYSQL_BINARY_ENCODING ? ADDITIONAL_MYSQL_TYPES.VARBINARY : column.type;
6162
break;
63+
// BLOB is also used to represent the TEXT type when the encoding is not binary
6264
case mysql.Types.BLOB:
63-
typeId = ((column.flags as number) & BINARY_FLAG) === 0 ? ADDITIONAL_MYSQL_TYPES.TEXT : column.type;
65+
typeId = column.encoding !== MYSQL_BINARY_ENCODING ? ADDITIONAL_MYSQL_TYPES.TEXT : column.type;
6466
break;
6567
}
6668

@@ -77,13 +79,16 @@ export function toColumnDescriptorFromDefinition(column: ColumnDefinition): Colu
7779
let typeId = column.type;
7880

7981
switch (column.type) {
82+
// STRING is overloaded to also include Binary types, ENUM and SET is already identified upstream in Zongji
8083
case mysql.Types.STRING:
8184
typeId = !column.charset ? ADDITIONAL_MYSQL_TYPES.BINARY : column.type;
8285
break;
86+
// VAR_STRING represents both VARCHAR and VARBINARY types
8387
case mysql.Types.VAR_STRING:
8488
case mysql.Types.VARCHAR:
8589
typeId = !column.charset ? ADDITIONAL_MYSQL_TYPES.VARBINARY : column.type;
8690
break;
91+
// BLOB is also used to represent the TEXT type when a charset is specified
8792
case mysql.Types.BLOB:
8893
typeId = column.charset ? ADDITIONAL_MYSQL_TYPES.TEXT : column.type;
8994
break;

modules/module-mysql/test/src/mysql-to-sqlite.test.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ describe('MySQL Data Types', () => {
4040
4141
char_col CHAR(10),
4242
varchar_col VARCHAR(255),
43+
varchar_binary_encoding_col VARCHAR(255) CHARACTER SET binary,
44+
varchar_with_bin_collation_col VARCHAR(255) COLLATE utf8mb4_bin,
45+
4346
binary_col BINARY(16),
4447
varbinary_col VARBINARY(256),
4548
tinyblob_col TINYBLOB,
@@ -145,6 +148,8 @@ INSERT INTO test_data (
145148
INSERT INTO test_data (
146149
char_col,
147150
varchar_col,
151+
varchar_binary_encoding_col,
152+
varchar_with_bin_collation_col,
148153
binary_col,
149154
varbinary_col,
150155
tinyblob_col,
@@ -159,7 +164,9 @@ INSERT INTO test_data (
159164
) VALUES (
160165
'CharData', -- CHAR(10) with padding spaces
161166
'Variable character data',-- VARCHAR(255)
162-
'ShortBin', -- BINARY(16)
167+
'Varchar with binary encoding', -- VARCHAR(255) with binary encoding
168+
'Variable character data with bin collation', -- VARCHAR(255) with bin collation
169+
'ShortBin', -- BINARY(16)
163170
'VariableBinaryData', -- VARBINARY(256)
164171
'TinyBlobData', -- TINYBLOB
165172
'BlobData', -- BLOB
@@ -177,6 +184,11 @@ INSERT INTO test_data (
177184
const expectedResult = {
178185
char_col: 'CharData',
179186
varchar_col: 'Variable character data',
187+
varchar_binary_encoding_col: new Uint8Array([
188+
86, 97, 114, 99, 104, 97, 114, 32, 119, 105, 116, 104, 32, 98, 105, 110, 97, 114, 121, 32, 101, 110, 99, 111,
189+
100, 105, 110, 103
190+
]),
191+
varchar_with_bin_collation_col: 'Variable character data with bin collation',
180192
binary_col: new Uint8Array([83, 104, 111, 114, 116, 66, 105, 110, 0, 0, 0, 0, 0, 0, 0, 0]), // Pad with 0
181193
varbinary_col: new Uint8Array([
182194
0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61

0 commit comments

Comments
 (0)