Skip to content

Commit f222cc8

Browse files
Merge branch 'main' of github.com:noplay/python-mysql-replication
2 parents 691f58e + 2b9e734 commit f222cc8

File tree

6 files changed

+73
-9
lines changed

6 files changed

+73
-9
lines changed

.github/workflows/pytest.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: PyTest
2+
on: [push, pull_request]
3+
4+
jobs:
5+
test:
6+
runs-on: ubuntu-latest
7+
timeout-minutes: 2
8+
9+
steps:
10+
- name: Check out code
11+
uses: actions/checkout@v2
12+
13+
- name: Setup Python
14+
uses: actions/setup-python@v2
15+
with:
16+
python-version: "3.7"
17+
18+
- name: Run database server in docker
19+
run: |
20+
docker compose create
21+
docker compose start
22+
# Wait for the services to accept connections,
23+
# TODO: do that smarter, poll connection attempt until it succeeds
24+
sleep 30
25+
26+
- name: Install dependencies
27+
run: |
28+
pip install .
29+
pip install pytest
30+
31+
- name: Run test suite
32+
run: |
33+
pytest -k "not test_no_trailing_rotate_event and not test_end_log_pos"

docker-compose.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
version: '3.2'
2+
services:
3+
percona-5.7:
4+
image: percona:5.7
5+
environment:
6+
MYSQL_ALLOW_EMPTY_PASSWORD: true
7+
ports:
8+
- 3306:3306
9+
command: mysqld --log-bin=mysql-bin.log --server-id 1 --binlog-format=row --gtid_mode=on --enforce-gtid-consistency=on --log_slave_updates
10+
11+
percona-5.7-ctl:
12+
image: percona:5.7
13+
environment:
14+
MYSQL_ALLOW_EMPTY_PASSWORD: true
15+
ports:
16+
- 3307:3307
17+
command: mysqld --log-bin=mysql-bin.log --server-id 1 --binlog-format=row --gtid_mode=on --enforce-gtid-consistency=on --log_slave_updates -P 3307

pymysqlreplication/packet.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,9 @@ def unpack_int32(self, n):
349349

350350
def read_binary_json(self, size):
351351
length = self.read_uint_by_size(size)
352+
if length == 0:
353+
# handle NULL value
354+
return None
352355
payload = self.read(length)
353356
self.unread(payload)
354357
t = self.read_uint8()
@@ -402,9 +405,9 @@ def read_binary_json_type_inlined(self, t, large):
402405
elif t == JSONB_TYPE_UINT16:
403406
return self.read_uint32() if large else self.read_uint16()
404407
elif t == JSONB_TYPE_INT32:
405-
return self.read_int64() if large else self.read_int32()
408+
return self.read_int32()
406409
elif t == JSONB_TYPE_UINT32:
407-
return self.read_uint64() if large else self.read_uint32()
410+
return self.read_uint32()
408411

409412
raise ValueError('Json type %d is not handled' % t)
410413

pymysqlreplication/row_event.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ def __init__(self, from_packet, event_size, table_map, ctl_connection, **kwargs)
8585
if self._fail_on_table_metadata_unavailable:
8686
raise TableMetadataUnavailableError(self.table)
8787

88-
def __is_null(self, null_bitmap, position):
88+
@staticmethod
89+
def _is_null(null_bitmap, position):
8990
bit = null_bitmap[int(position / 8)]
9091
if type(bit) is str:
9192
bit = ord(bit)
@@ -113,7 +114,7 @@ def _read_column_data(self, cols_bitmap):
113114
values[name] = None
114115
continue
115116

116-
if self.__is_null(null_bitmap, nullBitmapIndex):
117+
if self._is_null(null_bitmap, nullBitmapIndex):
117118
values[name] = None
118119
elif column.type == FIELD_TYPE.TINY:
119120
if unsigned:
@@ -649,7 +650,7 @@ def __init__(self, from_packet, event_size, table_map, ctl_connection, **kwargs)
649650
self.table, self.columns)
650651

651652
# ith column is nullable if (i - 1)th bit is set to True, not nullable otherwise
652-
## Refer to definition of and call to row.event.__is_null() to interpret bitmap corresponding to columns
653+
## Refer to definition of and call to row.event._is_null() to interpret bitmap corresponding to columns
653654
self.null_bitmask = self.packet.read((self.column_count + 7) / 8)
654655

655656
def get_table(self):

pymysqlreplication/tests/test_basic.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ def ignoredEvents(self):
2525
return [GtidEvent]
2626

2727
def test_allowed_event_list(self):
28-
self.assertEqual(len(self.stream._allowed_event_list(None, None, False)), 14)
29-
self.assertEqual(len(self.stream._allowed_event_list(None, None, True)), 13)
30-
self.assertEqual(len(self.stream._allowed_event_list(None, [RotateEvent], False)), 13)
28+
self.assertEqual(len(self.stream._allowed_event_list(None, None, False)), 15)
29+
self.assertEqual(len(self.stream._allowed_event_list(None, None, True)), 14)
30+
self.assertEqual(len(self.stream._allowed_event_list(None, [RotateEvent], False)), 14)
3131
self.assertEqual(len(self.stream._allowed_event_list([RotateEvent], None, False)), 1)
3232

3333
def test_read_query_event(self):

pymysqlreplication/tests/test_data_type.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,16 @@ def test_json_large(self):
513513

514514
self.assertEqual(event.rows[0]["values"]["value"], to_binary_dict(data))
515515

516+
def test_json_large_array(self):
517+
"Test json array larger than 64k bytes"
518+
if not self.isMySQL57():
519+
self.skipTest("Json is only supported in mysql 5.7")
520+
create_query = "CREATE TABLE test (id int, value json);"
521+
large_array = dict(my_key=[i for i in range(100000)])
522+
insert_query = "INSERT INTO test (id, value) VALUES (1, '%s');" % (json.dumps(large_array),)
523+
event = self.create_and_insert_value(create_query, insert_query)
524+
self.assertEqual(event.rows[0]["values"]["value"], to_binary_dict(large_array))
525+
516526
def test_json_large_with_literal(self):
517527
if not self.isMySQL57():
518528
self.skipTest("Json is only supported in mysql 5.7")
@@ -730,7 +740,7 @@ def test_null_bitmask(self):
730740
column_type = "INT"
731741
column_definition.append(column_type)
732742

733-
nullability = "NOT NULL" if not RowsEvent.__is_null(bit_mask, i) else ""
743+
nullability = "NOT NULL" if not RowsEvent._is_null(bit_mask, i) else ""
734744
column_definition.append(nullability)
735745

736746
columns.append(" ".join(column_definition))

0 commit comments

Comments
 (0)