Skip to content

Commit 1c79564

Browse files
mp-ebaloo
authored andcommitted
Add variable length JSON string support (#246)
1 parent 10eaaa2 commit 1c79564

File tree

2 files changed

+27
-1
lines changed

2 files changed

+27
-1
lines changed

pymysqlreplication/packet.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,22 @@ def read_length_coded_pascal_string(self, size):
252252
length = self.read_uint_by_size(size)
253253
return self.read(length)
254254

255+
def read_variable_length_string(self):
256+
"""Read a variable length string where the first 1-5 bytes stores the
257+
length of the string.
258+
259+
For each byte, the first bit being high indicates another byte must be
260+
read.
261+
"""
262+
byte = 0x80
263+
length = 0
264+
bits_read = 0
265+
while byte & 0x80 != 0:
266+
byte = byte2int(self.read(1))
267+
length = length | ((byte & 0x7f) << bits_read)
268+
bits_read = bits_read + 7
269+
return self.read(length)
270+
255271
def read_int24(self):
256272
a, b, c = struct.unpack("BBB", self.read(3))
257273
res = a | (b << 8) | (c << 16)
@@ -342,7 +358,7 @@ def read_binary_json_type(self, t, length):
342358
elif t in (JSONB_TYPE_SMALL_ARRAY, JSONB_TYPE_LARGE_ARRAY):
343359
return self.read_binary_json_array(length - 1, large)
344360
elif t in (JSONB_TYPE_STRING,):
345-
return self.read_length_coded_pascal_string(1)
361+
return self.read_variable_length_string()
346362
elif t in (JSONB_TYPE_LITERAL,):
347363
value = self.read_uint8()
348364
if value == JSONB_LITERAL_NULL:

pymysqlreplication/tests/test_data_type.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,16 @@ def test_json_unicode(self):
513513
event = self.create_and_insert_value(create_query, insert_query)
514514
self.assertEqual(event.rows[0]["values"]["value"][b"miam"], u'🍔'.encode('utf8'))
515515

516+
def test_json_long_string(self):
517+
if not self.isMySQL57():
518+
self.skipTest("Json is only supported in mysql 5.7")
519+
create_query = "CREATE TABLE test (id int, value json);"
520+
# The string length needs to be larger than what can fit in a single byte.
521+
string_value = "super_long_string" * 100
522+
insert_query = "INSERT INTO test (id, value) VALUES (1, '{\"my_key\": \"%s\"}');" % (string_value,)
523+
event = self.create_and_insert_value(create_query, insert_query)
524+
self.assertEqual(event.rows[0]["values"]["value"], to_binary_dict({"my_key": string_value}))
525+
516526
def test_null(self):
517527
create_query = "CREATE TABLE test ( \
518528
test TINYINT NULL DEFAULT NULL, \

0 commit comments

Comments
 (0)