Skip to content

Commit a4c8302

Browse files
Merge pull request #111 from noplay/indexerror
Prevent invalid table-map-entries to crash the whole app
2 parents 4333bfa + a4aa08c commit a4c8302

File tree

4 files changed

+46
-8
lines changed

4 files changed

+46
-8
lines changed

pymysqlreplication/binlogstream.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
MYSQL_EXPECTED_ERROR_CODES = [2013, 2006]
2929

3030

31+
3132
class BinLogStreamReader(object):
3233
"""Connect to replication stream and read event
3334
"""

pymysqlreplication/event.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def __init__(self, from_packet, event_size, table_map, ctl_connection,
2020
# The event have been fully processed, if processed is false
2121
# the event will be skipped
2222
self._processed = True
23+
self.complete = True
2324

2425
def _read_table_id(self):
2526
# Table ID is 6 byte

pymysqlreplication/row_event.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ def __init__(self, from_packet, event_size, table_map, ctl_connection, **kwargs)
5454
self.number_of_columns = self.packet.read_length_coded_binary()
5555
self.columns = self.table_map[self.table_id].columns
5656

57+
if len(self.columns) == 0: # could not read the table metadata, probably already dropped
58+
self.complete = False
59+
5760
def __is_null(self, null_bitmap, position):
5861
bit = null_bitmap[int(position / 8)]
5962
if type(bit) is str:
@@ -381,6 +384,10 @@ def _dump(self):
381384

382385
def _fetch_rows(self):
383386
self.__rows = []
387+
388+
if not self.complete:
389+
return
390+
384391
while self.packet.read_bytes + 1 < self.event_size:
385392
self.__rows.append(self._fetch_one_row())
386393

@@ -534,14 +541,15 @@ def __init__(self, from_packet, event_size, table_map, ctl_connection, **kwargs)
534541
else:
535542
self.column_schemas = self._ctl_connection._get_table_information(self.schema, self.table)
536543

537-
# Read columns meta data
538-
column_types = list(self.packet.read(self.column_count))
539-
self.packet.read_length_coded_binary()
540-
for i in range(0, len(column_types)):
541-
column_type = column_types[i]
542-
column_schema = self.column_schemas[i]
543-
col = Column(byte2int(column_type), column_schema, from_packet)
544-
self.columns.append(col)
544+
if len(self.column_schemas) != 0:
545+
# Read columns meta data
546+
column_types = list(self.packet.read(self.column_count))
547+
self.packet.read_length_coded_binary()
548+
for i in range(0, len(column_types)):
549+
column_type = column_types[i]
550+
column_schema = self.column_schemas[i]
551+
col = Column(byte2int(column_type), column_schema, from_packet)
552+
self.columns.append(col)
545553

546554
self.table_obj = Table(self.column_schemas, self.table_id, self.schema,
547555
self.table, self.columns)

pymysqlreplication/tests/test_basic.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,34 @@ def test_delete_multiple_row_event(self):
486486
self.assertEqual(event.rows[1]["values"]["id"], 2)
487487
self.assertEqual(event.rows[1]["values"]["data"], "World")
488488

489+
def test_drop_table(self):
490+
self.execute("CREATE TABLE test (id INTEGER(11))")
491+
self.execute("INSERT INTO test VALUES (1)")
492+
self.execute("DROP TABLE test")
493+
self.execute("COMMIT")
494+
495+
#RotateEvent
496+
self.stream.fetchone()
497+
#FormatDescription
498+
self.stream.fetchone()
499+
#QueryEvent for the Create Table
500+
self.stream.fetchone()
501+
502+
#QueryEvent for the BEGIN
503+
self.stream.fetchone()
504+
505+
event = self.stream.fetchone()
506+
self.assertIsInstance(event, TableMapEvent)
507+
508+
event = self.stream.fetchone()
509+
if self.isMySQL56AndMore():
510+
self.assertEqual(event.event_type, WRITE_ROWS_EVENT_V2)
511+
else:
512+
self.assertEqual(event.event_type, WRITE_ROWS_EVENT_V1)
513+
self.assertIsInstance(event, WriteRowsEvent)
514+
515+
self.assertEqual([], event.rows)
516+
489517

490518
class TestGtidBinLogStreamReader(base.PyMySQLReplicationTestCase):
491519
def test_read_query_event(self):

0 commit comments

Comments
 (0)